aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs42proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/nfs42proc.c')
-rw-r--r--fs/nfs/nfs42proc.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 0f020e4d8421..3e92a3cde15d 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -271,3 +271,74 @@ int nfs42_proc_layoutstats_generic(struct nfs_server *server,
271 return PTR_ERR(task); 271 return PTR_ERR(task);
272 return 0; 272 return 0;
273} 273}
274
275static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
276 struct file *dst_f, loff_t src_offset,
277 loff_t dst_offset, loff_t count)
278{
279 struct inode *src_inode = file_inode(src_f);
280 struct inode *dst_inode = file_inode(dst_f);
281 struct nfs_server *server = NFS_SERVER(dst_inode);
282 struct nfs42_clone_args args = {
283 .src_fh = NFS_FH(src_inode),
284 .dst_fh = NFS_FH(dst_inode),
285 .src_offset = src_offset,
286 .dst_offset = dst_offset,
287 .dst_bitmask = server->cache_consistency_bitmask,
288 };
289 struct nfs42_clone_res res = {
290 .server = server,
291 };
292 int status;
293
294 msg->rpc_argp = &args;
295 msg->rpc_resp = &res;
296
297 status = nfs42_set_rw_stateid(&args.src_stateid, src_f, FMODE_READ);
298 if (status)
299 return status;
300
301 status = nfs42_set_rw_stateid(&args.dst_stateid, dst_f, FMODE_WRITE);
302 if (status)
303 return status;
304
305 res.dst_fattr = nfs_alloc_fattr();
306 if (!res.dst_fattr)
307 return -ENOMEM;
308
309 status = nfs4_call_sync(server->client, server, msg,
310 &args.seq_args, &res.seq_res, 0);
311 if (status == 0)
312 status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
313
314 kfree(res.dst_fattr);
315 return status;
316}
317
318int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
319 loff_t src_offset, loff_t dst_offset, loff_t count)
320{
321 struct rpc_message msg = {
322 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE],
323 };
324 struct inode *inode = file_inode(src_f);
325 struct nfs_server *server = NFS_SERVER(file_inode(src_f));
326 struct nfs4_exception exception = { };
327 int err;
328
329 if (!nfs_server_capable(inode, NFS_CAP_CLONE))
330 return -EOPNOTSUPP;
331
332 do {
333 err = _nfs42_proc_clone(&msg, src_f, dst_f, src_offset,
334 dst_offset, count);
335 if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
336 NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
337 return -EOPNOTSUPP;
338 }
339 err = nfs4_handle_exception(server, err, &exception);
340 } while (exception.retry);
341
342 return err;
343
344}