blob: e34ade844737c1513f49278193a50bd870a196c5 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Anna Schumaker1c6dcbe2014-09-26 13:58:48 -04002/*
3 * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com>
4 */
5#include <linux/fs.h>
Olga Kornievskaia04915672019-06-04 16:14:30 -04006#include <linux/sunrpc/addr.h>
Anna Schumaker1c6dcbe2014-09-26 13:58:48 -04007#include <linux/sunrpc/sched.h>
8#include <linux/nfs.h>
9#include <linux/nfs3.h>
10#include <linux/nfs4.h>
11#include <linux/nfs_xdr.h>
12#include <linux/nfs_fs.h>
13#include "nfs4_fs.h"
14#include "nfs42.h"
Peng Tao1b4a4bd2015-06-23 19:51:56 +080015#include "iostat.h"
16#include "pnfs.h"
Anna Schumakerefc6f4a2017-01-09 15:14:33 -050017#include "nfs4session.h"
Peng Tao1b4a4bd2015-06-23 19:51:56 +080018#include "internal.h"
Olga Kornievskaia04915672019-06-04 16:14:30 -040019#include "delegation.h"
Peng Tao1b4a4bd2015-06-23 19:51:56 +080020
Anna Schumaker291e1b92015-11-16 14:51:07 -050021#define NFSDBG_FACILITY NFSDBG_PROC
Olga Kornievskaiac975c202018-07-09 15:13:34 -040022static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std);
Anna Schumaker1c6dcbe2014-09-26 13:58:48 -040023
Olga Kornievskaia04915672019-06-04 16:14:30 -040024static void nfs42_set_netaddr(struct file *filep, struct nfs42_netaddr *naddr)
25{
26 struct nfs_client *clp = (NFS_SERVER(file_inode(filep)))->nfs_client;
27 unsigned short port = 2049;
28
29 rcu_read_lock();
30 naddr->netid_len = scnprintf(naddr->netid,
31 sizeof(naddr->netid), "%s",
32 rpc_peeraddr2str(clp->cl_rpcclient,
33 RPC_DISPLAY_NETID));
34 naddr->addr_len = scnprintf(naddr->addr,
35 sizeof(naddr->addr),
36 "%s.%u.%u",
37 rpc_peeraddr2str(clp->cl_rpcclient,
38 RPC_DISPLAY_ADDR),
39 port >> 8, port & 255);
40 rcu_read_unlock();
41}
42
Anna Schumakerf4ac1672014-11-25 13:18:15 -050043static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +010044 struct nfs_lock_context *lock, loff_t offset, loff_t len)
Anna Schumakerf4ac1672014-11-25 13:18:15 -050045{
46 struct inode *inode = file_inode(filep);
Anna Schumaker9a519402015-03-16 14:06:23 -040047 struct nfs_server *server = NFS_SERVER(inode);
Anna Schumakerf4ac1672014-11-25 13:18:15 -050048 struct nfs42_falloc_args args = {
49 .falloc_fh = NFS_FH(inode),
50 .falloc_offset = offset,
51 .falloc_length = len,
Anna Schumaker9a519402015-03-16 14:06:23 -040052 .falloc_bitmask = server->cache_consistency_bitmask,
Anna Schumakerf4ac1672014-11-25 13:18:15 -050053 };
Anna Schumaker9a519402015-03-16 14:06:23 -040054 struct nfs42_falloc_res res = {
55 .falloc_server = server,
56 };
Anna Schumakerf4ac1672014-11-25 13:18:15 -050057 int status;
58
59 msg->rpc_argp = &args;
60 msg->rpc_resp = &res;
61
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +010062 status = nfs4_set_rw_stateid(&args.falloc_stateid, lock->open_context,
63 lock, FMODE_WRITE);
Anna Schumakerf4ac1672014-11-25 13:18:15 -050064 if (status)
65 return status;
66
Anna Schumaker9a519402015-03-16 14:06:23 -040067 res.falloc_fattr = nfs_alloc_fattr();
68 if (!res.falloc_fattr)
69 return -ENOMEM;
70
71 status = nfs4_call_sync(server->client, server, msg,
72 &args.seq_args, &res.seq_res, 0);
73 if (status == 0)
74 status = nfs_post_op_update_inode(inode, res.falloc_fattr);
75
76 kfree(res.falloc_fattr);
77 return status;
Anna Schumakerf4ac1672014-11-25 13:18:15 -050078}
79
80static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
81 loff_t offset, loff_t len)
82{
83 struct nfs_server *server = NFS_SERVER(file_inode(filep));
84 struct nfs4_exception exception = { };
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +010085 struct nfs_lock_context *lock;
Anna Schumakerf4ac1672014-11-25 13:18:15 -050086 int err;
87
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +010088 lock = nfs_get_lock_context(nfs_file_open_context(filep));
89 if (IS_ERR(lock))
90 return PTR_ERR(lock);
91
92 exception.inode = file_inode(filep);
93 exception.state = lock->open_context->state;
94
Anna Schumakerf4ac1672014-11-25 13:18:15 -050095 do {
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +010096 err = _nfs42_proc_fallocate(msg, filep, lock, offset, len);
97 if (err == -ENOTSUPP) {
98 err = -EOPNOTSUPP;
99 break;
100 }
Anna Schumakerf4ac1672014-11-25 13:18:15 -0500101 err = nfs4_handle_exception(server, err, &exception);
102 } while (exception.retry);
103
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100104 nfs_put_lock_context(lock);
Anna Schumakerf4ac1672014-11-25 13:18:15 -0500105 return err;
106}
107
108int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len)
109{
110 struct rpc_message msg = {
111 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE],
112 };
113 struct inode *inode = file_inode(filep);
114 int err;
115
116 if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE))
117 return -EOPNOTSUPP;
118
Al Viro59551022016-01-22 15:40:57 -0500119 inode_lock(inode);
Anna Schumakerf830f7d2015-03-16 14:06:24 -0400120
Anna Schumakerf4ac1672014-11-25 13:18:15 -0500121 err = nfs42_proc_fallocate(&msg, filep, offset, len);
122 if (err == -EOPNOTSUPP)
123 NFS_SERVER(inode)->caps &= ~NFS_CAP_ALLOCATE;
Anna Schumakerf830f7d2015-03-16 14:06:24 -0400124
Al Viro59551022016-01-22 15:40:57 -0500125 inode_unlock(inode);
Anna Schumakerf4ac1672014-11-25 13:18:15 -0500126 return err;
127}
128
Anna Schumaker624bd5b2014-11-25 13:18:16 -0500129int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
130{
131 struct rpc_message msg = {
132 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DEALLOCATE],
133 };
134 struct inode *inode = file_inode(filep);
135 int err;
136
137 if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE))
138 return -EOPNOTSUPP;
139
Al Viro59551022016-01-22 15:40:57 -0500140 inode_lock(inode);
Trond Myklebust1e564d32016-06-25 17:50:53 -0400141 err = nfs_sync_inode(inode);
142 if (err)
143 goto out_unlock;
Anna Schumakerf830f7d2015-03-16 14:06:24 -0400144
Anna Schumaker624bd5b2014-11-25 13:18:16 -0500145 err = nfs42_proc_fallocate(&msg, filep, offset, len);
Anna Schumaker9a519402015-03-16 14:06:23 -0400146 if (err == 0)
147 truncate_pagecache_range(inode, offset, (offset + len) -1);
Anna Schumaker624bd5b2014-11-25 13:18:16 -0500148 if (err == -EOPNOTSUPP)
149 NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE;
Trond Myklebust1e564d32016-06-25 17:50:53 -0400150out_unlock:
Al Viro59551022016-01-22 15:40:57 -0500151 inode_unlock(inode);
Anna Schumaker624bd5b2014-11-25 13:18:16 -0500152 return err;
153}
154
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400155static int handle_async_copy(struct nfs42_copy_res *res,
156 struct nfs_server *server,
157 struct file *src,
158 struct file *dst,
159 nfs4_stateid *src_stateid)
160{
Olga Kornievskaia99f2c552018-11-21 11:24:22 -0500161 struct nfs4_copy_state *copy, *tmp_copy;
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400162 int status = NFS4_OK;
Olga Kornievskaiabc0c9072018-07-09 15:13:32 -0400163 bool found_pending = false;
Olga Kornievskaiae4648aa2018-08-13 15:33:01 -0400164 struct nfs_open_context *ctx = nfs_file_open_context(dst);
Olga Kornievskaiabc0c9072018-07-09 15:13:32 -0400165
Olga Kornievskaia99f2c552018-11-21 11:24:22 -0500166 copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
167 if (!copy)
168 return -ENOMEM;
169
Olga Kornievskaiabc0c9072018-07-09 15:13:32 -0400170 spin_lock(&server->nfs_client->cl_lock);
Olga Kornievskaia99f2c552018-11-21 11:24:22 -0500171 list_for_each_entry(tmp_copy, &server->nfs_client->pending_cb_stateids,
Olga Kornievskaiabc0c9072018-07-09 15:13:32 -0400172 copies) {
Olga Kornievskaia99f2c552018-11-21 11:24:22 -0500173 if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
Olga Kornievskaiabc0c9072018-07-09 15:13:32 -0400174 NFS4_STATEID_SIZE))
175 continue;
176 found_pending = true;
Olga Kornievskaia99f2c552018-11-21 11:24:22 -0500177 list_del(&tmp_copy->copies);
Olga Kornievskaiabc0c9072018-07-09 15:13:32 -0400178 break;
179 }
180 if (found_pending) {
181 spin_unlock(&server->nfs_client->cl_lock);
Olga Kornievskaia99f2c552018-11-21 11:24:22 -0500182 kfree(copy);
183 copy = tmp_copy;
Olga Kornievskaiabc0c9072018-07-09 15:13:32 -0400184 goto out;
185 }
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400186
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400187 memcpy(&copy->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
188 init_completion(&copy->completion);
Olga Kornievskaiae4648aa2018-08-13 15:33:01 -0400189 copy->parent_state = ctx->state;
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400190
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400191 list_add_tail(&copy->copies, &server->ss_copies);
192 spin_unlock(&server->nfs_client->cl_lock);
193
Olga Kornievskaiac975c202018-07-09 15:13:34 -0400194 status = wait_for_completion_interruptible(&copy->completion);
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400195 spin_lock(&server->nfs_client->cl_lock);
196 list_del_init(&copy->copies);
197 spin_unlock(&server->nfs_client->cl_lock);
Olga Kornievskaiac975c202018-07-09 15:13:34 -0400198 if (status == -ERESTARTSYS) {
Olga Kornievskaiae4648aa2018-08-13 15:33:01 -0400199 goto out_cancel;
200 } else if (copy->flags) {
201 status = -EAGAIN;
202 goto out_cancel;
Olga Kornievskaiac975c202018-07-09 15:13:34 -0400203 }
Olga Kornievskaiabc0c9072018-07-09 15:13:32 -0400204out:
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400205 res->write_res.count = copy->count;
206 memcpy(&res->write_res.verifier, &copy->verf, sizeof(copy->verf));
207 status = -copy->error;
208
209 kfree(copy);
210 return status;
Olga Kornievskaiae4648aa2018-08-13 15:33:01 -0400211out_cancel:
212 nfs42_do_offload_cancel_async(dst, &copy->stateid);
213 kfree(copy);
214 return status;
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400215}
216
Olga Kornievskaia6b8d84e2018-07-09 15:13:36 -0400217static int process_copy_commit(struct file *dst, loff_t pos_dst,
218 struct nfs42_copy_res *res)
219{
220 struct nfs_commitres cres;
221 int status = -ENOMEM;
222
223 cres.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
224 if (!cres.verf)
225 goto out;
226
227 status = nfs4_proc_commit(dst, pos_dst, res->write_res.count, &cres);
228 if (status)
229 goto out_free;
230 if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
231 &cres.verf->verifier)) {
232 dprintk("commit verf differs from copy verf\n");
233 status = -EAGAIN;
234 }
235out_free:
236 kfree(cres.verf);
237out:
238 return status;
239}
240
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500241static ssize_t _nfs42_proc_copy(struct file *src,
Anna Schumaker2e724482013-05-21 16:53:03 -0400242 struct nfs_lock_context *src_lock,
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500243 struct file *dst,
Anna Schumaker2e724482013-05-21 16:53:03 -0400244 struct nfs_lock_context *dst_lock,
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500245 struct nfs42_copy_args *args,
Olga Kornievskaia1d38f3f2019-06-04 11:54:18 -0400246 struct nfs42_copy_res *res,
247 struct nl4_server *nss,
248 nfs4_stateid *cnr_stateid)
Anna Schumaker2e724482013-05-21 16:53:03 -0400249{
Anna Schumaker2e724482013-05-21 16:53:03 -0400250 struct rpc_message msg = {
251 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500252 .rpc_argp = args,
253 .rpc_resp = res,
Anna Schumaker2e724482013-05-21 16:53:03 -0400254 };
255 struct inode *dst_inode = file_inode(dst);
256 struct nfs_server *server = NFS_SERVER(dst_inode);
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500257 loff_t pos_src = args->src_pos;
258 loff_t pos_dst = args->dst_pos;
259 size_t count = args->count;
Olga Kornievskaia1ee48bd2017-07-06 09:43:02 -0400260 ssize_t status;
Anna Schumaker2e724482013-05-21 16:53:03 -0400261
Olga Kornievskaia1d38f3f2019-06-04 11:54:18 -0400262 if (nss) {
263 args->cp_src = nss;
264 nfs4_stateid_copy(&args->src_stateid, cnr_stateid);
265 } else {
266 status = nfs4_set_rw_stateid(&args->src_stateid,
267 src_lock->open_context, src_lock, FMODE_READ);
268 if (status)
269 return status;
270 }
Trond Myklebust837bb1d2016-06-25 18:12:03 -0400271 status = nfs_filemap_write_and_wait_range(file_inode(src)->i_mapping,
272 pos_src, pos_src + (loff_t)count - 1);
273 if (status)
274 return status;
275
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500276 status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context,
Anna Schumaker2e724482013-05-21 16:53:03 -0400277 dst_lock, FMODE_WRITE);
278 if (status)
279 return status;
280
Trond Myklebust837bb1d2016-06-25 18:12:03 -0400281 status = nfs_sync_inode(dst_inode);
282 if (status)
283 return status;
284
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400285 res->commit_res.verf = NULL;
286 if (args->sync) {
287 res->commit_res.verf =
288 kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
289 if (!res->commit_res.verf)
290 return -ENOMEM;
291 }
Olga Kornievskaiae4648aa2018-08-13 15:33:01 -0400292 set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
293 &dst_lock->open_context->state->flags);
294
Anna Schumaker2e724482013-05-21 16:53:03 -0400295 status = nfs4_call_sync(server->client, server, &msg,
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500296 &args->seq_args, &res->seq_res, 0);
Anna Schumaker2e724482013-05-21 16:53:03 -0400297 if (status == -ENOTSUPP)
298 server->caps &= ~NFS_CAP_COPY;
299 if (status)
Olga Kornievskaiae0926932017-05-08 18:02:24 -0400300 goto out;
Anna Schumaker2e724482013-05-21 16:53:03 -0400301
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400302 if (args->sync &&
303 nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
Olga Kornievskaiae0926932017-05-08 18:02:24 -0400304 &res->commit_res.verf->verifier)) {
305 status = -EAGAIN;
306 goto out;
Anna Schumaker2e724482013-05-21 16:53:03 -0400307 }
308
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400309 if (!res->synchronous) {
310 status = handle_async_copy(res, server, src, dst,
311 &args->src_stateid);
312 if (status)
313 return status;
314 }
315
Olga Kornievskaia6b8d84e2018-07-09 15:13:36 -0400316 if ((!res->synchronous || !args->sync) &&
317 res->write_res.verifier.committed != NFS_FILE_SYNC) {
318 status = process_copy_commit(dst, pos_dst, res);
319 if (status)
320 return status;
321 }
322
Anna Schumaker2e724482013-05-21 16:53:03 -0400323 truncate_pagecache_range(dst_inode, pos_dst,
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500324 pos_dst + res->write_res.count);
Anna Schumaker2e724482013-05-21 16:53:03 -0400325
Olga Kornievskaiae0926932017-05-08 18:02:24 -0400326 status = res->write_res.count;
327out:
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400328 if (args->sync)
329 kfree(res->commit_res.verf);
Olga Kornievskaiae0926932017-05-08 18:02:24 -0400330 return status;
Anna Schumaker2e724482013-05-21 16:53:03 -0400331}
332
333ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
Olga Kornievskaia1d38f3f2019-06-04 11:54:18 -0400334 struct file *dst, loff_t pos_dst, size_t count,
335 struct nl4_server *nss,
336 nfs4_stateid *cnr_stateid)
Anna Schumaker2e724482013-05-21 16:53:03 -0400337{
338 struct nfs_server *server = NFS_SERVER(file_inode(dst));
339 struct nfs_lock_context *src_lock;
340 struct nfs_lock_context *dst_lock;
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500341 struct nfs42_copy_args args = {
342 .src_fh = NFS_FH(file_inode(src)),
343 .src_pos = pos_src,
344 .dst_fh = NFS_FH(file_inode(dst)),
345 .dst_pos = pos_dst,
346 .count = count,
Olga Kornievskaia62164f32018-07-09 15:13:31 -0400347 .sync = false,
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500348 };
349 struct nfs42_copy_res res;
350 struct nfs4_exception src_exception = {
351 .inode = file_inode(src),
352 .stateid = &args.src_stateid,
353 };
354 struct nfs4_exception dst_exception = {
355 .inode = file_inode(dst),
356 .stateid = &args.dst_stateid,
357 };
Anna Schumaker2e724482013-05-21 16:53:03 -0400358 ssize_t err, err2;
359
Anna Schumaker2e724482013-05-21 16:53:03 -0400360 src_lock = nfs_get_lock_context(nfs_file_open_context(src));
361 if (IS_ERR(src_lock))
362 return PTR_ERR(src_lock);
363
Anna Schumaker2e724482013-05-21 16:53:03 -0400364 src_exception.state = src_lock->open_context->state;
365
366 dst_lock = nfs_get_lock_context(nfs_file_open_context(dst));
367 if (IS_ERR(dst_lock)) {
368 err = PTR_ERR(dst_lock);
369 goto out_put_src_lock;
370 }
371
Anna Schumaker2e724482013-05-21 16:53:03 -0400372 dst_exception.state = dst_lock->open_context->state;
373
374 do {
Linus Torvaldsea8ea732016-05-26 10:33:33 -0700375 inode_lock(file_inode(dst));
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500376 err = _nfs42_proc_copy(src, src_lock,
377 dst, dst_lock,
Olga Kornievskaia1d38f3f2019-06-04 11:54:18 -0400378 &args, &res,
379 nss, cnr_stateid);
Linus Torvaldsea8ea732016-05-26 10:33:33 -0700380 inode_unlock(file_inode(dst));
Anna Schumaker2e724482013-05-21 16:53:03 -0400381
Trond Myklebust9d8cacb2017-02-17 18:42:32 -0500382 if (err >= 0)
383 break;
Anna Schumaker2e724482013-05-21 16:53:03 -0400384 if (err == -ENOTSUPP) {
385 err = -EOPNOTSUPP;
386 break;
Olga Kornievskaia539f57b2018-07-09 15:13:35 -0400387 } else if (err == -EAGAIN) {
388 dst_exception.retry = 1;
389 continue;
390 } else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) {
391 args.sync = true;
Olga Kornievskaiae0926932017-05-08 18:02:24 -0400392 dst_exception.retry = 1;
393 continue;
Anna Schumaker2e724482013-05-21 16:53:03 -0400394 }
395
396 err2 = nfs4_handle_exception(server, err, &src_exception);
397 err = nfs4_handle_exception(server, err, &dst_exception);
398 if (!err)
399 err = err2;
400 } while (src_exception.retry || dst_exception.retry);
401
402 nfs_put_lock_context(dst_lock);
403out_put_src_lock:
404 nfs_put_lock_context(src_lock);
405 return err;
406}
407
Olga Kornievskaiac975c202018-07-09 15:13:34 -0400408struct nfs42_offloadcancel_data {
409 struct nfs_server *seq_server;
410 struct nfs42_offload_status_args args;
411 struct nfs42_offload_status_res res;
412};
413
414static void nfs42_offload_cancel_prepare(struct rpc_task *task, void *calldata)
415{
416 struct nfs42_offloadcancel_data *data = calldata;
417
418 nfs4_setup_sequence(data->seq_server->nfs_client,
419 &data->args.osa_seq_args,
420 &data->res.osr_seq_res, task);
421}
422
423static void nfs42_offload_cancel_done(struct rpc_task *task, void *calldata)
424{
425 struct nfs42_offloadcancel_data *data = calldata;
426
427 nfs41_sequence_done(task, &data->res.osr_seq_res);
428 if (task->tk_status &&
429 nfs4_async_handle_error(task, data->seq_server, NULL,
430 NULL) == -EAGAIN)
431 rpc_restart_call_prepare(task);
432}
433
434static void nfs42_free_offloadcancel_data(void *data)
435{
436 kfree(data);
437}
438
439static const struct rpc_call_ops nfs42_offload_cancel_ops = {
440 .rpc_call_prepare = nfs42_offload_cancel_prepare,
441 .rpc_call_done = nfs42_offload_cancel_done,
442 .rpc_release = nfs42_free_offloadcancel_data,
443};
444
445static int nfs42_do_offload_cancel_async(struct file *dst,
446 nfs4_stateid *stateid)
447{
448 struct nfs_server *dst_server = NFS_SERVER(file_inode(dst));
449 struct nfs42_offloadcancel_data *data = NULL;
450 struct nfs_open_context *ctx = nfs_file_open_context(dst);
451 struct rpc_task *task;
452 struct rpc_message msg = {
453 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OFFLOAD_CANCEL],
454 .rpc_cred = ctx->cred,
455 };
456 struct rpc_task_setup task_setup_data = {
457 .rpc_client = dst_server->client,
458 .rpc_message = &msg,
459 .callback_ops = &nfs42_offload_cancel_ops,
460 .workqueue = nfsiod_workqueue,
461 .flags = RPC_TASK_ASYNC,
462 };
463 int status;
464
465 if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL))
466 return -EOPNOTSUPP;
467
468 data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_NOFS);
469 if (data == NULL)
470 return -ENOMEM;
471
472 data->seq_server = dst_server;
473 data->args.osa_src_fh = NFS_FH(file_inode(dst));
474 memcpy(&data->args.osa_stateid, stateid,
475 sizeof(data->args.osa_stateid));
476 msg.rpc_argp = &data->args;
477 msg.rpc_resp = &data->res;
478 task_setup_data.callback_data = data;
479 nfs4_init_sequence(&data->args.osa_seq_args, &data->res.osr_seq_res,
480 1, 0);
481 task = rpc_run_task(&task_setup_data);
482 if (IS_ERR(task))
483 return PTR_ERR(task);
484 status = rpc_wait_for_completion_task(task);
485 if (status == -ENOTSUPP)
486 dst_server->caps &= ~NFS_CAP_OFFLOAD_CANCEL;
487 rpc_put_task(task);
488 return status;
489}
490
Olga Kornievskaia04915672019-06-04 16:14:30 -0400491int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
492 struct nfs42_copy_notify_args *args,
493 struct nfs42_copy_notify_res *res)
494{
495 struct nfs_server *src_server = NFS_SERVER(file_inode(src));
496 struct rpc_message msg = {
497 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY_NOTIFY],
498 .rpc_argp = args,
499 .rpc_resp = res,
500 };
501 int status;
502 struct nfs_open_context *ctx;
503 struct nfs_lock_context *l_ctx;
504
505 ctx = get_nfs_open_context(nfs_file_open_context(src));
506 l_ctx = nfs_get_lock_context(ctx);
507 if (IS_ERR(l_ctx))
508 return PTR_ERR(l_ctx);
509
510 status = nfs4_set_rw_stateid(&args->cna_src_stateid, ctx, l_ctx,
511 FMODE_READ);
512 nfs_put_lock_context(l_ctx);
513 if (status)
514 return status;
515
516 status = nfs4_call_sync(src_server->client, src_server, &msg,
517 &args->cna_seq_args, &res->cnr_seq_res, 0);
518 if (status == -ENOTSUPP)
519 src_server->caps &= ~NFS_CAP_COPY_NOTIFY;
520
521 put_nfs_open_context(nfs_file_open_context(src));
522 return status;
523}
524
525int nfs42_proc_copy_notify(struct file *src, struct file *dst,
526 struct nfs42_copy_notify_res *res)
527{
528 struct nfs_server *src_server = NFS_SERVER(file_inode(src));
529 struct nfs42_copy_notify_args *args;
530 struct nfs4_exception exception = {
531 .inode = file_inode(src),
532 };
533 int status;
534
535 if (!(src_server->caps & NFS_CAP_COPY_NOTIFY))
536 return -EOPNOTSUPP;
537
538 args = kzalloc(sizeof(struct nfs42_copy_notify_args), GFP_NOFS);
539 if (args == NULL)
540 return -ENOMEM;
541
542 args->cna_src_fh = NFS_FH(file_inode(src)),
543 args->cna_dst.nl4_type = NL4_NETADDR;
544 nfs42_set_netaddr(dst, &args->cna_dst.u.nl4_addr);
545 exception.stateid = &args->cna_src_stateid;
546
547 do {
548 status = _nfs42_proc_copy_notify(src, dst, args, res);
549 if (status == -ENOTSUPP) {
550 status = -EOPNOTSUPP;
551 goto out;
552 }
553 status = nfs4_handle_exception(src_server, status, &exception);
554 } while (exception.retry);
555
556out:
557 kfree(args);
558 return status;
559}
560
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100561static loff_t _nfs42_proc_llseek(struct file *filep,
562 struct nfs_lock_context *lock, loff_t offset, int whence)
Anna Schumaker1c6dcbe2014-09-26 13:58:48 -0400563{
564 struct inode *inode = file_inode(filep);
565 struct nfs42_seek_args args = {
566 .sa_fh = NFS_FH(inode),
567 .sa_offset = offset,
568 .sa_what = (whence == SEEK_HOLE) ?
569 NFS4_CONTENT_HOLE : NFS4_CONTENT_DATA,
570 };
571 struct nfs42_seek_res res;
572 struct rpc_message msg = {
573 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEEK],
574 .rpc_argp = &args,
575 .rpc_resp = &res,
576 };
577 struct nfs_server *server = NFS_SERVER(inode);
578 int status;
579
Anna Schumaker878ffa92014-10-23 14:00:54 -0400580 if (!nfs_server_capable(inode, NFS_CAP_SEEK))
Anna Schumaker1c6dcbe2014-09-26 13:58:48 -0400581 return -ENOTSUPP;
582
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100583 status = nfs4_set_rw_stateid(&args.sa_stateid, lock->open_context,
584 lock, FMODE_READ);
Anna Schumaker1c6dcbe2014-09-26 13:58:48 -0400585 if (status)
586 return status;
587
Trond Myklebuste95fc4a2016-06-25 17:57:39 -0400588 status = nfs_filemap_write_and_wait_range(inode->i_mapping,
589 offset, LLONG_MAX);
590 if (status)
591 return status;
592
Anna Schumaker1c6dcbe2014-09-26 13:58:48 -0400593 status = nfs4_call_sync(server->client, server, &msg,
594 &args.seq_args, &res.seq_res, 0);
595 if (status == -ENOTSUPP)
596 server->caps &= ~NFS_CAP_SEEK;
597 if (status)
598 return status;
599
600 return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
601}
Trond Myklebustbe3a5d22015-06-23 19:51:55 +0800602
J. Bruce Fieldsbdcc2cd2015-07-23 11:08:43 -0400603loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
604{
605 struct nfs_server *server = NFS_SERVER(file_inode(filep));
606 struct nfs4_exception exception = { };
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100607 struct nfs_lock_context *lock;
J. Bruce Fields306a5542015-09-16 17:21:27 -0400608 loff_t err;
J. Bruce Fieldsbdcc2cd2015-07-23 11:08:43 -0400609
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100610 lock = nfs_get_lock_context(nfs_file_open_context(filep));
611 if (IS_ERR(lock))
612 return PTR_ERR(lock);
613
614 exception.inode = file_inode(filep);
615 exception.state = lock->open_context->state;
616
J. Bruce Fieldsbdcc2cd2015-07-23 11:08:43 -0400617 do {
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100618 err = _nfs42_proc_llseek(filep, lock, offset, whence);
J. Bruce Fields306a5542015-09-16 17:21:27 -0400619 if (err >= 0)
620 break;
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100621 if (err == -ENOTSUPP) {
622 err = -EOPNOTSUPP;
623 break;
624 }
J. Bruce Fieldsbdcc2cd2015-07-23 11:08:43 -0400625 err = nfs4_handle_exception(server, err, &exception);
626 } while (exception.retry);
627
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100628 nfs_put_lock_context(lock);
J. Bruce Fieldsbdcc2cd2015-07-23 11:08:43 -0400629 return err;
630}
631
632
Peng Tao1b4a4bd2015-06-23 19:51:56 +0800633static void
634nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
635{
636 struct nfs42_layoutstat_data *data = calldata;
Trond Myklebust9a0fe862016-08-19 15:33:12 -0400637 struct inode *inode = data->inode;
638 struct nfs_server *server = NFS_SERVER(inode);
639 struct pnfs_layout_hdr *lo;
Peng Tao1b4a4bd2015-06-23 19:51:56 +0800640
Trond Myklebust9a0fe862016-08-19 15:33:12 -0400641 spin_lock(&inode->i_lock);
642 lo = NFS_I(inode)->layout;
643 if (!pnfs_layout_is_valid(lo)) {
644 spin_unlock(&inode->i_lock);
645 rpc_exit(task, 0);
646 return;
647 }
648 nfs4_stateid_copy(&data->args.stateid, &lo->plh_stateid);
649 spin_unlock(&inode->i_lock);
Anna Schumaker6de7e122017-01-09 16:51:52 -0500650 nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
651 &data->res.seq_res, task);
Peng Tao1b4a4bd2015-06-23 19:51:56 +0800652}
653
654static void
655nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
656{
657 struct nfs42_layoutstat_data *data = calldata;
Peng Tao68d264c2015-12-06 20:55:09 -0500658 struct inode *inode = data->inode;
659 struct pnfs_layout_hdr *lo;
Peng Tao1b4a4bd2015-06-23 19:51:56 +0800660
661 if (!nfs4_sequence_done(task, &data->res.seq_res))
662 return;
663
Trond Myklebust6c5a0d82015-06-27 11:45:46 -0400664 switch (task->tk_status) {
665 case 0:
666 break;
Trond Myklebustcf61eb22018-05-29 22:06:08 -0400667 case -NFS4ERR_BADHANDLE:
668 case -ESTALE:
669 pnfs_destroy_layout(NFS_I(inode));
670 break;
Peng Tao68d264c2015-12-06 20:55:09 -0500671 case -NFS4ERR_EXPIRED:
Trond Myklebust206b3bb2016-08-05 12:16:19 -0400672 case -NFS4ERR_ADMIN_REVOKED:
673 case -NFS4ERR_DELEG_REVOKED:
Peng Tao68d264c2015-12-06 20:55:09 -0500674 case -NFS4ERR_STALE_STATEID:
Peng Tao68d264c2015-12-06 20:55:09 -0500675 case -NFS4ERR_BAD_STATEID:
676 spin_lock(&inode->i_lock);
677 lo = NFS_I(inode)->layout;
Trond Myklebust9a0fe862016-08-19 15:33:12 -0400678 if (pnfs_layout_is_valid(lo) &&
679 nfs4_stateid_match(&data->args.stateid,
Peng Tao68d264c2015-12-06 20:55:09 -0500680 &lo->plh_stateid)) {
681 LIST_HEAD(head);
682
683 /*
684 * Mark the bad layout state as invalid, then retry
685 * with the current stateid.
686 */
Trond Myklebust5f46be02016-07-22 11:25:27 -0400687 pnfs_mark_layout_stateid_invalid(lo, &head);
Peng Tao68d264c2015-12-06 20:55:09 -0500688 spin_unlock(&inode->i_lock);
689 pnfs_free_lseg_list(&head);
Trond Myklebust1f18b822017-04-29 10:10:17 -0400690 nfs_commit_inode(inode, 0);
Peng Tao68d264c2015-12-06 20:55:09 -0500691 } else
692 spin_unlock(&inode->i_lock);
693 break;
Trond Myklebust9a0fe862016-08-19 15:33:12 -0400694 case -NFS4ERR_OLD_STATEID:
695 spin_lock(&inode->i_lock);
696 lo = NFS_I(inode)->layout;
697 if (pnfs_layout_is_valid(lo) &&
698 nfs4_stateid_match_other(&data->args.stateid,
699 &lo->plh_stateid)) {
700 /* Do we need to delay before resending? */
701 if (!nfs4_stateid_is_newer(&lo->plh_stateid,
702 &data->args.stateid))
703 rpc_delay(task, HZ);
704 rpc_restart_call_prepare(task);
705 }
706 spin_unlock(&inode->i_lock);
707 break;
Trond Myklebust6c5a0d82015-06-27 11:45:46 -0400708 case -ENOTSUPP:
709 case -EOPNOTSUPP:
Peng Tao68d264c2015-12-06 20:55:09 -0500710 NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
Trond Myklebust6c5a0d82015-06-27 11:45:46 -0400711 }
Peng Tao1b4a4bd2015-06-23 19:51:56 +0800712}
713
714static void
715nfs42_layoutstat_release(void *calldata)
716{
717 struct nfs42_layoutstat_data *data = calldata;
Trond Myklebust422c93c2016-10-06 17:53:20 -0400718 struct nfs42_layoutstat_devinfo *devinfo = data->args.devinfo;
719 int i;
Peng Tao87334082015-06-23 19:51:57 +0800720
Trond Myklebust422c93c2016-10-06 17:53:20 -0400721 for (i = 0; i < data->args.num_dev; i++) {
722 if (devinfo[i].ld_private.ops && devinfo[i].ld_private.ops->free)
723 devinfo[i].ld_private.ops->free(&devinfo[i].ld_private);
724 }
Peng Tao1b4a4bd2015-06-23 19:51:56 +0800725
726 pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout);
Peng Tao1bfe3b22015-06-23 19:52:03 +0800727 smp_mb__before_atomic();
728 clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags);
729 smp_mb__after_atomic();
Peng Tao1b4a4bd2015-06-23 19:51:56 +0800730 nfs_iput_and_deactive(data->inode);
731 kfree(data->args.devinfo);
732 kfree(data);
733}
734
Trond Myklebustbe3a5d22015-06-23 19:51:55 +0800735static const struct rpc_call_ops nfs42_layoutstat_ops = {
Peng Tao1b4a4bd2015-06-23 19:51:56 +0800736 .rpc_call_prepare = nfs42_layoutstat_prepare,
737 .rpc_call_done = nfs42_layoutstat_done,
738 .rpc_release = nfs42_layoutstat_release,
Trond Myklebustbe3a5d22015-06-23 19:51:55 +0800739};
740
741int nfs42_proc_layoutstats_generic(struct nfs_server *server,
742 struct nfs42_layoutstat_data *data)
743{
744 struct rpc_message msg = {
745 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTSTATS],
746 .rpc_argp = &data->args,
747 .rpc_resp = &data->res,
748 };
749 struct rpc_task_setup task_setup = {
750 .rpc_client = server->client,
751 .rpc_message = &msg,
752 .callback_ops = &nfs42_layoutstat_ops,
753 .callback_data = data,
754 .flags = RPC_TASK_ASYNC,
755 };
756 struct rpc_task *task;
757
Peng Tao1b4a4bd2015-06-23 19:51:56 +0800758 data->inode = nfs_igrab_and_active(data->args.inode);
759 if (!data->inode) {
760 nfs42_layoutstat_release(data);
761 return -EAGAIN;
762 }
Anna Schumakerfba83f32018-05-04 16:22:50 -0400763 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0);
Trond Myklebustbe3a5d22015-06-23 19:51:55 +0800764 task = rpc_run_task(&task_setup);
765 if (IS_ERR(task))
766 return PTR_ERR(task);
Jeff Layton3f807e52016-10-04 00:07:43 -0400767 rpc_put_task(task);
Trond Myklebustbe3a5d22015-06-23 19:51:55 +0800768 return 0;
769}
Peng Taoe5341f32015-09-26 02:24:35 +0800770
Trond Myklebust3eb86092019-02-08 10:31:05 -0500771static struct nfs42_layouterror_data *
772nfs42_alloc_layouterror_data(struct pnfs_layout_segment *lseg, gfp_t gfp_flags)
773{
774 struct nfs42_layouterror_data *data;
775 struct inode *inode = lseg->pls_layout->plh_inode;
776
777 data = kzalloc(sizeof(*data), gfp_flags);
778 if (data) {
779 data->args.inode = data->inode = nfs_igrab_and_active(inode);
780 if (data->inode) {
781 data->lseg = pnfs_get_lseg(lseg);
782 if (data->lseg)
783 return data;
784 nfs_iput_and_deactive(data->inode);
785 }
786 kfree(data);
787 }
788 return NULL;
789}
790
791static void
792nfs42_free_layouterror_data(struct nfs42_layouterror_data *data)
793{
794 pnfs_put_lseg(data->lseg);
795 nfs_iput_and_deactive(data->inode);
796 kfree(data);
797}
798
799static void
800nfs42_layouterror_prepare(struct rpc_task *task, void *calldata)
801{
802 struct nfs42_layouterror_data *data = calldata;
803 struct inode *inode = data->inode;
804 struct nfs_server *server = NFS_SERVER(inode);
805 struct pnfs_layout_hdr *lo = data->lseg->pls_layout;
806 unsigned i;
807
808 spin_lock(&inode->i_lock);
809 if (!pnfs_layout_is_valid(lo)) {
810 spin_unlock(&inode->i_lock);
811 rpc_exit(task, 0);
812 return;
813 }
814 for (i = 0; i < data->args.num_errors; i++)
815 nfs4_stateid_copy(&data->args.errors[i].stateid,
816 &lo->plh_stateid);
817 spin_unlock(&inode->i_lock);
818 nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
819 &data->res.seq_res, task);
820}
821
822static void
823nfs42_layouterror_done(struct rpc_task *task, void *calldata)
824{
825 struct nfs42_layouterror_data *data = calldata;
826 struct inode *inode = data->inode;
827 struct pnfs_layout_hdr *lo = data->lseg->pls_layout;
828
829 if (!nfs4_sequence_done(task, &data->res.seq_res))
830 return;
831
832 switch (task->tk_status) {
833 case 0:
834 break;
835 case -NFS4ERR_BADHANDLE:
836 case -ESTALE:
837 pnfs_destroy_layout(NFS_I(inode));
838 break;
839 case -NFS4ERR_EXPIRED:
840 case -NFS4ERR_ADMIN_REVOKED:
841 case -NFS4ERR_DELEG_REVOKED:
842 case -NFS4ERR_STALE_STATEID:
843 case -NFS4ERR_BAD_STATEID:
844 spin_lock(&inode->i_lock);
845 if (pnfs_layout_is_valid(lo) &&
846 nfs4_stateid_match(&data->args.errors[0].stateid,
847 &lo->plh_stateid)) {
848 LIST_HEAD(head);
849
850 /*
851 * Mark the bad layout state as invalid, then retry
852 * with the current stateid.
853 */
854 pnfs_mark_layout_stateid_invalid(lo, &head);
855 spin_unlock(&inode->i_lock);
856 pnfs_free_lseg_list(&head);
857 nfs_commit_inode(inode, 0);
858 } else
859 spin_unlock(&inode->i_lock);
860 break;
861 case -NFS4ERR_OLD_STATEID:
862 spin_lock(&inode->i_lock);
863 if (pnfs_layout_is_valid(lo) &&
864 nfs4_stateid_match_other(&data->args.errors[0].stateid,
865 &lo->plh_stateid)) {
866 /* Do we need to delay before resending? */
867 if (!nfs4_stateid_is_newer(&lo->plh_stateid,
868 &data->args.errors[0].stateid))
869 rpc_delay(task, HZ);
870 rpc_restart_call_prepare(task);
871 }
872 spin_unlock(&inode->i_lock);
873 break;
874 case -ENOTSUPP:
875 case -EOPNOTSUPP:
876 NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTERROR;
877 }
878}
879
880static void
881nfs42_layouterror_release(void *calldata)
882{
883 struct nfs42_layouterror_data *data = calldata;
884
885 nfs42_free_layouterror_data(data);
886}
887
888static const struct rpc_call_ops nfs42_layouterror_ops = {
889 .rpc_call_prepare = nfs42_layouterror_prepare,
890 .rpc_call_done = nfs42_layouterror_done,
891 .rpc_release = nfs42_layouterror_release,
892};
893
894int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg,
895 const struct nfs42_layout_error *errors, size_t n)
896{
897 struct inode *inode = lseg->pls_layout->plh_inode;
898 struct nfs42_layouterror_data *data;
899 struct rpc_task *task;
900 struct rpc_message msg = {
901 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTERROR],
902 };
903 struct rpc_task_setup task_setup = {
904 .rpc_message = &msg,
905 .callback_ops = &nfs42_layouterror_ops,
906 .flags = RPC_TASK_ASYNC,
907 };
908 unsigned int i;
909
910 if (!nfs_server_capable(inode, NFS_CAP_LAYOUTERROR))
911 return -EOPNOTSUPP;
912 if (n > NFS42_LAYOUTERROR_MAX)
913 return -EINVAL;
914 data = nfs42_alloc_layouterror_data(lseg, GFP_NOFS);
915 if (!data)
916 return -ENOMEM;
917 for (i = 0; i < n; i++) {
918 data->args.errors[i] = errors[i];
919 data->args.num_errors++;
920 data->res.num_errors++;
921 }
922 msg.rpc_argp = &data->args;
923 msg.rpc_resp = &data->res;
924 task_setup.callback_data = data;
925 task_setup.rpc_client = NFS_SERVER(inode)->client;
926 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0);
927 task = rpc_run_task(&task_setup);
928 if (IS_ERR(task))
929 return PTR_ERR(task);
930 rpc_put_task(task);
931 return 0;
932}
933EXPORT_SYMBOL_GPL(nfs42_proc_layouterror);
934
Peng Taoe5341f32015-09-26 02:24:35 +0800935static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100936 struct file *dst_f, struct nfs_lock_context *src_lock,
937 struct nfs_lock_context *dst_lock, loff_t src_offset,
938 loff_t dst_offset, loff_t count)
Peng Taoe5341f32015-09-26 02:24:35 +0800939{
940 struct inode *src_inode = file_inode(src_f);
941 struct inode *dst_inode = file_inode(dst_f);
942 struct nfs_server *server = NFS_SERVER(dst_inode);
943 struct nfs42_clone_args args = {
944 .src_fh = NFS_FH(src_inode),
945 .dst_fh = NFS_FH(dst_inode),
946 .src_offset = src_offset,
947 .dst_offset = dst_offset,
Christoph Hellwig9494b2c2015-11-13 09:38:45 +0100948 .count = count,
Peng Taoe5341f32015-09-26 02:24:35 +0800949 .dst_bitmask = server->cache_consistency_bitmask,
950 };
951 struct nfs42_clone_res res = {
952 .server = server,
953 };
954 int status;
955
956 msg->rpc_argp = &args;
957 msg->rpc_resp = &res;
958
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100959 status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
960 src_lock, FMODE_READ);
Peng Taoe5341f32015-09-26 02:24:35 +0800961 if (status)
962 return status;
963
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100964 status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
965 dst_lock, FMODE_WRITE);
Peng Taoe5341f32015-09-26 02:24:35 +0800966 if (status)
967 return status;
968
969 res.dst_fattr = nfs_alloc_fattr();
970 if (!res.dst_fattr)
971 return -ENOMEM;
972
973 status = nfs4_call_sync(server->client, server, msg,
974 &args.seq_args, &res.seq_res, 0);
975 if (status == 0)
976 status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
977
978 kfree(res.dst_fattr);
979 return status;
980}
981
982int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
983 loff_t src_offset, loff_t dst_offset, loff_t count)
984{
985 struct rpc_message msg = {
986 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE],
987 };
988 struct inode *inode = file_inode(src_f);
989 struct nfs_server *server = NFS_SERVER(file_inode(src_f));
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100990 struct nfs_lock_context *src_lock;
991 struct nfs_lock_context *dst_lock;
992 struct nfs4_exception src_exception = { };
993 struct nfs4_exception dst_exception = { };
994 int err, err2;
Peng Taoe5341f32015-09-26 02:24:35 +0800995
996 if (!nfs_server_capable(inode, NFS_CAP_CLONE))
997 return -EOPNOTSUPP;
998
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +0100999 src_lock = nfs_get_lock_context(nfs_file_open_context(src_f));
1000 if (IS_ERR(src_lock))
1001 return PTR_ERR(src_lock);
1002
1003 src_exception.inode = file_inode(src_f);
1004 src_exception.state = src_lock->open_context->state;
1005
1006 dst_lock = nfs_get_lock_context(nfs_file_open_context(dst_f));
1007 if (IS_ERR(dst_lock)) {
1008 err = PTR_ERR(dst_lock);
1009 goto out_put_src_lock;
1010 }
1011
1012 dst_exception.inode = file_inode(dst_f);
1013 dst_exception.state = dst_lock->open_context->state;
1014
Peng Taoe5341f32015-09-26 02:24:35 +08001015 do {
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +01001016 err = _nfs42_proc_clone(&msg, src_f, dst_f, src_lock, dst_lock,
1017 src_offset, dst_offset, count);
Peng Taoe5341f32015-09-26 02:24:35 +08001018 if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
1019 NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +01001020 err = -EOPNOTSUPP;
1021 break;
Peng Taoe5341f32015-09-26 02:24:35 +08001022 }
Peng Taoe5341f32015-09-26 02:24:35 +08001023
Christoph Hellwig4bdf87e2016-02-17 15:48:28 +01001024 err2 = nfs4_handle_exception(server, err, &src_exception);
1025 err = nfs4_handle_exception(server, err, &dst_exception);
1026 if (!err)
1027 err = err2;
1028 } while (src_exception.retry || dst_exception.retry);
1029
1030 nfs_put_lock_context(dst_lock);
1031out_put_src_lock:
1032 nfs_put_lock_context(src_lock);
Peng Taoe5341f32015-09-26 02:24:35 +08001033 return err;
Peng Taoe5341f32015-09-26 02:24:35 +08001034}