aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfs/inode.c3
-rw-r--r--fs/nfs/nfs4proc.c82
-rw-r--r--fs/nfs/nfs4xdr.c111
-rw-r--r--fs/nfs/pnfs.c45
-rw-r--r--fs/nfs/pnfs.h18
-rw-r--r--include/linux/nfs4.h1
-rw-r--r--include/linux/nfs_xdr.h21
7 files changed, 274 insertions, 7 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 57bb31ad7a5e..e9c6d9f8f7e8 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -1424,9 +1424,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
1424 */ 1424 */
1425void nfs4_evict_inode(struct inode *inode) 1425void nfs4_evict_inode(struct inode *inode)
1426{ 1426{
1427 pnfs_destroy_layout(NFS_I(inode));
1428 truncate_inode_pages(&inode->i_data, 0); 1427 truncate_inode_pages(&inode->i_data, 0);
1429 end_writeback(inode); 1428 end_writeback(inode);
1429 pnfs_return_layout(inode);
1430 pnfs_destroy_layout(NFS_I(inode));
1430 /* If we are holding a delegation, return it! */ 1431 /* If we are holding a delegation, return it! */
1431 nfs_inode_return_delegation_noreclaim(inode); 1432 nfs_inode_return_delegation_noreclaim(inode);
1432 /* First call standard NFS clear_inode() code */ 1433 /* First call standard NFS clear_inode() code */
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 92c8bc4b5f97..5b4124e4c22f 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -5673,6 +5673,88 @@ int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
5673 return status; 5673 return status;
5674} 5674}
5675 5675
5676static void
5677nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
5678{
5679 struct nfs4_layoutreturn *lrp = calldata;
5680
5681 dprintk("--> %s\n", __func__);
5682 if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args,
5683 &lrp->res.seq_res, 0, task))
5684 return;
5685 rpc_call_start(task);
5686}
5687
5688static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
5689{
5690 struct nfs4_layoutreturn *lrp = calldata;
5691 struct nfs_server *server;
5692
5693 dprintk("--> %s\n", __func__);
5694
5695 if (!nfs4_sequence_done(task, &lrp->res.seq_res))
5696 return;
5697
5698 server = NFS_SERVER(lrp->args.inode);
5699 if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
5700 nfs_restart_rpc(task, lrp->clp);
5701 return;
5702 }
5703 if (task->tk_status == 0) {
5704 struct pnfs_layout_hdr *lo = NFS_I(lrp->args.inode)->layout;
5705
5706 if (lrp->res.lrs_present) {
5707 spin_lock(&lo->plh_inode->i_lock);
5708 pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
5709 spin_unlock(&lo->plh_inode->i_lock);
5710 } else
5711 BUG_ON(!list_empty(&lo->plh_segs));
5712 }
5713 dprintk("<-- %s\n", __func__);
5714}
5715
5716static void nfs4_layoutreturn_release(void *calldata)
5717{
5718 struct nfs4_layoutreturn *lrp = calldata;
5719
5720 dprintk("--> %s\n", __func__);
5721 put_layout_hdr(NFS_I(lrp->args.inode)->layout);
5722 kfree(calldata);
5723 dprintk("<-- %s\n", __func__);
5724}
5725
5726static const struct rpc_call_ops nfs4_layoutreturn_call_ops = {
5727 .rpc_call_prepare = nfs4_layoutreturn_prepare,
5728 .rpc_call_done = nfs4_layoutreturn_done,
5729 .rpc_release = nfs4_layoutreturn_release,
5730};
5731
5732int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
5733{
5734 struct rpc_task *task;
5735 struct rpc_message msg = {
5736 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN],
5737 .rpc_argp = &lrp->args,
5738 .rpc_resp = &lrp->res,
5739 };
5740 struct rpc_task_setup task_setup_data = {
5741 .rpc_client = lrp->clp->cl_rpcclient,
5742 .rpc_message = &msg,
5743 .callback_ops = &nfs4_layoutreturn_call_ops,
5744 .callback_data = lrp,
5745 };
5746 int status;
5747
5748 dprintk("--> %s\n", __func__);
5749 task = rpc_run_task(&task_setup_data);
5750 if (IS_ERR(task))
5751 return PTR_ERR(task);
5752 status = task->tk_status;
5753 dprintk("<-- %s status=%d\n", __func__, status);
5754 rpc_put_task(task);
5755 return status;
5756}
5757
5676static int 5758static int
5677_nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) 5759_nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
5678{ 5760{
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index c3ccd2c46834..f24212064356 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -338,7 +338,11 @@ static int nfs4_stat_to_errno(int);
338 1 /* layoutupdate4 layout type */ + \ 338 1 /* layoutupdate4 layout type */ + \
339 1 /* NULL filelayout layoutupdate4 payload */) 339 1 /* NULL filelayout layoutupdate4 payload */)
340#define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3) 340#define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3)
341 341#define encode_layoutreturn_maxsz (8 + op_encode_hdr_maxsz + \
342 encode_stateid_maxsz + \
343 1 /* FIXME: opaque lrf_body always empty at the moment */)
344#define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \
345 1 + decode_stateid_maxsz)
342#else /* CONFIG_NFS_V4_1 */ 346#else /* CONFIG_NFS_V4_1 */
343#define encode_sequence_maxsz 0 347#define encode_sequence_maxsz 0
344#define decode_sequence_maxsz 0 348#define decode_sequence_maxsz 0
@@ -760,7 +764,14 @@ static int nfs4_stat_to_errno(int);
760 decode_putfh_maxsz + \ 764 decode_putfh_maxsz + \
761 decode_layoutcommit_maxsz + \ 765 decode_layoutcommit_maxsz + \
762 decode_getattr_maxsz) 766 decode_getattr_maxsz)
763 767#define NFS4_enc_layoutreturn_sz (compound_encode_hdr_maxsz + \
768 encode_sequence_maxsz + \
769 encode_putfh_maxsz + \
770 encode_layoutreturn_maxsz)
771#define NFS4_dec_layoutreturn_sz (compound_decode_hdr_maxsz + \
772 decode_sequence_maxsz + \
773 decode_putfh_maxsz + \
774 decode_layoutreturn_maxsz)
764 775
765const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + 776const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH +
766 compound_encode_hdr_maxsz + 777 compound_encode_hdr_maxsz +
@@ -1889,6 +1900,31 @@ encode_layoutcommit(struct xdr_stream *xdr,
1889 hdr->replen += decode_layoutcommit_maxsz; 1900 hdr->replen += decode_layoutcommit_maxsz;
1890 return 0; 1901 return 0;
1891} 1902}
1903
1904static void
1905encode_layoutreturn(struct xdr_stream *xdr,
1906 const struct nfs4_layoutreturn_args *args,
1907 struct compound_hdr *hdr)
1908{
1909 __be32 *p;
1910
1911 p = reserve_space(xdr, 20);
1912 *p++ = cpu_to_be32(OP_LAYOUTRETURN);
1913 *p++ = cpu_to_be32(0); /* reclaim. always 0 for now */
1914 *p++ = cpu_to_be32(args->layout_type);
1915 *p++ = cpu_to_be32(IOMODE_ANY);
1916 *p = cpu_to_be32(RETURN_FILE);
1917 p = reserve_space(xdr, 16 + NFS4_STATEID_SIZE);
1918 p = xdr_encode_hyper(p, 0);
1919 p = xdr_encode_hyper(p, NFS4_MAX_UINT64);
1920 spin_lock(&args->inode->i_lock);
1921 xdr_encode_opaque_fixed(p, &args->stateid.data, NFS4_STATEID_SIZE);
1922 spin_unlock(&args->inode->i_lock);
1923 p = reserve_space(xdr, 4);
1924 *p = cpu_to_be32(0);
1925 hdr->nops++;
1926 hdr->replen += decode_layoutreturn_maxsz;
1927}
1892#endif /* CONFIG_NFS_V4_1 */ 1928#endif /* CONFIG_NFS_V4_1 */
1893 1929
1894/* 1930/*
@@ -2706,9 +2742,9 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req,
2706/* 2742/*
2707 * Encode LAYOUTCOMMIT request 2743 * Encode LAYOUTCOMMIT request
2708 */ 2744 */
2709static int nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req, 2745static void nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
2710 struct xdr_stream *xdr, 2746 struct xdr_stream *xdr,
2711 struct nfs4_layoutcommit_args *args) 2747 struct nfs4_layoutcommit_args *args)
2712{ 2748{
2713 struct compound_hdr hdr = { 2749 struct compound_hdr hdr = {
2714 .minorversion = nfs4_xdr_minorversion(&args->seq_args), 2750 .minorversion = nfs4_xdr_minorversion(&args->seq_args),
@@ -2720,7 +2756,24 @@ static int nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req,
2720 encode_layoutcommit(xdr, args, &hdr); 2756 encode_layoutcommit(xdr, args, &hdr);
2721 encode_getfattr(xdr, args->bitmask, &hdr); 2757 encode_getfattr(xdr, args->bitmask, &hdr);
2722 encode_nops(&hdr); 2758 encode_nops(&hdr);
2723 return 0; 2759}
2760
2761/*
2762 * Encode LAYOUTRETURN request
2763 */
2764static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req,
2765 struct xdr_stream *xdr,
2766 struct nfs4_layoutreturn_args *args)
2767{
2768 struct compound_hdr hdr = {
2769 .minorversion = nfs4_xdr_minorversion(&args->seq_args),
2770 };
2771
2772 encode_compound_hdr(xdr, req, &hdr);
2773 encode_sequence(xdr, &args->seq_args, &hdr);
2774 encode_putfh(xdr, NFS_FH(args->inode), &hdr);
2775 encode_layoutreturn(xdr, args, &hdr);
2776 encode_nops(&hdr);
2724} 2777}
2725#endif /* CONFIG_NFS_V4_1 */ 2778#endif /* CONFIG_NFS_V4_1 */
2726 2779
@@ -5203,6 +5256,27 @@ out_overflow:
5203 return -EIO; 5256 return -EIO;
5204} 5257}
5205 5258
5259static int decode_layoutreturn(struct xdr_stream *xdr,
5260 struct nfs4_layoutreturn_res *res)
5261{
5262 __be32 *p;
5263 int status;
5264
5265 status = decode_op_hdr(xdr, OP_LAYOUTRETURN);
5266 if (status)
5267 return status;
5268 p = xdr_inline_decode(xdr, 4);
5269 if (unlikely(!p))
5270 goto out_overflow;
5271 res->lrs_present = be32_to_cpup(p);
5272 if (res->lrs_present)
5273 status = decode_stateid(xdr, &res->stateid);
5274 return status;
5275out_overflow:
5276 print_overflow_msg(__func__, xdr);
5277 return -EIO;
5278}
5279
5206static int decode_layoutcommit(struct xdr_stream *xdr, 5280static int decode_layoutcommit(struct xdr_stream *xdr,
5207 struct rpc_rqst *req, 5281 struct rpc_rqst *req,
5208 struct nfs4_layoutcommit_res *res) 5282 struct nfs4_layoutcommit_res *res)
@@ -6320,6 +6394,30 @@ out:
6320} 6394}
6321 6395
6322/* 6396/*
6397 * Decode LAYOUTRETURN response
6398 */
6399static int nfs4_xdr_dec_layoutreturn(struct rpc_rqst *rqstp,
6400 struct xdr_stream *xdr,
6401 struct nfs4_layoutreturn_res *res)
6402{
6403 struct compound_hdr hdr;
6404 int status;
6405
6406 status = decode_compound_hdr(xdr, &hdr);
6407 if (status)
6408 goto out;
6409 status = decode_sequence(xdr, &res->seq_res, rqstp);
6410 if (status)
6411 goto out;
6412 status = decode_putfh(xdr);
6413 if (status)
6414 goto out;
6415 status = decode_layoutreturn(xdr, res);
6416out:
6417 return status;
6418}
6419
6420/*
6323 * Decode LAYOUTCOMMIT response 6421 * Decode LAYOUTCOMMIT response
6324 */ 6422 */
6325static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp, 6423static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp,
@@ -6547,6 +6645,7 @@ struct rpc_procinfo nfs4_procedures[] = {
6547 PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo), 6645 PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo),
6548 PROC(LAYOUTGET, enc_layoutget, dec_layoutget), 6646 PROC(LAYOUTGET, enc_layoutget, dec_layoutget),
6549 PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit), 6647 PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit),
6648 PROC(LAYOUTRETURN, enc_layoutreturn, dec_layoutreturn),
6550#endif /* CONFIG_NFS_V4_1 */ 6649#endif /* CONFIG_NFS_V4_1 */
6551}; 6650};
6552 6651
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 171662114fdd..00b128241746 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -619,6 +619,51 @@ out_err_free:
619 return NULL; 619 return NULL;
620} 620}
621 621
622/* Initiates a LAYOUTRETURN(FILE) */
623int
624_pnfs_return_layout(struct inode *ino)
625{
626 struct pnfs_layout_hdr *lo = NULL;
627 struct nfs_inode *nfsi = NFS_I(ino);
628 LIST_HEAD(tmp_list);
629 struct nfs4_layoutreturn *lrp;
630 nfs4_stateid stateid;
631 int status = 0;
632
633 dprintk("--> %s\n", __func__);
634
635 spin_lock(&ino->i_lock);
636 lo = nfsi->layout;
637 if (!lo || !mark_matching_lsegs_invalid(lo, &tmp_list, NULL)) {
638 spin_unlock(&ino->i_lock);
639 dprintk("%s: no layout segments to return\n", __func__);
640 goto out;
641 }
642 stateid = nfsi->layout->plh_stateid;
643 /* Reference matched in nfs4_layoutreturn_release */
644 get_layout_hdr(lo);
645 spin_unlock(&ino->i_lock);
646 pnfs_free_lseg_list(&tmp_list);
647
648 WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags));
649
650 lrp = kzalloc(sizeof(*lrp), GFP_KERNEL);
651 if (unlikely(lrp == NULL)) {
652 status = -ENOMEM;
653 goto out;
654 }
655
656 lrp->args.stateid = stateid;
657 lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id;
658 lrp->args.inode = ino;
659 lrp->clp = NFS_SERVER(ino)->nfs_client;
660
661 status = nfs4_proc_layoutreturn(lrp);
662out:
663 dprintk("<-- %s status: %d\n", __func__, status);
664 return status;
665}
666
622bool pnfs_roc(struct inode *ino) 667bool pnfs_roc(struct inode *ino)
623{ 668{
624 struct pnfs_layout_hdr *lo; 669 struct pnfs_layout_hdr *lo;
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 0383e66e71f0..c34f7a0e3bc2 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -129,6 +129,7 @@ extern void pnfs_unregister_layoutdriver(struct pnfs_layoutdriver_type *);
129extern int nfs4_proc_getdeviceinfo(struct nfs_server *server, 129extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
130 struct pnfs_device *dev); 130 struct pnfs_device *dev);
131extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp); 131extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
132extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
132 133
133/* pnfs.c */ 134/* pnfs.c */
134void get_layout_hdr(struct pnfs_layout_hdr *lo); 135void get_layout_hdr(struct pnfs_layout_hdr *lo);
@@ -165,6 +166,7 @@ void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
165bool pnfs_roc_drain(struct inode *ino, u32 *barrier); 166bool pnfs_roc_drain(struct inode *ino, u32 *barrier);
166void pnfs_set_layoutcommit(struct nfs_write_data *wdata); 167void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
167int pnfs_layoutcommit_inode(struct inode *inode, bool sync); 168int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
169int _pnfs_return_layout(struct inode *);
168int pnfs_ld_write_done(struct nfs_write_data *); 170int pnfs_ld_write_done(struct nfs_write_data *);
169int pnfs_ld_read_done(struct nfs_read_data *); 171int pnfs_ld_read_done(struct nfs_read_data *);
170 172
@@ -256,6 +258,17 @@ static inline void pnfs_clear_request_commit(struct nfs_page *req)
256 put_lseg(req->wb_commit_lseg); 258 put_lseg(req->wb_commit_lseg);
257} 259}
258 260
261static inline int pnfs_return_layout(struct inode *ino)
262{
263 struct nfs_inode *nfsi = NFS_I(ino);
264 struct nfs_server *nfss = NFS_SERVER(ino);
265
266 if (pnfs_enabled_sb(nfss) && nfsi->layout)
267 return _pnfs_return_layout(ino);
268
269 return 0;
270}
271
259#else /* CONFIG_NFS_V4_1 */ 272#else /* CONFIG_NFS_V4_1 */
260 273
261static inline void pnfs_destroy_all_layouts(struct nfs_client *clp) 274static inline void pnfs_destroy_all_layouts(struct nfs_client *clp)
@@ -298,6 +311,11 @@ pnfs_try_to_write_data(struct nfs_write_data *data,
298 return PNFS_NOT_ATTEMPTED; 311 return PNFS_NOT_ATTEMPTED;
299} 312}
300 313
314static inline int pnfs_return_layout(struct inode *ino)
315{
316 return 0;
317}
318
301static inline bool 319static inline bool
302pnfs_roc(struct inode *ino) 320pnfs_roc(struct inode *ino)
303{ 321{
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 178fafe0ff93..9376eaf26e15 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -562,6 +562,7 @@ enum {
562 NFSPROC4_CLNT_LAYOUTGET, 562 NFSPROC4_CLNT_LAYOUTGET,
563 NFSPROC4_CLNT_GETDEVICEINFO, 563 NFSPROC4_CLNT_GETDEVICEINFO,
564 NFSPROC4_CLNT_LAYOUTCOMMIT, 564 NFSPROC4_CLNT_LAYOUTCOMMIT,
565 NFSPROC4_CLNT_LAYOUTRETURN,
565}; 566};
566 567
567/* nfs41 types */ 568/* nfs41 types */
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 7c8ff0984a84..5e8444a11adf 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -269,6 +269,27 @@ struct nfs4_layoutcommit_data {
269 struct nfs4_layoutcommit_res res; 269 struct nfs4_layoutcommit_res res;
270}; 270};
271 271
272struct nfs4_layoutreturn_args {
273 __u32 layout_type;
274 struct inode *inode;
275 nfs4_stateid stateid;
276 struct nfs4_sequence_args seq_args;
277};
278
279struct nfs4_layoutreturn_res {
280 struct nfs4_sequence_res seq_res;
281 u32 lrs_present;
282 nfs4_stateid stateid;
283};
284
285struct nfs4_layoutreturn {
286 struct nfs4_layoutreturn_args args;
287 struct nfs4_layoutreturn_res res;
288 struct rpc_cred *cred;
289 struct nfs_client *clp;
290 int rpc_status;
291};
292
272/* 293/*
273 * Arguments to the open call. 294 * Arguments to the open call.
274 */ 295 */