Skip to content

Commit 62164f3

Browse files
olgakorn1amschuma-ntap
authored andcommitted
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>
1 parent 67aa744 commit 62164f3

File tree

7 files changed

+104
-9
lines changed

7 files changed

+104
-9
lines changed

fs/nfs/callback_proc.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -662,9 +662,45 @@ __be32 nfs4_callback_notify_lock(void *argp, void *resp,
662662
}
663663
#endif /* CONFIG_NFS_V4_1 */
664664
#ifdef CONFIG_NFS_V4_2
665-
__be32 nfs4_callback_offload(void *args, void *dummy,
665+
static 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,
666679
struct cb_process_state *cps)
667680
{
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+
}
701+
out:
702+
rcu_read_unlock();
703+
668704
return 0;
669705
}
670706
#endif /* CONFIG_NFS_V4_2 */

fs/nfs/client.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,7 @@ struct nfs_server *nfs_alloc_server(void)
886886
INIT_LIST_HEAD(&server->delegations);
887887
INIT_LIST_HEAD(&server->layouts);
888888
INIT_LIST_HEAD(&server->state_owners_lru);
889+
INIT_LIST_HEAD(&server->ss_copies);
889890

890891
atomic_set(&server->active, 0);
891892

fs/nfs/nfs42proc.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,37 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
130130
return err;
131131
}
132132

133+
static 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+
133164
static ssize_t _nfs42_proc_copy(struct file *src,
134165
struct nfs_lock_context *src_lock,
135166
struct file *dst,
@@ -168,28 +199,41 @@ static ssize_t _nfs42_proc_copy(struct file *src,
168199
if (status)
169200
return status;
170201

171-
res->commit_res.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
172-
if (!res->commit_res.verf)
173-
return -ENOMEM;
202+
res->commit_res.verf = NULL;
203+
if (args->sync) {
204+
res->commit_res.verf =
205+
kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
206+
if (!res->commit_res.verf)
207+
return -ENOMEM;
208+
}
174209
status = nfs4_call_sync(server->client, server, &msg,
175210
&args->seq_args, &res->seq_res, 0);
176211
if (status == -ENOTSUPP)
177212
server->caps &= ~NFS_CAP_COPY;
178213
if (status)
179214
goto out;
180215

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,
182218
&res->commit_res.verf->verifier)) {
183219
status = -EAGAIN;
184220
goto out;
185221
}
186222

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+
187230
truncate_pagecache_range(dst_inode, pos_dst,
188231
pos_dst + res->write_res.count);
189232

190233
status = res->write_res.count;
191234
out:
192-
kfree(res->commit_res.verf);
235+
if (args->sync)
236+
kfree(res->commit_res.verf);
193237
return status;
194238
}
195239

@@ -206,6 +250,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
206250
.dst_fh = NFS_FH(file_inode(dst)),
207251
.dst_pos = pos_dst,
208252
.count = count,
253+
.sync = false,
209254
};
210255
struct nfs42_copy_res res;
211256
struct nfs4_exception src_exception = {

fs/nfs/nfs42xdr.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ static void encode_copy(struct xdr_stream *xdr,
150150
encode_uint64(xdr, args->count);
151151

152152
encode_uint32(xdr, 1); /* consecutive = true */
153-
encode_uint32(xdr, 1); /* synchronous = true */
153+
encode_uint32(xdr, args->sync);
154154
encode_uint32(xdr, 0); /* src server list */
155155
}
156156

@@ -273,7 +273,8 @@ static void nfs4_xdr_enc_copy(struct rpc_rqst *req,
273273
encode_savefh(xdr, &hdr);
274274
encode_putfh(xdr, args->dst_fh, &hdr);
275275
encode_copy(xdr, args, &hdr);
276-
encode_copy_commit(xdr, args, &hdr);
276+
if (args->sync)
277+
encode_copy_commit(xdr, args, &hdr);
277278
encode_nops(&hdr);
278279
}
279280

@@ -551,7 +552,8 @@ static int nfs4_xdr_dec_copy(struct rpc_rqst *rqstp,
551552
status = decode_copy(xdr, res);
552553
if (status)
553554
goto out;
554-
status = decode_commit(xdr, &res->commit_res);
555+
if (res->commit_res.verf)
556+
status = decode_commit(xdr, &res->commit_res);
555557
out:
556558
return status;
557559
}

include/linux/nfs_fs.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,15 @@ struct nfs_inode {
185185
struct inode vfs_inode;
186186
};
187187

188+
struct 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+
188197
/*
189198
* Access bit flags
190199
*/

include/linux/nfs_fs_sb.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ struct nfs_server {
208208
struct list_head state_owners_lru;
209209
struct list_head layouts;
210210
struct list_head delegations;
211+
struct list_head ss_copies;
211212

212213
unsigned long mig_gen;
213214
unsigned long mig_status;

include/linux/nfs_xdr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1388,6 +1388,7 @@ struct nfs42_copy_args {
13881388
u64 dst_pos;
13891389

13901390
u64 count;
1391+
bool sync;
13911392
};
13921393

13931394
struct nfs42_write_res {

0 commit comments

Comments
 (0)