diff options
author | Andy Adamson <andros@netapp.com> | 2011-03-23 09:27:54 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2011-03-23 15:29:04 -0400 |
commit | 863a3c6c686d5773f7192a4818769e15db12ce08 (patch) | |
tree | 3ff8bf04c583aa0c16ae30b0821bc9148d49a47a /fs | |
parent | e0c2b3801828aadb65dec9f67f7c6b7a675ad007 (diff) |
NFSv4.1: layoutcommit
The filelayout driver sends LAYOUTCOMMIT only when COMMIT goes to
the data server (as opposed to the MDS) and the data server WRITE
is not NFS_FILE_SYNC.
Only whole file layout support means that there is only one IOMODE_RW layout
segment.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Alexandros Batsakis <batsakis@netapp.com>
Signed-off-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: Dean Hildebrand <dhildeb@us.ibm.com>
Signed-off-by: Fred Isaman <iisaman@citi.umich.edu>
Signed-off-by: Mingyang Guo <guomingyang@nrchpc.ac.cn>
Signed-off-by: Tao Guo <guotao@nrchpc.ac.cn>
Signed-off-by: Zhang Jingwang <zhangjingwang@nrchpc.ac.cn>
Tested-by: Boaz Harrosh <bharrosh@panasas.com>
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
Signed-off-by: Fred Isaman <iisaman@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/file.c | 3 | ||||
-rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 18 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 94 | ||||
-rw-r--r-- | fs/nfs/nfs4xdr.c | 129 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 94 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 9 | ||||
-rw-r--r-- | fs/nfs/write.c | 15 |
8 files changed, 362 insertions, 2 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index d85a534b15cd..85cb95de5df5 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -326,6 +326,9 @@ nfs_file_fsync(struct file *file, int datasync) | |||
326 | ret = xchg(&ctx->error, 0); | 326 | ret = xchg(&ctx->error, 0); |
327 | if (!ret && status < 0) | 327 | if (!ret && status < 0) |
328 | ret = status; | 328 | ret = status; |
329 | if (!ret && !datasync) | ||
330 | /* application has asked for meta-data sync */ | ||
331 | ret = pnfs_layoutcommit_inode(inode, 1); | ||
329 | return ret; | 332 | return ret; |
330 | } | 333 | } |
331 | 334 | ||
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c64be1cff080..1e612d159b71 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
@@ -262,6 +262,8 @@ extern int nfs4_proc_destroy_session(struct nfs4_session *); | |||
262 | extern int nfs4_init_session(struct nfs_server *server); | 262 | extern int nfs4_init_session(struct nfs_server *server); |
263 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, | 263 | extern int nfs4_proc_get_lease_time(struct nfs_client *clp, |
264 | struct nfs_fsinfo *fsinfo); | 264 | struct nfs_fsinfo *fsinfo); |
265 | extern int nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, | ||
266 | int sync); | ||
265 | 267 | ||
266 | static inline bool | 268 | static inline bool |
267 | is_ds_only_client(struct nfs_client *clp) | 269 | is_ds_only_client(struct nfs_client *clp) |
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 97e75a22af72..fc1a0e9c1270 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -154,6 +154,23 @@ static int filelayout_read_done_cb(struct rpc_task *task, | |||
154 | } | 154 | } |
155 | 155 | ||
156 | /* | 156 | /* |
157 | * We reference the rpc_cred of the first WRITE that triggers the need for | ||
158 | * a LAYOUTCOMMIT, and use it to send the layoutcommit compound. | ||
159 | * rfc5661 is not clear about which credential should be used. | ||
160 | */ | ||
161 | static void | ||
162 | filelayout_set_layoutcommit(struct nfs_write_data *wdata) | ||
163 | { | ||
164 | if (FILELAYOUT_LSEG(wdata->lseg)->commit_through_mds || | ||
165 | wdata->res.verf->committed == NFS_FILE_SYNC) | ||
166 | return; | ||
167 | |||
168 | pnfs_set_layoutcommit(wdata); | ||
169 | dprintk("%s ionde %lu pls_end_pos %lu\n", __func__, wdata->inode->i_ino, | ||
170 | (unsigned long) wdata->lseg->pls_end_pos); | ||
171 | } | ||
172 | |||
173 | /* | ||
157 | * Call ops for the async read/write cases | 174 | * Call ops for the async read/write cases |
158 | * In the case of dense layouts, the offset needs to be reset to its | 175 | * In the case of dense layouts, the offset needs to be reset to its |
159 | * original value. | 176 | * original value. |
@@ -210,6 +227,7 @@ static int filelayout_write_done_cb(struct rpc_task *task, | |||
210 | return -EAGAIN; | 227 | return -EAGAIN; |
211 | } | 228 | } |
212 | 229 | ||
230 | filelayout_set_layoutcommit(data); | ||
213 | return 0; | 231 | return 0; |
214 | } | 232 | } |
215 | 233 | ||
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 5d61cccc8d4d..6f2f40239d10 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -5616,6 +5616,100 @@ int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev) | |||
5616 | } | 5616 | } |
5617 | EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo); | 5617 | EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo); |
5618 | 5618 | ||
5619 | static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata) | ||
5620 | { | ||
5621 | struct nfs4_layoutcommit_data *data = calldata; | ||
5622 | struct nfs_server *server = NFS_SERVER(data->args.inode); | ||
5623 | |||
5624 | if (nfs4_setup_sequence(server, &data->args.seq_args, | ||
5625 | &data->res.seq_res, 1, task)) | ||
5626 | return; | ||
5627 | rpc_call_start(task); | ||
5628 | } | ||
5629 | |||
5630 | static void | ||
5631 | nfs4_layoutcommit_done(struct rpc_task *task, void *calldata) | ||
5632 | { | ||
5633 | struct nfs4_layoutcommit_data *data = calldata; | ||
5634 | struct nfs_server *server = NFS_SERVER(data->args.inode); | ||
5635 | |||
5636 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | ||
5637 | return; | ||
5638 | |||
5639 | switch (task->tk_status) { /* Just ignore these failures */ | ||
5640 | case NFS4ERR_DELEG_REVOKED: /* layout was recalled */ | ||
5641 | case NFS4ERR_BADIOMODE: /* no IOMODE_RW layout for range */ | ||
5642 | case NFS4ERR_BADLAYOUT: /* no layout */ | ||
5643 | case NFS4ERR_GRACE: /* loca_recalim always false */ | ||
5644 | task->tk_status = 0; | ||
5645 | } | ||
5646 | |||
5647 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) { | ||
5648 | nfs_restart_rpc(task, server->nfs_client); | ||
5649 | return; | ||
5650 | } | ||
5651 | |||
5652 | if (task->tk_status == 0) | ||
5653 | nfs_post_op_update_inode_force_wcc(data->args.inode, | ||
5654 | data->res.fattr); | ||
5655 | } | ||
5656 | |||
5657 | static void nfs4_layoutcommit_release(void *calldata) | ||
5658 | { | ||
5659 | struct nfs4_layoutcommit_data *data = calldata; | ||
5660 | |||
5661 | /* Matched by references in pnfs_set_layoutcommit */ | ||
5662 | put_lseg(data->lseg); | ||
5663 | put_rpccred(data->cred); | ||
5664 | kfree(data); | ||
5665 | } | ||
5666 | |||
5667 | static const struct rpc_call_ops nfs4_layoutcommit_ops = { | ||
5668 | .rpc_call_prepare = nfs4_layoutcommit_prepare, | ||
5669 | .rpc_call_done = nfs4_layoutcommit_done, | ||
5670 | .rpc_release = nfs4_layoutcommit_release, | ||
5671 | }; | ||
5672 | |||
5673 | int | ||
5674 | nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, int sync) | ||
5675 | { | ||
5676 | struct rpc_message msg = { | ||
5677 | .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTCOMMIT], | ||
5678 | .rpc_argp = &data->args, | ||
5679 | .rpc_resp = &data->res, | ||
5680 | .rpc_cred = data->cred, | ||
5681 | }; | ||
5682 | struct rpc_task_setup task_setup_data = { | ||
5683 | .task = &data->task, | ||
5684 | .rpc_client = NFS_CLIENT(data->args.inode), | ||
5685 | .rpc_message = &msg, | ||
5686 | .callback_ops = &nfs4_layoutcommit_ops, | ||
5687 | .callback_data = data, | ||
5688 | .flags = RPC_TASK_ASYNC, | ||
5689 | }; | ||
5690 | struct rpc_task *task; | ||
5691 | int status = 0; | ||
5692 | |||
5693 | dprintk("NFS: %4d initiating layoutcommit call. sync %d " | ||
5694 | "lbw: %llu inode %lu\n", | ||
5695 | data->task.tk_pid, sync, | ||
5696 | data->args.lastbytewritten, | ||
5697 | data->args.inode->i_ino); | ||
5698 | |||
5699 | task = rpc_run_task(&task_setup_data); | ||
5700 | if (IS_ERR(task)) | ||
5701 | return PTR_ERR(task); | ||
5702 | if (!sync) | ||
5703 | goto out; | ||
5704 | status = nfs4_wait_for_completion_rpc_task(task); | ||
5705 | if (status != 0) | ||
5706 | goto out; | ||
5707 | status = task->tk_status; | ||
5708 | out: | ||
5709 | dprintk("%s: status %d\n", __func__, status); | ||
5710 | rpc_put_task(task); | ||
5711 | return status; | ||
5712 | } | ||
5619 | #endif /* CONFIG_NFS_V4_1 */ | 5713 | #endif /* CONFIG_NFS_V4_1 */ |
5620 | 5714 | ||
5621 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { | 5715 | struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 07cdf925c524..207d399c8dee 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -324,6 +324,18 @@ static int nfs4_stat_to_errno(int); | |||
324 | #define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \ | 324 | #define decode_layoutget_maxsz (op_decode_hdr_maxsz + 8 + \ |
325 | decode_stateid_maxsz + \ | 325 | decode_stateid_maxsz + \ |
326 | XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE)) | 326 | XDR_QUADLEN(PNFS_LAYOUT_MAXSIZE)) |
327 | #define encode_layoutcommit_maxsz (op_encode_hdr_maxsz + \ | ||
328 | 2 /* offset */ + \ | ||
329 | 2 /* length */ + \ | ||
330 | 1 /* reclaim */ + \ | ||
331 | encode_stateid_maxsz + \ | ||
332 | 1 /* new offset (true) */ + \ | ||
333 | 2 /* last byte written */ + \ | ||
334 | 1 /* nt_timechanged (false) */ + \ | ||
335 | 1 /* layoutupdate4 layout type */ + \ | ||
336 | 1 /* NULL filelayout layoutupdate4 payload */) | ||
337 | #define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3) | ||
338 | |||
327 | #else /* CONFIG_NFS_V4_1 */ | 339 | #else /* CONFIG_NFS_V4_1 */ |
328 | #define encode_sequence_maxsz 0 | 340 | #define encode_sequence_maxsz 0 |
329 | #define decode_sequence_maxsz 0 | 341 | #define decode_sequence_maxsz 0 |
@@ -727,6 +739,17 @@ static int nfs4_stat_to_errno(int); | |||
727 | decode_sequence_maxsz + \ | 739 | decode_sequence_maxsz + \ |
728 | decode_putfh_maxsz + \ | 740 | decode_putfh_maxsz + \ |
729 | decode_layoutget_maxsz) | 741 | decode_layoutget_maxsz) |
742 | #define NFS4_enc_layoutcommit_sz (compound_encode_hdr_maxsz + \ | ||
743 | encode_sequence_maxsz +\ | ||
744 | encode_putfh_maxsz + \ | ||
745 | encode_layoutcommit_maxsz + \ | ||
746 | encode_getattr_maxsz) | ||
747 | #define NFS4_dec_layoutcommit_sz (compound_decode_hdr_maxsz + \ | ||
748 | decode_sequence_maxsz + \ | ||
749 | decode_putfh_maxsz + \ | ||
750 | decode_layoutcommit_maxsz + \ | ||
751 | decode_getattr_maxsz) | ||
752 | |||
730 | 753 | ||
731 | const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + | 754 | const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + |
732 | compound_encode_hdr_maxsz + | 755 | compound_encode_hdr_maxsz + |
@@ -1816,6 +1839,34 @@ encode_layoutget(struct xdr_stream *xdr, | |||
1816 | hdr->nops++; | 1839 | hdr->nops++; |
1817 | hdr->replen += decode_layoutget_maxsz; | 1840 | hdr->replen += decode_layoutget_maxsz; |
1818 | } | 1841 | } |
1842 | |||
1843 | static int | ||
1844 | encode_layoutcommit(struct xdr_stream *xdr, | ||
1845 | const struct nfs4_layoutcommit_args *args, | ||
1846 | struct compound_hdr *hdr) | ||
1847 | { | ||
1848 | __be32 *p; | ||
1849 | |||
1850 | dprintk("%s: lbw: %llu type: %d\n", __func__, args->lastbytewritten, | ||
1851 | NFS_SERVER(args->inode)->pnfs_curr_ld->id); | ||
1852 | |||
1853 | p = reserve_space(xdr, 48 + NFS4_STATEID_SIZE); | ||
1854 | *p++ = cpu_to_be32(OP_LAYOUTCOMMIT); | ||
1855 | /* Only whole file layouts */ | ||
1856 | p = xdr_encode_hyper(p, 0); /* offset */ | ||
1857 | p = xdr_encode_hyper(p, NFS4_MAX_UINT64); /* length */ | ||
1858 | *p++ = cpu_to_be32(0); /* reclaim */ | ||
1859 | p = xdr_encode_opaque_fixed(p, args->stateid.data, NFS4_STATEID_SIZE); | ||
1860 | *p++ = cpu_to_be32(1); /* newoffset = TRUE */ | ||
1861 | p = xdr_encode_hyper(p, args->lastbytewritten); | ||
1862 | *p++ = cpu_to_be32(0); /* Never send time_modify_changed */ | ||
1863 | *p++ = cpu_to_be32(NFS_SERVER(args->inode)->pnfs_curr_ld->id);/* type */ | ||
1864 | *p++ = cpu_to_be32(0); /* no file layout payload */ | ||
1865 | |||
1866 | hdr->nops++; | ||
1867 | hdr->replen += decode_layoutcommit_maxsz; | ||
1868 | return 0; | ||
1869 | } | ||
1819 | #endif /* CONFIG_NFS_V4_1 */ | 1870 | #endif /* CONFIG_NFS_V4_1 */ |
1820 | 1871 | ||
1821 | /* | 1872 | /* |
@@ -2607,6 +2658,26 @@ static void nfs4_xdr_enc_layoutget(struct rpc_rqst *req, | |||
2607 | encode_layoutget(xdr, args, &hdr); | 2658 | encode_layoutget(xdr, args, &hdr); |
2608 | encode_nops(&hdr); | 2659 | encode_nops(&hdr); |
2609 | } | 2660 | } |
2661 | |||
2662 | /* | ||
2663 | * Encode LAYOUTCOMMIT request | ||
2664 | */ | ||
2665 | static int nfs4_xdr_enc_layoutcommit(struct rpc_rqst *req, | ||
2666 | struct xdr_stream *xdr, | ||
2667 | struct nfs4_layoutcommit_args *args) | ||
2668 | { | ||
2669 | struct compound_hdr hdr = { | ||
2670 | .minorversion = nfs4_xdr_minorversion(&args->seq_args), | ||
2671 | }; | ||
2672 | |||
2673 | encode_compound_hdr(xdr, req, &hdr); | ||
2674 | encode_sequence(xdr, &args->seq_args, &hdr); | ||
2675 | encode_putfh(xdr, NFS_FH(args->inode), &hdr); | ||
2676 | encode_layoutcommit(xdr, args, &hdr); | ||
2677 | encode_getfattr(xdr, args->bitmask, &hdr); | ||
2678 | encode_nops(&hdr); | ||
2679 | return 0; | ||
2680 | } | ||
2610 | #endif /* CONFIG_NFS_V4_1 */ | 2681 | #endif /* CONFIG_NFS_V4_1 */ |
2611 | 2682 | ||
2612 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) | 2683 | static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) |
@@ -5007,6 +5078,35 @@ out_overflow: | |||
5007 | print_overflow_msg(__func__, xdr); | 5078 | print_overflow_msg(__func__, xdr); |
5008 | return -EIO; | 5079 | return -EIO; |
5009 | } | 5080 | } |
5081 | |||
5082 | static int decode_layoutcommit(struct xdr_stream *xdr, | ||
5083 | struct rpc_rqst *req, | ||
5084 | struct nfs4_layoutcommit_res *res) | ||
5085 | { | ||
5086 | __be32 *p; | ||
5087 | __u32 sizechanged; | ||
5088 | int status; | ||
5089 | |||
5090 | status = decode_op_hdr(xdr, OP_LAYOUTCOMMIT); | ||
5091 | if (status) | ||
5092 | return status; | ||
5093 | |||
5094 | p = xdr_inline_decode(xdr, 4); | ||
5095 | if (unlikely(!p)) | ||
5096 | goto out_overflow; | ||
5097 | sizechanged = be32_to_cpup(p); | ||
5098 | |||
5099 | if (sizechanged) { | ||
5100 | /* throw away new size */ | ||
5101 | p = xdr_inline_decode(xdr, 8); | ||
5102 | if (unlikely(!p)) | ||
5103 | goto out_overflow; | ||
5104 | } | ||
5105 | return 0; | ||
5106 | out_overflow: | ||
5107 | print_overflow_msg(__func__, xdr); | ||
5108 | return -EIO; | ||
5109 | } | ||
5010 | #endif /* CONFIG_NFS_V4_1 */ | 5110 | #endif /* CONFIG_NFS_V4_1 */ |
5011 | 5111 | ||
5012 | /* | 5112 | /* |
@@ -6068,6 +6168,34 @@ static int nfs4_xdr_dec_layoutget(struct rpc_rqst *rqstp, | |||
6068 | out: | 6168 | out: |
6069 | return status; | 6169 | return status; |
6070 | } | 6170 | } |
6171 | |||
6172 | /* | ||
6173 | * Decode LAYOUTCOMMIT response | ||
6174 | */ | ||
6175 | static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp, | ||
6176 | struct xdr_stream *xdr, | ||
6177 | struct nfs4_layoutcommit_res *res) | ||
6178 | { | ||
6179 | struct compound_hdr hdr; | ||
6180 | int status; | ||
6181 | |||
6182 | status = decode_compound_hdr(xdr, &hdr); | ||
6183 | if (status) | ||
6184 | goto out; | ||
6185 | status = decode_sequence(xdr, &res->seq_res, rqstp); | ||
6186 | if (status) | ||
6187 | goto out; | ||
6188 | status = decode_putfh(xdr); | ||
6189 | if (status) | ||
6190 | goto out; | ||
6191 | status = decode_layoutcommit(xdr, rqstp, res); | ||
6192 | if (status) | ||
6193 | goto out; | ||
6194 | decode_getfattr(xdr, res->fattr, res->server, | ||
6195 | !RPC_IS_ASYNC(rqstp->rq_task)); | ||
6196 | out: | ||
6197 | return status; | ||
6198 | } | ||
6071 | #endif /* CONFIG_NFS_V4_1 */ | 6199 | #endif /* CONFIG_NFS_V4_1 */ |
6072 | 6200 | ||
6073 | /** | 6201 | /** |
@@ -6269,6 +6397,7 @@ struct rpc_procinfo nfs4_procedures[] = { | |||
6269 | PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete), | 6397 | PROC(RECLAIM_COMPLETE, enc_reclaim_complete, dec_reclaim_complete), |
6270 | PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo), | 6398 | PROC(GETDEVICEINFO, enc_getdeviceinfo, dec_getdeviceinfo), |
6271 | PROC(LAYOUTGET, enc_layoutget, dec_layoutget), | 6399 | PROC(LAYOUTGET, enc_layoutget, dec_layoutget), |
6400 | PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit), | ||
6272 | #endif /* CONFIG_NFS_V4_1 */ | 6401 | #endif /* CONFIG_NFS_V4_1 */ |
6273 | }; | 6402 | }; |
6274 | 6403 | ||
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index c67565965f2a..2a08ca0dddc1 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -946,3 +946,97 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata, | |||
946 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | 946 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); |
947 | return trypnfs; | 947 | return trypnfs; |
948 | } | 948 | } |
949 | |||
950 | /* | ||
951 | * Currently there is only one (whole file) write lseg. | ||
952 | */ | ||
953 | static struct pnfs_layout_segment *pnfs_list_write_lseg(struct inode *inode) | ||
954 | { | ||
955 | struct pnfs_layout_segment *lseg, *rv = NULL; | ||
956 | |||
957 | list_for_each_entry(lseg, &NFS_I(inode)->layout->plh_segs, pls_list) | ||
958 | if (lseg->pls_range.iomode == IOMODE_RW) | ||
959 | rv = lseg; | ||
960 | return rv; | ||
961 | } | ||
962 | |||
963 | void | ||
964 | pnfs_set_layoutcommit(struct nfs_write_data *wdata) | ||
965 | { | ||
966 | struct nfs_inode *nfsi = NFS_I(wdata->inode); | ||
967 | loff_t end_pos = wdata->args.offset + wdata->res.count; | ||
968 | |||
969 | spin_lock(&nfsi->vfs_inode.i_lock); | ||
970 | if (!test_and_set_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { | ||
971 | /* references matched in nfs4_layoutcommit_release */ | ||
972 | get_lseg(wdata->lseg); | ||
973 | wdata->lseg->pls_lc_cred = | ||
974 | get_rpccred(wdata->args.context->state->owner->so_cred); | ||
975 | mark_inode_dirty_sync(wdata->inode); | ||
976 | dprintk("%s: Set layoutcommit for inode %lu ", | ||
977 | __func__, wdata->inode->i_ino); | ||
978 | } | ||
979 | if (end_pos > wdata->lseg->pls_end_pos) | ||
980 | wdata->lseg->pls_end_pos = end_pos; | ||
981 | spin_unlock(&nfsi->vfs_inode.i_lock); | ||
982 | } | ||
983 | EXPORT_SYMBOL_GPL(pnfs_set_layoutcommit); | ||
984 | |||
985 | int | ||
986 | pnfs_layoutcommit_inode(struct inode *inode, int sync) | ||
987 | { | ||
988 | struct nfs4_layoutcommit_data *data; | ||
989 | struct nfs_inode *nfsi = NFS_I(inode); | ||
990 | struct pnfs_layout_segment *lseg; | ||
991 | struct rpc_cred *cred; | ||
992 | loff_t end_pos; | ||
993 | int status = 0; | ||
994 | |||
995 | dprintk("--> %s inode %lu\n", __func__, inode->i_ino); | ||
996 | |||
997 | /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */ | ||
998 | data = kzalloc(sizeof(*data), GFP_NOFS); | ||
999 | spin_lock(&inode->i_lock); | ||
1000 | |||
1001 | if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) { | ||
1002 | spin_unlock(&inode->i_lock); | ||
1003 | kfree(data); | ||
1004 | goto out; | ||
1005 | } | ||
1006 | /* | ||
1007 | * Currently only one (whole file) write lseg which is referenced | ||
1008 | * in pnfs_set_layoutcommit and will be found. | ||
1009 | */ | ||
1010 | lseg = pnfs_list_write_lseg(inode); | ||
1011 | |||
1012 | end_pos = lseg->pls_end_pos; | ||
1013 | cred = lseg->pls_lc_cred; | ||
1014 | lseg->pls_end_pos = 0; | ||
1015 | lseg->pls_lc_cred = NULL; | ||
1016 | |||
1017 | if (!data) { | ||
1018 | put_lseg(lseg); | ||
1019 | spin_unlock(&inode->i_lock); | ||
1020 | put_rpccred(cred); | ||
1021 | status = -ENOMEM; | ||
1022 | goto out; | ||
1023 | } else { | ||
1024 | memcpy(&data->args.stateid.data, nfsi->layout->plh_stateid.data, | ||
1025 | sizeof(nfsi->layout->plh_stateid.data)); | ||
1026 | } | ||
1027 | spin_unlock(&inode->i_lock); | ||
1028 | |||
1029 | data->args.inode = inode; | ||
1030 | data->lseg = lseg; | ||
1031 | data->cred = cred; | ||
1032 | nfs_fattr_init(&data->fattr); | ||
1033 | data->args.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask; | ||
1034 | data->res.fattr = &data->fattr; | ||
1035 | data->args.lastbytewritten = end_pos - 1; | ||
1036 | data->res.server = NFS_SERVER(inode); | ||
1037 | |||
1038 | status = nfs4_proc_layoutcommit(data, sync); | ||
1039 | out: | ||
1040 | dprintk("<-- %s status %d\n", __func__, status); | ||
1041 | return status; | ||
1042 | } | ||
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 5370f1b9aa43..0806c77862b6 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
@@ -43,6 +43,8 @@ struct pnfs_layout_segment { | |||
43 | atomic_t pls_refcount; | 43 | atomic_t pls_refcount; |
44 | unsigned long pls_flags; | 44 | unsigned long pls_flags; |
45 | struct pnfs_layout_hdr *pls_layout; | 45 | struct pnfs_layout_hdr *pls_layout; |
46 | struct rpc_cred *pls_lc_cred; /* LAYOUTCOMMIT credential */ | ||
47 | loff_t pls_end_pos; /* LAYOUTCOMMIT write end */ | ||
46 | }; | 48 | }; |
47 | 49 | ||
48 | enum pnfs_try_status { | 50 | enum pnfs_try_status { |
@@ -152,7 +154,8 @@ bool pnfs_roc(struct inode *ino); | |||
152 | void pnfs_roc_release(struct inode *ino); | 154 | void pnfs_roc_release(struct inode *ino); |
153 | void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); | 155 | void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); |
154 | bool pnfs_roc_drain(struct inode *ino, u32 *barrier); | 156 | bool pnfs_roc_drain(struct inode *ino, u32 *barrier); |
155 | 157 | void pnfs_set_layoutcommit(struct nfs_write_data *wdata); | |
158 | int pnfs_layoutcommit_inode(struct inode *inode, int sync); | ||
156 | 159 | ||
157 | static inline int lo_fail_bit(u32 iomode) | 160 | static inline int lo_fail_bit(u32 iomode) |
158 | { | 161 | { |
@@ -325,6 +328,10 @@ static inline void pnfs_clear_request_commit(struct nfs_page *req) | |||
325 | { | 328 | { |
326 | } | 329 | } |
327 | 330 | ||
331 | static inline int pnfs_layoutcommit_inode(struct inode *inode, int sync) | ||
332 | { | ||
333 | return 0; | ||
334 | } | ||
328 | #endif /* CONFIG_NFS_V4_1 */ | 335 | #endif /* CONFIG_NFS_V4_1 */ |
329 | 336 | ||
330 | #endif /* FS_NFS_PNFS_H */ | 337 | #endif /* FS_NFS_PNFS_H */ |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index e7aeda0663c5..a03c11f9081e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1562,7 +1562,20 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr | |||
1562 | 1562 | ||
1563 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) | 1563 | int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
1564 | { | 1564 | { |
1565 | return nfs_commit_unstable_pages(inode, wbc); | 1565 | int ret; |
1566 | |||
1567 | ret = nfs_commit_unstable_pages(inode, wbc); | ||
1568 | if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) { | ||
1569 | int status, sync = wbc->sync_mode; | ||
1570 | |||
1571 | if (wbc->nonblocking || wbc->for_background) | ||
1572 | sync = 0; | ||
1573 | |||
1574 | status = pnfs_layoutcommit_inode(inode, sync); | ||
1575 | if (status < 0) | ||
1576 | return status; | ||
1577 | } | ||
1578 | return ret; | ||
1566 | } | 1579 | } |
1567 | 1580 | ||
1568 | /* | 1581 | /* |