aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlga Kornievskaia <kolga@netapp.com>2018-07-20 18:19:20 -0400
committerJ. Bruce Fields <bfields@redhat.com>2018-09-25 20:34:54 -0400
commite0639dc5805a9d4faaa2c07ad98fa853b9529dd3 (patch)
tree6807e44cd08cf5035f46d4f01d1a0db486cac7d0
parent885e2bf3ea5121975ade0d7866ab6226a8547dc9 (diff)
NFSD introduce async copy feature
Upon receiving a request for async copy, create a new kthread. If we get asynchronous request, make sure to copy the needed arguments/state from the stack before starting the copy. Then start the thread and reply back to the client indicating copy is asynchronous. nfsd_copy_file_range() will copy in a loop over the total number of bytes is needed to copy. In case a failure happens in the middle, we ignore the error and return how much we copied so far. Once done creating a workitem for the callback workqueue and send CB_OFFLOAD with the results. The lifetime of the copy stateid is bound to the vfs copy. This way we don't need to keep the nfsd_net structure for the callback. We could keep it around longer so that an OFFLOAD_STATUS that came late would still get results, but clients should be able to deal without that. We handle OFFLOAD_CANCEL by sending a signal to the copy thread and calling kthread_stop. A client should cancel any ongoing copies before calling DESTROY_CLIENT; if not, we return a CLIENT_BUSY error. If the client is destroyed for some other reason (lease expiration, or server shutdown), we must clean up any ongoing copies ourselves. Signed-off-by: Olga Kornievskaia <kolga@netapp.com> [colin.king@canonical.com: fix leak in error case] [bfields@fieldses.org: remove signalling, merge patches] Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/netns.h8
-rw-r--r--fs/nfsd/nfs4proc.c261
-rw-r--r--fs/nfsd/nfs4state.c38
-rw-r--r--fs/nfsd/nfs4xdr.c21
-rw-r--r--fs/nfsd/nfsctl.c1
-rw-r--r--fs/nfsd/state.h9
-rw-r--r--fs/nfsd/xdr4.h12
7 files changed, 326 insertions, 24 deletions
diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h
index 426f55005697..32cb8c027483 100644
--- a/fs/nfsd/netns.h
+++ b/fs/nfsd/netns.h
@@ -123,6 +123,14 @@ struct nfsd_net {
123 123
124 wait_queue_head_t ntf_wq; 124 wait_queue_head_t ntf_wq;
125 atomic_t ntf_refcnt; 125 atomic_t ntf_refcnt;
126
127 /*
128 * clientid and stateid data for construction of net unique COPY
129 * stateids.
130 */
131 u32 s2s_cp_cl_id;
132 struct idr s2s_cp_stateids;
133 spinlock_t s2s_cp_lock;
126}; 134};
127 135
128/* Simple check to find out if a given net was properly initialized */ 136/* Simple check to find out if a given net was properly initialized */
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index 0c7832321010..edff074d38c7 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -36,6 +36,7 @@
36#include <linux/file.h> 36#include <linux/file.h>
37#include <linux/falloc.h> 37#include <linux/falloc.h>
38#include <linux/slab.h> 38#include <linux/slab.h>
39#include <linux/kthread.h>
39 40
40#include "idmap.h" 41#include "idmap.h"
41#include "cache.h" 42#include "cache.h"
@@ -1089,37 +1090,236 @@ out:
1089 return status; 1090 return status;
1090} 1091}
1091 1092
1093void nfs4_put_copy(struct nfsd4_copy *copy)
1094{
1095 if (!refcount_dec_and_test(&copy->refcount))
1096 return;
1097 kfree(copy);
1098}
1099
1100static bool
1101check_and_set_stop_copy(struct nfsd4_copy *copy)
1102{
1103 bool value;
1104
1105 spin_lock(&copy->cp_clp->async_lock);
1106 value = copy->stopped;
1107 if (!copy->stopped)
1108 copy->stopped = true;
1109 spin_unlock(&copy->cp_clp->async_lock);
1110 return value;
1111}
1112
1113static void nfsd4_stop_copy(struct nfsd4_copy *copy)
1114{
1115 /* only 1 thread should stop the copy */
1116 if (!check_and_set_stop_copy(copy))
1117 kthread_stop(copy->copy_task);
1118 nfs4_put_copy(copy);
1119}
1120
1121static struct nfsd4_copy *nfsd4_get_copy(struct nfs4_client *clp)
1122{
1123 struct nfsd4_copy *copy = NULL;
1124
1125 spin_lock(&clp->async_lock);
1126 if (!list_empty(&clp->async_copies)) {
1127 copy = list_first_entry(&clp->async_copies, struct nfsd4_copy,
1128 copies);
1129 refcount_inc(&copy->refcount);
1130 }
1131 spin_unlock(&clp->async_lock);
1132 return copy;
1133}
1134
1135void nfsd4_shutdown_copy(struct nfs4_client *clp)
1136{
1137 struct nfsd4_copy *copy;
1138
1139 while ((copy = nfsd4_get_copy(clp)) != NULL)
1140 nfsd4_stop_copy(copy);
1141}
1142
1143static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
1144{
1145 struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb);
1146
1147 nfs4_put_copy(copy);
1148}
1149
1150static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,
1151 struct rpc_task *task)
1152{
1153 return 1;
1154}
1155
1156static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = {
1157 .release = nfsd4_cb_offload_release,
1158 .done = nfsd4_cb_offload_done
1159};
1160
1161static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync)
1162{
1163 copy->cp_res.wr_stable_how = NFS_UNSTABLE;
1164 copy->cp_synchronous = sync;
1165 gen_boot_verifier(&copy->cp_res.wr_verifier, copy->cp_clp->net);
1166}
1167
1168static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
1169{
1170 ssize_t bytes_copied = 0;
1171 size_t bytes_total = copy->cp_count;
1172 u64 src_pos = copy->cp_src_pos;
1173 u64 dst_pos = copy->cp_dst_pos;
1174
1175 do {
1176 if (kthread_should_stop())
1177 break;
1178 bytes_copied = nfsd_copy_file_range(copy->file_src, src_pos,
1179 copy->file_dst, dst_pos, bytes_total);
1180 if (bytes_copied <= 0)
1181 break;
1182 bytes_total -= bytes_copied;
1183 copy->cp_res.wr_bytes_written += bytes_copied;
1184 src_pos += bytes_copied;
1185 dst_pos += bytes_copied;
1186 } while (bytes_total > 0 && !copy->cp_synchronous);
1187 return bytes_copied;
1188}
1189
1190static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
1191{
1192 __be32 status;
1193 ssize_t bytes;
1194
1195 bytes = _nfsd_copy_file_range(copy);
1196 /* for async copy, we ignore the error, client can always retry
1197 * to get the error
1198 */
1199 if (bytes < 0 && !copy->cp_res.wr_bytes_written)
1200 status = nfserrno(bytes);
1201 else {
1202 nfsd4_init_copy_res(copy, sync);
1203 status = nfs_ok;
1204 }
1205
1206 fput(copy->file_src);
1207 fput(copy->file_dst);
1208 return status;
1209}
1210
1211static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
1212{
1213 dst->cp_src_pos = src->cp_src_pos;
1214 dst->cp_dst_pos = src->cp_dst_pos;
1215 dst->cp_count = src->cp_count;
1216 dst->cp_synchronous = src->cp_synchronous;
1217 memcpy(&dst->cp_res, &src->cp_res, sizeof(src->cp_res));
1218 memcpy(&dst->fh, &src->fh, sizeof(src->fh));
1219 dst->cp_clp = src->cp_clp;
1220 dst->file_dst = get_file(src->file_dst);
1221 dst->file_src = get_file(src->file_src);
1222 memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
1223}
1224
1225static void cleanup_async_copy(struct nfsd4_copy *copy)
1226{
1227 nfs4_free_cp_state(copy);
1228 fput(copy->file_dst);
1229 fput(copy->file_src);
1230 spin_lock(&copy->cp_clp->async_lock);
1231 list_del(&copy->copies);
1232 spin_unlock(&copy->cp_clp->async_lock);
1233 nfs4_put_copy(copy);
1234}
1235
1236static int nfsd4_do_async_copy(void *data)
1237{
1238 struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
1239 struct nfsd4_copy *cb_copy;
1240
1241 copy->nfserr = nfsd4_do_copy(copy, 0);
1242 cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
1243 if (!cb_copy)
1244 goto out;
1245 memcpy(&cb_copy->cp_res, &copy->cp_res, sizeof(copy->cp_res));
1246 cb_copy->cp_clp = copy->cp_clp;
1247 cb_copy->nfserr = copy->nfserr;
1248 memcpy(&cb_copy->fh, &copy->fh, sizeof(copy->fh));
1249 nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp,
1250 &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD);
1251 nfsd4_run_cb(&cb_copy->cp_cb);
1252out:
1253 cleanup_async_copy(copy);
1254 return 0;
1255}
1256
1092static __be32 1257static __be32
1093nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 1258nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1094 union nfsd4_op_u *u) 1259 union nfsd4_op_u *u)
1095{ 1260{
1096 struct nfsd4_copy *copy = &u->copy; 1261 struct nfsd4_copy *copy = &u->copy;
1097 struct file *src, *dst;
1098 __be32 status; 1262 __be32 status;
1099 ssize_t bytes; 1263 struct nfsd4_copy *async_copy = NULL;
1100 1264
1101 status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid, &src, 1265 status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
1102 &copy->cp_dst_stateid, &dst); 1266 &copy->file_src, &copy->cp_dst_stateid,
1267 &copy->file_dst);
1103 if (status) 1268 if (status)
1104 goto out; 1269 goto out;
1105 1270
1106 bytes = nfsd_copy_file_range(src, copy->cp_src_pos, 1271 copy->cp_clp = cstate->clp;
1107 dst, copy->cp_dst_pos, copy->cp_count); 1272 memcpy(&copy->fh, &cstate->current_fh.fh_handle,
1273 sizeof(struct knfsd_fh));
1274 if (!copy->cp_synchronous) {
1275 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1108 1276
1109 if (bytes < 0) 1277 status = nfserrno(-ENOMEM);
1110 status = nfserrno(bytes); 1278 async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
1111 else { 1279 if (!async_copy)
1112 copy->cp_res.wr_bytes_written = bytes; 1280 goto out;
1113 copy->cp_res.wr_stable_how = NFS_UNSTABLE; 1281 if (!nfs4_init_cp_state(nn, copy)) {
1114 copy->cp_synchronous = 1; 1282 kfree(async_copy);
1115 gen_boot_verifier(&copy->cp_res.wr_verifier, SVC_NET(rqstp)); 1283 goto out;
1284 }
1285 refcount_set(&async_copy->refcount, 1);
1286 memcpy(&copy->cp_res.cb_stateid, &copy->cp_stateid,
1287 sizeof(copy->cp_stateid));
1288 dup_copy_fields(copy, async_copy);
1289 async_copy->copy_task = kthread_create(nfsd4_do_async_copy,
1290 async_copy, "%s", "copy thread");
1291 if (IS_ERR(async_copy->copy_task))
1292 goto out_err;
1293 spin_lock(&async_copy->cp_clp->async_lock);
1294 list_add(&async_copy->copies,
1295 &async_copy->cp_clp->async_copies);
1296 spin_unlock(&async_copy->cp_clp->async_lock);
1297 wake_up_process(async_copy->copy_task);
1116 status = nfs_ok; 1298 status = nfs_ok;
1117 } 1299 } else
1118 1300 status = nfsd4_do_copy(copy, 1);
1119 fput(src);
1120 fput(dst);
1121out: 1301out:
1122 return status; 1302 return status;
1303out_err:
1304 cleanup_async_copy(async_copy);
1305 goto out;
1306}
1307
1308struct nfsd4_copy *
1309find_async_copy(struct nfs4_client *clp, stateid_t *stateid)
1310{
1311 struct nfsd4_copy *copy;
1312
1313 spin_lock(&clp->async_lock);
1314 list_for_each_entry(copy, &clp->async_copies, copies) {
1315 if (memcmp(&copy->cp_stateid, stateid, NFS4_STATEID_SIZE))
1316 continue;
1317 refcount_inc(&copy->refcount);
1318 spin_unlock(&clp->async_lock);
1319 return copy;
1320 }
1321 spin_unlock(&clp->async_lock);
1322 return NULL;
1123} 1323}
1124 1324
1125static __be32 1325static __be32
@@ -1127,7 +1327,18 @@ nfsd4_offload_cancel(struct svc_rqst *rqstp,
1127 struct nfsd4_compound_state *cstate, 1327 struct nfsd4_compound_state *cstate,
1128 union nfsd4_op_u *u) 1328 union nfsd4_op_u *u)
1129{ 1329{
1130 return 0; 1330 struct nfsd4_offload_status *os = &u->offload_status;
1331 __be32 status = 0;
1332 struct nfsd4_copy *copy;
1333 struct nfs4_client *clp = cstate->clp;
1334
1335 copy = find_async_copy(clp, &os->stateid);
1336 if (copy)
1337 nfsd4_stop_copy(copy);
1338 else
1339 status = nfserr_bad_stateid;
1340
1341 return status;
1131} 1342}
1132 1343
1133static __be32 1344static __be32
@@ -1157,7 +1368,19 @@ nfsd4_offload_status(struct svc_rqst *rqstp,
1157 struct nfsd4_compound_state *cstate, 1368 struct nfsd4_compound_state *cstate,
1158 union nfsd4_op_u *u) 1369 union nfsd4_op_u *u)
1159{ 1370{
1160 return nfserr_notsupp; 1371 struct nfsd4_offload_status *os = &u->offload_status;
1372 __be32 status = 0;
1373 struct nfsd4_copy *copy;
1374 struct nfs4_client *clp = cstate->clp;
1375
1376 copy = find_async_copy(clp, &os->stateid);
1377 if (copy) {
1378 os->count = copy->cp_res.wr_bytes_written;
1379 nfs4_put_copy(copy);
1380 } else
1381 status = nfserr_bad_stateid;
1382
1383 return status;
1161} 1384}
1162 1385
1163static __be32 1386static __be32
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b0ca0efd2875..07a57d024f95 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -713,6 +713,36 @@ out_free:
713 return NULL; 713 return NULL;
714} 714}
715 715
716/*
717 * Create a unique stateid_t to represent each COPY.
718 */
719int nfs4_init_cp_state(struct nfsd_net *nn, struct nfsd4_copy *copy)
720{
721 int new_id;
722
723 idr_preload(GFP_KERNEL);
724 spin_lock(&nn->s2s_cp_lock);
725 new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, copy, 0, 0, GFP_NOWAIT);
726 spin_unlock(&nn->s2s_cp_lock);
727 idr_preload_end();
728 if (new_id < 0)
729 return 0;
730 copy->cp_stateid.si_opaque.so_id = new_id;
731 copy->cp_stateid.si_opaque.so_clid.cl_boot = nn->boot_time;
732 copy->cp_stateid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id;
733 return 1;
734}
735
736void nfs4_free_cp_state(struct nfsd4_copy *copy)
737{
738 struct nfsd_net *nn;
739
740 nn = net_generic(copy->cp_clp->net, nfsd_net_id);
741 spin_lock(&nn->s2s_cp_lock);
742 idr_remove(&nn->s2s_cp_stateids, copy->cp_stateid.si_opaque.so_id);
743 spin_unlock(&nn->s2s_cp_lock);
744}
745
716static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) 746static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
717{ 747{
718 struct nfs4_stid *stid; 748 struct nfs4_stid *stid;
@@ -1827,6 +1857,8 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name)
1827#ifdef CONFIG_NFSD_PNFS 1857#ifdef CONFIG_NFSD_PNFS
1828 INIT_LIST_HEAD(&clp->cl_lo_states); 1858 INIT_LIST_HEAD(&clp->cl_lo_states);
1829#endif 1859#endif
1860 INIT_LIST_HEAD(&clp->async_copies);
1861 spin_lock_init(&clp->async_lock);
1830 spin_lock_init(&clp->cl_lock); 1862 spin_lock_init(&clp->cl_lock);
1831 rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); 1863 rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
1832 return clp; 1864 return clp;
@@ -1942,6 +1974,7 @@ __destroy_client(struct nfs4_client *clp)
1942 } 1974 }
1943 } 1975 }
1944 nfsd4_return_all_client_layouts(clp); 1976 nfsd4_return_all_client_layouts(clp);
1977 nfsd4_shutdown_copy(clp);
1945 nfsd4_shutdown_callback(clp); 1978 nfsd4_shutdown_callback(clp);
1946 if (clp->cl_cb_conn.cb_xprt) 1979 if (clp->cl_cb_conn.cb_xprt)
1947 svc_xprt_put(clp->cl_cb_conn.cb_xprt); 1980 svc_xprt_put(clp->cl_cb_conn.cb_xprt);
@@ -2475,7 +2508,8 @@ static bool client_has_state(struct nfs4_client *clp)
2475 || !list_empty(&clp->cl_lo_states) 2508 || !list_empty(&clp->cl_lo_states)
2476#endif 2509#endif
2477 || !list_empty(&clp->cl_delegations) 2510 || !list_empty(&clp->cl_delegations)
2478 || !list_empty(&clp->cl_sessions); 2511 || !list_empty(&clp->cl_sessions)
2512 || !list_empty(&clp->async_copies);
2479} 2513}
2480 2514
2481__be32 2515__be32
@@ -7161,6 +7195,8 @@ static int nfs4_state_create_net(struct net *net)
7161 INIT_LIST_HEAD(&nn->close_lru); 7195 INIT_LIST_HEAD(&nn->close_lru);
7162 INIT_LIST_HEAD(&nn->del_recall_lru); 7196 INIT_LIST_HEAD(&nn->del_recall_lru);
7163 spin_lock_init(&nn->client_lock); 7197 spin_lock_init(&nn->client_lock);
7198 spin_lock_init(&nn->s2s_cp_lock);
7199 idr_init(&nn->s2s_cp_stateids);
7164 7200
7165 spin_lock_init(&nn->blocked_locks_lock); 7201 spin_lock_init(&nn->blocked_locks_lock);
7166 INIT_LIST_HEAD(&nn->blocked_locks_lru); 7202 INIT_LIST_HEAD(&nn->blocked_locks_lru);
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index b78280a8af73..3de42a729093 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -4231,15 +4231,27 @@ nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr,
4231#endif /* CONFIG_NFSD_PNFS */ 4231#endif /* CONFIG_NFSD_PNFS */
4232 4232
4233static __be32 4233static __be32
4234nfsd42_encode_write_res(struct nfsd4_compoundres *resp, struct nfsd42_write_res *write) 4234nfsd42_encode_write_res(struct nfsd4_compoundres *resp,
4235 struct nfsd42_write_res *write, bool sync)
4235{ 4236{
4236 __be32 *p; 4237 __be32 *p;
4238 p = xdr_reserve_space(&resp->xdr, 4);
4239 if (!p)
4240 return nfserr_resource;
4237 4241
4238 p = xdr_reserve_space(&resp->xdr, 4 + 8 + 4 + NFS4_VERIFIER_SIZE); 4242 if (sync)
4243 *p++ = cpu_to_be32(0);
4244 else {
4245 __be32 nfserr;
4246 *p++ = cpu_to_be32(1);
4247 nfserr = nfsd4_encode_stateid(&resp->xdr, &write->cb_stateid);
4248 if (nfserr)
4249 return nfserr;
4250 }
4251 p = xdr_reserve_space(&resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE);
4239 if (!p) 4252 if (!p)
4240 return nfserr_resource; 4253 return nfserr_resource;
4241 4254
4242 *p++ = cpu_to_be32(0);
4243 p = xdr_encode_hyper(p, write->wr_bytes_written); 4255 p = xdr_encode_hyper(p, write->wr_bytes_written);
4244 *p++ = cpu_to_be32(write->wr_stable_how); 4256 *p++ = cpu_to_be32(write->wr_stable_how);
4245 p = xdr_encode_opaque_fixed(p, write->wr_verifier.data, 4257 p = xdr_encode_opaque_fixed(p, write->wr_verifier.data,
@@ -4253,7 +4265,8 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr,
4253{ 4265{
4254 __be32 *p; 4266 __be32 *p;
4255 4267
4256 nfserr = nfsd42_encode_write_res(resp, &copy->cp_res); 4268 nfserr = nfsd42_encode_write_res(resp, &copy->cp_res,
4269 copy->cp_synchronous);
4257 if (nfserr) 4270 if (nfserr)
4258 return nfserr; 4271 return nfserr;
4259 4272
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 7fb9f7c667b1..6384c9b94898 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -1242,6 +1242,7 @@ static __net_init int nfsd_init_net(struct net *net)
1242 nn->somebody_reclaimed = false; 1242 nn->somebody_reclaimed = false;
1243 nn->clverifier_counter = prandom_u32(); 1243 nn->clverifier_counter = prandom_u32();
1244 nn->clientid_counter = prandom_u32(); 1244 nn->clientid_counter = prandom_u32();
1245 nn->s2s_cp_cl_id = nn->clientid_counter++;
1245 1246
1246 atomic_set(&nn->ntf_refcnt, 0); 1247 atomic_set(&nn->ntf_refcnt, 0);
1247 init_waitqueue_head(&nn->ntf_wq); 1248 init_waitqueue_head(&nn->ntf_wq);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 6e38d9927448..6aacb325b6a0 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -355,6 +355,8 @@ struct nfs4_client {
355 struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */ 355 struct rpc_wait_queue cl_cb_waitq; /* backchannel callers may */
356 /* wait here for slots */ 356 /* wait here for slots */
357 struct net *net; 357 struct net *net;
358 struct list_head async_copies; /* list of async copies */
359 spinlock_t async_lock; /* lock for async copies */
358}; 360};
359 361
360/* struct nfs4_client_reset 362/* struct nfs4_client_reset
@@ -600,6 +602,7 @@ struct nfsd4_blocked_lock {
600 602
601struct nfsd4_compound_state; 603struct nfsd4_compound_state;
602struct nfsd_net; 604struct nfsd_net;
605struct nfsd4_copy;
603 606
604extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, 607extern __be32 nfs4_preprocess_stateid_op(struct svc_rqst *rqstp,
605 struct nfsd4_compound_state *cstate, struct svc_fh *fhp, 608 struct nfsd4_compound_state *cstate, struct svc_fh *fhp,
@@ -609,6 +612,8 @@ __be32 nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
609 struct nfs4_stid **s, struct nfsd_net *nn); 612 struct nfs4_stid **s, struct nfsd_net *nn);
610struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab, 613struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab,
611 void (*sc_free)(struct nfs4_stid *)); 614 void (*sc_free)(struct nfs4_stid *));
615int nfs4_init_cp_state(struct nfsd_net *nn, struct nfsd4_copy *copy);
616void nfs4_free_cp_state(struct nfsd4_copy *copy);
612void nfs4_unhash_stid(struct nfs4_stid *s); 617void nfs4_unhash_stid(struct nfs4_stid *s);
613void nfs4_put_stid(struct nfs4_stid *s); 618void nfs4_put_stid(struct nfs4_stid *s);
614void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid); 619void nfs4_inc_and_copy_stateid(stateid_t *dst, struct nfs4_stid *stid);
@@ -627,6 +632,7 @@ extern void nfsd4_run_cb(struct nfsd4_callback *cb);
627extern int nfsd4_create_callback_queue(void); 632extern int nfsd4_create_callback_queue(void);
628extern void nfsd4_destroy_callback_queue(void); 633extern void nfsd4_destroy_callback_queue(void);
629extern void nfsd4_shutdown_callback(struct nfs4_client *); 634extern void nfsd4_shutdown_callback(struct nfs4_client *);
635extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
630extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp); 636extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp);
631extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name, 637extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(const char *name,
632 struct nfsd_net *nn); 638 struct nfsd_net *nn);
@@ -634,6 +640,9 @@ extern bool nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn);
634 640
635struct nfs4_file *find_file(struct knfsd_fh *fh); 641struct nfs4_file *find_file(struct knfsd_fh *fh);
636void put_nfs4_file(struct nfs4_file *fi); 642void put_nfs4_file(struct nfs4_file *fi);
643extern void nfs4_put_copy(struct nfsd4_copy *copy);
644extern struct nfsd4_copy *
645find_async_copy(struct nfs4_client *clp, stateid_t *staetid);
637static inline void get_nfs4_file(struct nfs4_file *fi) 646static inline void get_nfs4_file(struct nfs4_file *fi)
638{ 647{
639 refcount_inc(&fi->fi_ref); 648 refcount_inc(&fi->fi_ref);
diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
index 06cf218944c5..feeb6d4bdffd 100644
--- a/fs/nfsd/xdr4.h
+++ b/fs/nfsd/xdr4.h
@@ -532,6 +532,18 @@ struct nfsd4_copy {
532 struct nfsd4_callback cp_cb; 532 struct nfsd4_callback cp_cb;
533 __be32 nfserr; 533 __be32 nfserr;
534 struct knfsd_fh fh; 534 struct knfsd_fh fh;
535
536 struct nfs4_client *cp_clp;
537
538 struct file *file_src;
539 struct file *file_dst;
540
541 stateid_t cp_stateid;
542
543 struct list_head copies;
544 struct task_struct *copy_task;
545 refcount_t refcount;
546 bool stopped;
535}; 547};
536 548
537struct nfsd4_seek { 549struct nfsd4_seek {