summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlga Kornievskaia <kolga@netapp.com>2018-07-09 15:13:31 -0400
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2018-08-09 12:56:39 -0400
commit62164f317972fcd36590578888f33a1994dda519 (patch)
tree24608dd5c9a8cd89f5bb16325e21b44d7064acb3
parent67aa7444c4beb40aafedd8d2c60bbcc54987adda (diff)
NFS add support for asynchronous COPY
Change xdr to always send COPY asynchronously. Keep the list copies send in a list under a server structure. Once copy is sent, it waits on a completion structure that will be signalled by the callback thread that receives CB_OFFLOAD. If CB_OFFLOAD returned an error and even if it returned partial bytes, ignore them (as we can't commit without a verifier to match) and return an error. Signed-off-by: Olga Kornievskaia <kolga@netapp.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r--fs/nfs/callback_proc.c38
-rw-r--r--fs/nfs/client.c1
-rw-r--r--fs/nfs/nfs42proc.c55
-rw-r--r--fs/nfs/nfs42xdr.c8
-rw-r--r--include/linux/nfs_fs.h9
-rw-r--r--include/linux/nfs_fs_sb.h1
-rw-r--r--include/linux/nfs_xdr.h1
7 files changed, 104 insertions, 9 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index d6f45bd176a9..acdda259912e 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -662,9 +662,45 @@ __be32 nfs4_callback_notify_lock(void *argp, void *resp,
662} 662}
663#endif /* CONFIG_NFS_V4_1 */ 663#endif /* CONFIG_NFS_V4_1 */
664#ifdef CONFIG_NFS_V4_2 664#ifdef CONFIG_NFS_V4_2
665__be32 nfs4_callback_offload(void *args, void *dummy, 665static void nfs4_copy_cb_args(struct nfs4_copy_state *cp_state,
666 struct cb_offloadargs *args)
667{
668 cp_state->count = args->wr_count;
669 cp_state->error = args->error;
670 if (!args->error) {
671 cp_state->verf.committed = args->wr_writeverf.committed;
672 memcpy(&cp_state->verf.verifier.data[0],
673 &args->wr_writeverf.verifier.data[0],
674 NFS4_VERIFIER_SIZE);
675 }
676}
677
678__be32 nfs4_callback_offload(void *data, void *dummy,
666 struct cb_process_state *cps) 679 struct cb_process_state *cps)
667{ 680{
681 struct cb_offloadargs *args = data;
682 struct nfs_server *server;
683 struct nfs4_copy_state *copy;
684
685 rcu_read_lock();
686 list_for_each_entry_rcu(server, &cps->clp->cl_superblocks,
687 client_link) {
688 spin_lock(&server->nfs_client->cl_lock);
689 list_for_each_entry(copy, &server->ss_copies, copies) {
690 if (memcmp(args->coa_stateid.other,
691 copy->stateid.other,
692 sizeof(args->coa_stateid.other)))
693 continue;
694 nfs4_copy_cb_args(copy, args);
695 complete(&copy->completion);
696 spin_unlock(&server->nfs_client->cl_lock);
697 goto out;
698 }
699 spin_unlock(&server->nfs_client->cl_lock);
700 }
701out:
702 rcu_read_unlock();
703
668 return 0; 704 return 0;
669} 705}
670#endif /* CONFIG_NFS_V4_2 */ 706#endif /* CONFIG_NFS_V4_2 */
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 377a61654a88..96d5f8135eb9 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -886,6 +886,7 @@ struct nfs_server *nfs_alloc_server(void)
886 INIT_LIST_HEAD(&server->delegations); 886 INIT_LIST_HEAD(&server->delegations);
887 INIT_LIST_HEAD(&server->layouts); 887 INIT_LIST_HEAD(&server->layouts);
888 INIT_LIST_HEAD(&server->state_owners_lru); 888 INIT_LIST_HEAD(&server->state_owners_lru);
889 INIT_LIST_HEAD(&server->ss_copies);
889 890
890 atomic_set(&server->active, 0); 891 atomic_set(&server->active, 0);
891 892
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 5f59b6f65a42..023aea8f6cf1 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -130,6 +130,37 @@ out_unlock:
130 return err; 130 return err;
131} 131}
132 132
133static int handle_async_copy(struct nfs42_copy_res *res,
134 struct nfs_server *server,
135 struct file *src,
136 struct file *dst,
137 nfs4_stateid *src_stateid)
138{
139 struct nfs4_copy_state *copy;
140 int status = NFS4_OK;
141
142 copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
143 if (!copy)
144 return -ENOMEM;
145 memcpy(&copy->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
146 init_completion(&copy->completion);
147
148 spin_lock(&server->nfs_client->cl_lock);
149 list_add_tail(&copy->copies, &server->ss_copies);
150 spin_unlock(&server->nfs_client->cl_lock);
151
152 wait_for_completion_interruptible(&copy->completion);
153 spin_lock(&server->nfs_client->cl_lock);
154 list_del_init(&copy->copies);
155 spin_unlock(&server->nfs_client->cl_lock);
156 res->write_res.count = copy->count;
157 memcpy(&res->write_res.verifier, &copy->verf, sizeof(copy->verf));
158 status = -copy->error;
159
160 kfree(copy);
161 return status;
162}
163
133static ssize_t _nfs42_proc_copy(struct file *src, 164static ssize_t _nfs42_proc_copy(struct file *src,
134 struct nfs_lock_context *src_lock, 165 struct nfs_lock_context *src_lock,
135 struct file *dst, 166 struct file *dst,
@@ -168,9 +199,13 @@ static ssize_t _nfs42_proc_copy(struct file *src,
168 if (status) 199 if (status)
169 return status; 200 return status;
170 201
171 res->commit_res.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS); 202 res->commit_res.verf = NULL;
172 if (!res->commit_res.verf) 203 if (args->sync) {
173 return -ENOMEM; 204 res->commit_res.verf =
205 kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
206 if (!res->commit_res.verf)
207 return -ENOMEM;
208 }
174 status = nfs4_call_sync(server->client, server, &msg, 209 status = nfs4_call_sync(server->client, server, &msg,
175 &args->seq_args, &res->seq_res, 0); 210 &args->seq_args, &res->seq_res, 0);
176 if (status == -ENOTSUPP) 211 if (status == -ENOTSUPP)
@@ -178,18 +213,27 @@ static ssize_t _nfs42_proc_copy(struct file *src,
178 if (status) 213 if (status)
179 goto out; 214 goto out;
180 215
181 if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier, 216 if (args->sync &&
217 nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
182 &res->commit_res.verf->verifier)) { 218 &res->commit_res.verf->verifier)) {
183 status = -EAGAIN; 219 status = -EAGAIN;
184 goto out; 220 goto out;
185 } 221 }
186 222
223 if (!res->synchronous) {
224 status = handle_async_copy(res, server, src, dst,
225 &args->src_stateid);
226 if (status)
227 return status;
228 }
229
187 truncate_pagecache_range(dst_inode, pos_dst, 230 truncate_pagecache_range(dst_inode, pos_dst,
188 pos_dst + res->write_res.count); 231 pos_dst + res->write_res.count);
189 232
190 status = res->write_res.count; 233 status = res->write_res.count;
191out: 234out:
192 kfree(res->commit_res.verf); 235 if (args->sync)
236 kfree(res->commit_res.verf);
193 return status; 237 return status;
194} 238}
195 239
@@ -206,6 +250,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
206 .dst_fh = NFS_FH(file_inode(dst)), 250 .dst_fh = NFS_FH(file_inode(dst)),
207 .dst_pos = pos_dst, 251 .dst_pos = pos_dst,
208 .count = count, 252 .count = count,
253 .sync = false,
209 }; 254 };
210 struct nfs42_copy_res res; 255 struct nfs42_copy_res res;
211 struct nfs4_exception src_exception = { 256 struct nfs4_exception src_exception = {
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index 205c3567ea08..69f72ed2bf87 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -150,7 +150,7 @@ static void encode_copy(struct xdr_stream *xdr,
150 encode_uint64(xdr, args->count); 150 encode_uint64(xdr, args->count);
151 151
152 encode_uint32(xdr, 1); /* consecutive = true */ 152 encode_uint32(xdr, 1); /* consecutive = true */
153 encode_uint32(xdr, 1); /* synchronous = true */ 153 encode_uint32(xdr, args->sync);
154 encode_uint32(xdr, 0); /* src server list */ 154 encode_uint32(xdr, 0); /* src server list */
155} 155}
156 156
@@ -273,7 +273,8 @@ static void nfs4_xdr_enc_copy(struct rpc_rqst *req,
273 encode_savefh(xdr, &hdr); 273 encode_savefh(xdr, &hdr);
274 encode_putfh(xdr, args->dst_fh, &hdr); 274 encode_putfh(xdr, args->dst_fh, &hdr);
275 encode_copy(xdr, args, &hdr); 275 encode_copy(xdr, args, &hdr);
276 encode_copy_commit(xdr, args, &hdr); 276 if (args->sync)
277 encode_copy_commit(xdr, args, &hdr);
277 encode_nops(&hdr); 278 encode_nops(&hdr);
278} 279}
279 280
@@ -551,7 +552,8 @@ static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp,
551 status = decode_copy(xdr, res); 552 status = decode_copy(xdr, res);
552 if (status) 553 if (status)
553 goto out; 554 goto out;
554 status = decode_commit(xdr, &res->commit_res); 555 if (res->commit_res.verf)
556 status = decode_commit(xdr, &res->commit_res);
555out: 557out:
556 return status; 558 return status;
557} 559}
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 2f129bbfaae8..645ad8e342f6 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -185,6 +185,15 @@ struct nfs_inode {
185 struct inode vfs_inode; 185 struct inode vfs_inode;
186}; 186};
187 187
188struct nfs4_copy_state {
189 struct list_head copies;
190 nfs4_stateid stateid;
191 struct completion completion;
192 uint64_t count;
193 struct nfs_writeverf verf;
194 int error;
195};
196
188/* 197/*
189 * Access bit flags 198 * Access bit flags
190 */ 199 */
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index fbc735f08d7e..f88952d7b9fb 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -208,6 +208,7 @@ struct nfs_server {
208 struct list_head state_owners_lru; 208 struct list_head state_owners_lru;
209 struct list_head layouts; 209 struct list_head layouts;
210 struct list_head delegations; 210 struct list_head delegations;
211 struct list_head ss_copies;
211 212
212 unsigned long mig_gen; 213 unsigned long mig_gen;
213 unsigned long mig_status; 214 unsigned long mig_status;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 06ddfa31cbef..bd1c889a9ed9 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1388,6 +1388,7 @@ struct nfs42_copy_args {
1388 u64 dst_pos; 1388 u64 dst_pos;
1389 1389
1390 u64 count; 1390 u64 count;
1391 bool sync;
1391}; 1392};
1392 1393
1393struct nfs42_write_res { 1394struct nfs42_write_res {