1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (c) 2014 Anna Schumaker <Anna.Schumaker@Netapp.com>
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun #include <linux/fs.h>
6*4882a593Smuzhiyun #include <linux/sunrpc/addr.h>
7*4882a593Smuzhiyun #include <linux/sunrpc/sched.h>
8*4882a593Smuzhiyun #include <linux/nfs.h>
9*4882a593Smuzhiyun #include <linux/nfs3.h>
10*4882a593Smuzhiyun #include <linux/nfs4.h>
11*4882a593Smuzhiyun #include <linux/nfs_xdr.h>
12*4882a593Smuzhiyun #include <linux/nfs_fs.h>
13*4882a593Smuzhiyun #include "nfs4_fs.h"
14*4882a593Smuzhiyun #include "nfs42.h"
15*4882a593Smuzhiyun #include "iostat.h"
16*4882a593Smuzhiyun #include "pnfs.h"
17*4882a593Smuzhiyun #include "nfs4session.h"
18*4882a593Smuzhiyun #include "internal.h"
19*4882a593Smuzhiyun #include "delegation.h"
20*4882a593Smuzhiyun #include "nfs4trace.h"
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #define NFSDBG_FACILITY NFSDBG_PROC
23*4882a593Smuzhiyun static int nfs42_do_offload_cancel_async(struct file *dst, nfs4_stateid *std);
24*4882a593Smuzhiyun
nfs42_set_netaddr(struct file * filep,struct nfs42_netaddr * naddr)25*4882a593Smuzhiyun static void nfs42_set_netaddr(struct file *filep, struct nfs42_netaddr *naddr)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun struct nfs_client *clp = (NFS_SERVER(file_inode(filep)))->nfs_client;
28*4882a593Smuzhiyun unsigned short port = 2049;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun rcu_read_lock();
31*4882a593Smuzhiyun naddr->netid_len = scnprintf(naddr->netid,
32*4882a593Smuzhiyun sizeof(naddr->netid), "%s",
33*4882a593Smuzhiyun rpc_peeraddr2str(clp->cl_rpcclient,
34*4882a593Smuzhiyun RPC_DISPLAY_NETID));
35*4882a593Smuzhiyun naddr->addr_len = scnprintf(naddr->addr,
36*4882a593Smuzhiyun sizeof(naddr->addr),
37*4882a593Smuzhiyun "%s.%u.%u",
38*4882a593Smuzhiyun rpc_peeraddr2str(clp->cl_rpcclient,
39*4882a593Smuzhiyun RPC_DISPLAY_ADDR),
40*4882a593Smuzhiyun port >> 8, port & 255);
41*4882a593Smuzhiyun rcu_read_unlock();
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun
_nfs42_proc_fallocate(struct rpc_message * msg,struct file * filep,struct nfs_lock_context * lock,loff_t offset,loff_t len)44*4882a593Smuzhiyun static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
45*4882a593Smuzhiyun struct nfs_lock_context *lock, loff_t offset, loff_t len)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun struct inode *inode = file_inode(filep);
48*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(inode);
49*4882a593Smuzhiyun u32 bitmask[3];
50*4882a593Smuzhiyun struct nfs42_falloc_args args = {
51*4882a593Smuzhiyun .falloc_fh = NFS_FH(inode),
52*4882a593Smuzhiyun .falloc_offset = offset,
53*4882a593Smuzhiyun .falloc_length = len,
54*4882a593Smuzhiyun .falloc_bitmask = bitmask,
55*4882a593Smuzhiyun };
56*4882a593Smuzhiyun struct nfs42_falloc_res res = {
57*4882a593Smuzhiyun .falloc_server = server,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun int status;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun msg->rpc_argp = &args;
62*4882a593Smuzhiyun msg->rpc_resp = &res;
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun status = nfs4_set_rw_stateid(&args.falloc_stateid, lock->open_context,
65*4882a593Smuzhiyun lock, FMODE_WRITE);
66*4882a593Smuzhiyun if (status) {
67*4882a593Smuzhiyun if (status == -EAGAIN)
68*4882a593Smuzhiyun status = -NFS4ERR_BAD_STATEID;
69*4882a593Smuzhiyun return status;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun memcpy(bitmask, server->cache_consistency_bitmask, sizeof(bitmask));
73*4882a593Smuzhiyun if (server->attr_bitmask[1] & FATTR4_WORD1_SPACE_USED)
74*4882a593Smuzhiyun bitmask[1] |= FATTR4_WORD1_SPACE_USED;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun res.falloc_fattr = nfs_alloc_fattr();
77*4882a593Smuzhiyun if (!res.falloc_fattr)
78*4882a593Smuzhiyun return -ENOMEM;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun status = nfs4_call_sync(server->client, server, msg,
81*4882a593Smuzhiyun &args.seq_args, &res.seq_res, 0);
82*4882a593Smuzhiyun if (status == 0)
83*4882a593Smuzhiyun status = nfs_post_op_update_inode_force_wcc(inode,
84*4882a593Smuzhiyun res.falloc_fattr);
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun kfree(res.falloc_fattr);
87*4882a593Smuzhiyun return status;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
nfs42_proc_fallocate(struct rpc_message * msg,struct file * filep,loff_t offset,loff_t len)90*4882a593Smuzhiyun static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
91*4882a593Smuzhiyun loff_t offset, loff_t len)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun struct inode *inode = file_inode(filep);
94*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(inode);
95*4882a593Smuzhiyun struct nfs4_exception exception = { };
96*4882a593Smuzhiyun struct nfs_lock_context *lock;
97*4882a593Smuzhiyun int err;
98*4882a593Smuzhiyun
99*4882a593Smuzhiyun lock = nfs_get_lock_context(nfs_file_open_context(filep));
100*4882a593Smuzhiyun if (IS_ERR(lock))
101*4882a593Smuzhiyun return PTR_ERR(lock);
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun exception.inode = inode;
104*4882a593Smuzhiyun exception.state = lock->open_context->state;
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun err = nfs_sync_inode(inode);
107*4882a593Smuzhiyun if (err)
108*4882a593Smuzhiyun goto out;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun do {
111*4882a593Smuzhiyun err = _nfs42_proc_fallocate(msg, filep, lock, offset, len);
112*4882a593Smuzhiyun if (err == -ENOTSUPP) {
113*4882a593Smuzhiyun err = -EOPNOTSUPP;
114*4882a593Smuzhiyun break;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun err = nfs4_handle_exception(server, err, &exception);
117*4882a593Smuzhiyun } while (exception.retry);
118*4882a593Smuzhiyun out:
119*4882a593Smuzhiyun nfs_put_lock_context(lock);
120*4882a593Smuzhiyun return err;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
nfs42_proc_allocate(struct file * filep,loff_t offset,loff_t len)123*4882a593Smuzhiyun int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct rpc_message msg = {
126*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE],
127*4882a593Smuzhiyun };
128*4882a593Smuzhiyun struct inode *inode = file_inode(filep);
129*4882a593Smuzhiyun int err;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE))
132*4882a593Smuzhiyun return -EOPNOTSUPP;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun inode_lock(inode);
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun err = nfs42_proc_fallocate(&msg, filep, offset, len);
137*4882a593Smuzhiyun if (err == -EOPNOTSUPP)
138*4882a593Smuzhiyun NFS_SERVER(inode)->caps &= ~NFS_CAP_ALLOCATE;
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun inode_unlock(inode);
141*4882a593Smuzhiyun return err;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
nfs42_proc_deallocate(struct file * filep,loff_t offset,loff_t len)144*4882a593Smuzhiyun int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun struct rpc_message msg = {
147*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DEALLOCATE],
148*4882a593Smuzhiyun };
149*4882a593Smuzhiyun struct inode *inode = file_inode(filep);
150*4882a593Smuzhiyun int err;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE))
153*4882a593Smuzhiyun return -EOPNOTSUPP;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun inode_lock(inode);
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun err = nfs42_proc_fallocate(&msg, filep, offset, len);
158*4882a593Smuzhiyun if (err == 0)
159*4882a593Smuzhiyun truncate_pagecache_range(inode, offset, (offset + len) -1);
160*4882a593Smuzhiyun if (err == -EOPNOTSUPP)
161*4882a593Smuzhiyun NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE;
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun inode_unlock(inode);
164*4882a593Smuzhiyun return err;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun
handle_async_copy(struct nfs42_copy_res * res,struct nfs_server * dst_server,struct nfs_server * src_server,struct file * src,struct file * dst,nfs4_stateid * src_stateid,bool * restart)167*4882a593Smuzhiyun static int handle_async_copy(struct nfs42_copy_res *res,
168*4882a593Smuzhiyun struct nfs_server *dst_server,
169*4882a593Smuzhiyun struct nfs_server *src_server,
170*4882a593Smuzhiyun struct file *src,
171*4882a593Smuzhiyun struct file *dst,
172*4882a593Smuzhiyun nfs4_stateid *src_stateid,
173*4882a593Smuzhiyun bool *restart)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun struct nfs4_copy_state *copy, *tmp_copy;
176*4882a593Smuzhiyun int status = NFS4_OK;
177*4882a593Smuzhiyun bool found_pending = false;
178*4882a593Smuzhiyun struct nfs_open_context *dst_ctx = nfs_file_open_context(dst);
179*4882a593Smuzhiyun struct nfs_open_context *src_ctx = nfs_file_open_context(src);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
182*4882a593Smuzhiyun if (!copy)
183*4882a593Smuzhiyun return -ENOMEM;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun spin_lock(&dst_server->nfs_client->cl_lock);
186*4882a593Smuzhiyun list_for_each_entry(tmp_copy,
187*4882a593Smuzhiyun &dst_server->nfs_client->pending_cb_stateids,
188*4882a593Smuzhiyun copies) {
189*4882a593Smuzhiyun if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
190*4882a593Smuzhiyun NFS4_STATEID_SIZE))
191*4882a593Smuzhiyun continue;
192*4882a593Smuzhiyun found_pending = true;
193*4882a593Smuzhiyun list_del(&tmp_copy->copies);
194*4882a593Smuzhiyun break;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun if (found_pending) {
197*4882a593Smuzhiyun spin_unlock(&dst_server->nfs_client->cl_lock);
198*4882a593Smuzhiyun kfree(copy);
199*4882a593Smuzhiyun copy = tmp_copy;
200*4882a593Smuzhiyun goto out;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
204*4882a593Smuzhiyun init_completion(©->completion);
205*4882a593Smuzhiyun copy->parent_dst_state = dst_ctx->state;
206*4882a593Smuzhiyun copy->parent_src_state = src_ctx->state;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun list_add_tail(©->copies, &dst_server->ss_copies);
209*4882a593Smuzhiyun spin_unlock(&dst_server->nfs_client->cl_lock);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun if (dst_server != src_server) {
212*4882a593Smuzhiyun spin_lock(&src_server->nfs_client->cl_lock);
213*4882a593Smuzhiyun list_add_tail(©->src_copies, &src_server->ss_copies);
214*4882a593Smuzhiyun spin_unlock(&src_server->nfs_client->cl_lock);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun status = wait_for_completion_interruptible(©->completion);
218*4882a593Smuzhiyun spin_lock(&dst_server->nfs_client->cl_lock);
219*4882a593Smuzhiyun list_del_init(©->copies);
220*4882a593Smuzhiyun spin_unlock(&dst_server->nfs_client->cl_lock);
221*4882a593Smuzhiyun if (dst_server != src_server) {
222*4882a593Smuzhiyun spin_lock(&src_server->nfs_client->cl_lock);
223*4882a593Smuzhiyun list_del_init(©->src_copies);
224*4882a593Smuzhiyun spin_unlock(&src_server->nfs_client->cl_lock);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun if (status == -ERESTARTSYS) {
227*4882a593Smuzhiyun goto out_cancel;
228*4882a593Smuzhiyun } else if (copy->flags || copy->error == NFS4ERR_PARTNER_NO_AUTH) {
229*4882a593Smuzhiyun status = -EAGAIN;
230*4882a593Smuzhiyun *restart = true;
231*4882a593Smuzhiyun goto out_cancel;
232*4882a593Smuzhiyun }
233*4882a593Smuzhiyun out:
234*4882a593Smuzhiyun res->write_res.count = copy->count;
235*4882a593Smuzhiyun memcpy(&res->write_res.verifier, ©->verf, sizeof(copy->verf));
236*4882a593Smuzhiyun status = -copy->error;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun out_free:
239*4882a593Smuzhiyun kfree(copy);
240*4882a593Smuzhiyun return status;
241*4882a593Smuzhiyun out_cancel:
242*4882a593Smuzhiyun nfs42_do_offload_cancel_async(dst, ©->stateid);
243*4882a593Smuzhiyun if (!nfs42_files_from_same_server(src, dst))
244*4882a593Smuzhiyun nfs42_do_offload_cancel_async(src, src_stateid);
245*4882a593Smuzhiyun goto out_free;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
process_copy_commit(struct file * dst,loff_t pos_dst,struct nfs42_copy_res * res)248*4882a593Smuzhiyun static int process_copy_commit(struct file *dst, loff_t pos_dst,
249*4882a593Smuzhiyun struct nfs42_copy_res *res)
250*4882a593Smuzhiyun {
251*4882a593Smuzhiyun struct nfs_commitres cres;
252*4882a593Smuzhiyun int status = -ENOMEM;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun cres.verf = kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
255*4882a593Smuzhiyun if (!cres.verf)
256*4882a593Smuzhiyun goto out;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun status = nfs4_proc_commit(dst, pos_dst, res->write_res.count, &cres);
259*4882a593Smuzhiyun if (status)
260*4882a593Smuzhiyun goto out_free;
261*4882a593Smuzhiyun if (nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
262*4882a593Smuzhiyun &cres.verf->verifier)) {
263*4882a593Smuzhiyun dprintk("commit verf differs from copy verf\n");
264*4882a593Smuzhiyun status = -EAGAIN;
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun out_free:
267*4882a593Smuzhiyun kfree(cres.verf);
268*4882a593Smuzhiyun out:
269*4882a593Smuzhiyun return status;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
_nfs42_proc_copy(struct file * src,struct nfs_lock_context * src_lock,struct file * dst,struct nfs_lock_context * dst_lock,struct nfs42_copy_args * args,struct nfs42_copy_res * res,struct nl4_server * nss,nfs4_stateid * cnr_stateid,bool * restart)272*4882a593Smuzhiyun static ssize_t _nfs42_proc_copy(struct file *src,
273*4882a593Smuzhiyun struct nfs_lock_context *src_lock,
274*4882a593Smuzhiyun struct file *dst,
275*4882a593Smuzhiyun struct nfs_lock_context *dst_lock,
276*4882a593Smuzhiyun struct nfs42_copy_args *args,
277*4882a593Smuzhiyun struct nfs42_copy_res *res,
278*4882a593Smuzhiyun struct nl4_server *nss,
279*4882a593Smuzhiyun nfs4_stateid *cnr_stateid,
280*4882a593Smuzhiyun bool *restart)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun struct rpc_message msg = {
283*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
284*4882a593Smuzhiyun .rpc_argp = args,
285*4882a593Smuzhiyun .rpc_resp = res,
286*4882a593Smuzhiyun };
287*4882a593Smuzhiyun struct inode *dst_inode = file_inode(dst);
288*4882a593Smuzhiyun struct inode *src_inode = file_inode(src);
289*4882a593Smuzhiyun struct nfs_server *dst_server = NFS_SERVER(dst_inode);
290*4882a593Smuzhiyun struct nfs_server *src_server = NFS_SERVER(src_inode);
291*4882a593Smuzhiyun loff_t pos_src = args->src_pos;
292*4882a593Smuzhiyun loff_t pos_dst = args->dst_pos;
293*4882a593Smuzhiyun size_t count = args->count;
294*4882a593Smuzhiyun ssize_t status;
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun if (nss) {
297*4882a593Smuzhiyun args->cp_src = nss;
298*4882a593Smuzhiyun nfs4_stateid_copy(&args->src_stateid, cnr_stateid);
299*4882a593Smuzhiyun } else {
300*4882a593Smuzhiyun status = nfs4_set_rw_stateid(&args->src_stateid,
301*4882a593Smuzhiyun src_lock->open_context, src_lock, FMODE_READ);
302*4882a593Smuzhiyun if (status) {
303*4882a593Smuzhiyun if (status == -EAGAIN)
304*4882a593Smuzhiyun status = -NFS4ERR_BAD_STATEID;
305*4882a593Smuzhiyun return status;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun }
308*4882a593Smuzhiyun status = nfs_filemap_write_and_wait_range(file_inode(src)->i_mapping,
309*4882a593Smuzhiyun pos_src, pos_src + (loff_t)count - 1);
310*4882a593Smuzhiyun if (status)
311*4882a593Smuzhiyun return status;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun status = nfs4_set_rw_stateid(&args->dst_stateid, dst_lock->open_context,
314*4882a593Smuzhiyun dst_lock, FMODE_WRITE);
315*4882a593Smuzhiyun if (status) {
316*4882a593Smuzhiyun if (status == -EAGAIN)
317*4882a593Smuzhiyun status = -NFS4ERR_BAD_STATEID;
318*4882a593Smuzhiyun return status;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun status = nfs_sync_inode(dst_inode);
322*4882a593Smuzhiyun if (status)
323*4882a593Smuzhiyun return status;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun res->commit_res.verf = NULL;
326*4882a593Smuzhiyun if (args->sync) {
327*4882a593Smuzhiyun res->commit_res.verf =
328*4882a593Smuzhiyun kzalloc(sizeof(struct nfs_writeverf), GFP_NOFS);
329*4882a593Smuzhiyun if (!res->commit_res.verf)
330*4882a593Smuzhiyun return -ENOMEM;
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun set_bit(NFS_CLNT_SRC_SSC_COPY_STATE,
333*4882a593Smuzhiyun &src_lock->open_context->state->flags);
334*4882a593Smuzhiyun set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
335*4882a593Smuzhiyun &dst_lock->open_context->state->flags);
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun status = nfs4_call_sync(dst_server->client, dst_server, &msg,
338*4882a593Smuzhiyun &args->seq_args, &res->seq_res, 0);
339*4882a593Smuzhiyun if (status == -ENOTSUPP)
340*4882a593Smuzhiyun dst_server->caps &= ~NFS_CAP_COPY;
341*4882a593Smuzhiyun if (status)
342*4882a593Smuzhiyun goto out;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun if (args->sync &&
345*4882a593Smuzhiyun nfs_write_verifier_cmp(&res->write_res.verifier.verifier,
346*4882a593Smuzhiyun &res->commit_res.verf->verifier)) {
347*4882a593Smuzhiyun status = -EAGAIN;
348*4882a593Smuzhiyun goto out;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun if (!res->synchronous) {
352*4882a593Smuzhiyun status = handle_async_copy(res, dst_server, src_server, src,
353*4882a593Smuzhiyun dst, &args->src_stateid, restart);
354*4882a593Smuzhiyun if (status)
355*4882a593Smuzhiyun goto out;
356*4882a593Smuzhiyun }
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun if ((!res->synchronous || !args->sync) &&
359*4882a593Smuzhiyun res->write_res.verifier.committed != NFS_FILE_SYNC) {
360*4882a593Smuzhiyun status = process_copy_commit(dst, pos_dst, res);
361*4882a593Smuzhiyun if (status)
362*4882a593Smuzhiyun goto out;
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun WARN_ON_ONCE(invalidate_inode_pages2_range(dst_inode->i_mapping,
366*4882a593Smuzhiyun pos_dst >> PAGE_SHIFT,
367*4882a593Smuzhiyun (pos_dst + res->write_res.count - 1) >> PAGE_SHIFT));
368*4882a593Smuzhiyun spin_lock(&dst_inode->i_lock);
369*4882a593Smuzhiyun NFS_I(dst_inode)->cache_validity |= (NFS_INO_REVAL_PAGECACHE |
370*4882a593Smuzhiyun NFS_INO_REVAL_FORCED | NFS_INO_INVALID_SIZE |
371*4882a593Smuzhiyun NFS_INO_INVALID_ATTR | NFS_INO_INVALID_DATA);
372*4882a593Smuzhiyun spin_unlock(&dst_inode->i_lock);
373*4882a593Smuzhiyun spin_lock(&src_inode->i_lock);
374*4882a593Smuzhiyun NFS_I(src_inode)->cache_validity |= (NFS_INO_REVAL_PAGECACHE |
375*4882a593Smuzhiyun NFS_INO_REVAL_FORCED | NFS_INO_INVALID_ATIME);
376*4882a593Smuzhiyun spin_unlock(&src_inode->i_lock);
377*4882a593Smuzhiyun status = res->write_res.count;
378*4882a593Smuzhiyun out:
379*4882a593Smuzhiyun if (args->sync)
380*4882a593Smuzhiyun kfree(res->commit_res.verf);
381*4882a593Smuzhiyun return status;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
nfs42_proc_copy(struct file * src,loff_t pos_src,struct file * dst,loff_t pos_dst,size_t count,struct nl4_server * nss,nfs4_stateid * cnr_stateid,bool sync)384*4882a593Smuzhiyun ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
385*4882a593Smuzhiyun struct file *dst, loff_t pos_dst, size_t count,
386*4882a593Smuzhiyun struct nl4_server *nss,
387*4882a593Smuzhiyun nfs4_stateid *cnr_stateid, bool sync)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(file_inode(dst));
390*4882a593Smuzhiyun struct nfs_lock_context *src_lock;
391*4882a593Smuzhiyun struct nfs_lock_context *dst_lock;
392*4882a593Smuzhiyun struct nfs42_copy_args args = {
393*4882a593Smuzhiyun .src_fh = NFS_FH(file_inode(src)),
394*4882a593Smuzhiyun .src_pos = pos_src,
395*4882a593Smuzhiyun .dst_fh = NFS_FH(file_inode(dst)),
396*4882a593Smuzhiyun .dst_pos = pos_dst,
397*4882a593Smuzhiyun .count = count,
398*4882a593Smuzhiyun .sync = sync,
399*4882a593Smuzhiyun };
400*4882a593Smuzhiyun struct nfs42_copy_res res;
401*4882a593Smuzhiyun struct nfs4_exception src_exception = {
402*4882a593Smuzhiyun .inode = file_inode(src),
403*4882a593Smuzhiyun .stateid = &args.src_stateid,
404*4882a593Smuzhiyun };
405*4882a593Smuzhiyun struct nfs4_exception dst_exception = {
406*4882a593Smuzhiyun .inode = file_inode(dst),
407*4882a593Smuzhiyun .stateid = &args.dst_stateid,
408*4882a593Smuzhiyun };
409*4882a593Smuzhiyun ssize_t err, err2;
410*4882a593Smuzhiyun bool restart = false;
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun src_lock = nfs_get_lock_context(nfs_file_open_context(src));
413*4882a593Smuzhiyun if (IS_ERR(src_lock))
414*4882a593Smuzhiyun return PTR_ERR(src_lock);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun src_exception.state = src_lock->open_context->state;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun dst_lock = nfs_get_lock_context(nfs_file_open_context(dst));
419*4882a593Smuzhiyun if (IS_ERR(dst_lock)) {
420*4882a593Smuzhiyun err = PTR_ERR(dst_lock);
421*4882a593Smuzhiyun goto out_put_src_lock;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun dst_exception.state = dst_lock->open_context->state;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun do {
427*4882a593Smuzhiyun inode_lock(file_inode(dst));
428*4882a593Smuzhiyun err = _nfs42_proc_copy(src, src_lock,
429*4882a593Smuzhiyun dst, dst_lock,
430*4882a593Smuzhiyun &args, &res,
431*4882a593Smuzhiyun nss, cnr_stateid, &restart);
432*4882a593Smuzhiyun inode_unlock(file_inode(dst));
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun if (err >= 0)
435*4882a593Smuzhiyun break;
436*4882a593Smuzhiyun if (err == -ENOTSUPP &&
437*4882a593Smuzhiyun nfs42_files_from_same_server(src, dst)) {
438*4882a593Smuzhiyun err = -EOPNOTSUPP;
439*4882a593Smuzhiyun break;
440*4882a593Smuzhiyun } else if (err == -EAGAIN) {
441*4882a593Smuzhiyun if (!restart) {
442*4882a593Smuzhiyun dst_exception.retry = 1;
443*4882a593Smuzhiyun continue;
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun break;
446*4882a593Smuzhiyun } else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) {
447*4882a593Smuzhiyun args.sync = true;
448*4882a593Smuzhiyun dst_exception.retry = 1;
449*4882a593Smuzhiyun continue;
450*4882a593Smuzhiyun } else if ((err == -ESTALE ||
451*4882a593Smuzhiyun err == -NFS4ERR_OFFLOAD_DENIED ||
452*4882a593Smuzhiyun err == -ENOTSUPP) &&
453*4882a593Smuzhiyun !nfs42_files_from_same_server(src, dst)) {
454*4882a593Smuzhiyun nfs42_do_offload_cancel_async(src, &args.src_stateid);
455*4882a593Smuzhiyun err = -EOPNOTSUPP;
456*4882a593Smuzhiyun break;
457*4882a593Smuzhiyun }
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun err2 = nfs4_handle_exception(server, err, &src_exception);
460*4882a593Smuzhiyun err = nfs4_handle_exception(server, err, &dst_exception);
461*4882a593Smuzhiyun if (!err)
462*4882a593Smuzhiyun err = err2;
463*4882a593Smuzhiyun } while (src_exception.retry || dst_exception.retry);
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun nfs_put_lock_context(dst_lock);
466*4882a593Smuzhiyun out_put_src_lock:
467*4882a593Smuzhiyun nfs_put_lock_context(src_lock);
468*4882a593Smuzhiyun return err;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun struct nfs42_offloadcancel_data {
472*4882a593Smuzhiyun struct nfs_server *seq_server;
473*4882a593Smuzhiyun struct nfs42_offload_status_args args;
474*4882a593Smuzhiyun struct nfs42_offload_status_res res;
475*4882a593Smuzhiyun };
476*4882a593Smuzhiyun
nfs42_offload_cancel_prepare(struct rpc_task * task,void * calldata)477*4882a593Smuzhiyun static void nfs42_offload_cancel_prepare(struct rpc_task *task, void *calldata)
478*4882a593Smuzhiyun {
479*4882a593Smuzhiyun struct nfs42_offloadcancel_data *data = calldata;
480*4882a593Smuzhiyun
481*4882a593Smuzhiyun nfs4_setup_sequence(data->seq_server->nfs_client,
482*4882a593Smuzhiyun &data->args.osa_seq_args,
483*4882a593Smuzhiyun &data->res.osr_seq_res, task);
484*4882a593Smuzhiyun }
485*4882a593Smuzhiyun
nfs42_offload_cancel_done(struct rpc_task * task,void * calldata)486*4882a593Smuzhiyun static void nfs42_offload_cancel_done(struct rpc_task *task, void *calldata)
487*4882a593Smuzhiyun {
488*4882a593Smuzhiyun struct nfs42_offloadcancel_data *data = calldata;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun nfs41_sequence_done(task, &data->res.osr_seq_res);
491*4882a593Smuzhiyun if (task->tk_status &&
492*4882a593Smuzhiyun nfs4_async_handle_error(task, data->seq_server, NULL,
493*4882a593Smuzhiyun NULL) == -EAGAIN)
494*4882a593Smuzhiyun rpc_restart_call_prepare(task);
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun
nfs42_free_offloadcancel_data(void * data)497*4882a593Smuzhiyun static void nfs42_free_offloadcancel_data(void *data)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun kfree(data);
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun static const struct rpc_call_ops nfs42_offload_cancel_ops = {
503*4882a593Smuzhiyun .rpc_call_prepare = nfs42_offload_cancel_prepare,
504*4882a593Smuzhiyun .rpc_call_done = nfs42_offload_cancel_done,
505*4882a593Smuzhiyun .rpc_release = nfs42_free_offloadcancel_data,
506*4882a593Smuzhiyun };
507*4882a593Smuzhiyun
nfs42_do_offload_cancel_async(struct file * dst,nfs4_stateid * stateid)508*4882a593Smuzhiyun static int nfs42_do_offload_cancel_async(struct file *dst,
509*4882a593Smuzhiyun nfs4_stateid *stateid)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun struct nfs_server *dst_server = NFS_SERVER(file_inode(dst));
512*4882a593Smuzhiyun struct nfs42_offloadcancel_data *data = NULL;
513*4882a593Smuzhiyun struct nfs_open_context *ctx = nfs_file_open_context(dst);
514*4882a593Smuzhiyun struct rpc_task *task;
515*4882a593Smuzhiyun struct rpc_message msg = {
516*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OFFLOAD_CANCEL],
517*4882a593Smuzhiyun .rpc_cred = ctx->cred,
518*4882a593Smuzhiyun };
519*4882a593Smuzhiyun struct rpc_task_setup task_setup_data = {
520*4882a593Smuzhiyun .rpc_client = dst_server->client,
521*4882a593Smuzhiyun .rpc_message = &msg,
522*4882a593Smuzhiyun .callback_ops = &nfs42_offload_cancel_ops,
523*4882a593Smuzhiyun .workqueue = nfsiod_workqueue,
524*4882a593Smuzhiyun .flags = RPC_TASK_ASYNC,
525*4882a593Smuzhiyun };
526*4882a593Smuzhiyun int status;
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun if (!(dst_server->caps & NFS_CAP_OFFLOAD_CANCEL))
529*4882a593Smuzhiyun return -EOPNOTSUPP;
530*4882a593Smuzhiyun
531*4882a593Smuzhiyun data = kzalloc(sizeof(struct nfs42_offloadcancel_data), GFP_NOFS);
532*4882a593Smuzhiyun if (data == NULL)
533*4882a593Smuzhiyun return -ENOMEM;
534*4882a593Smuzhiyun
535*4882a593Smuzhiyun data->seq_server = dst_server;
536*4882a593Smuzhiyun data->args.osa_src_fh = NFS_FH(file_inode(dst));
537*4882a593Smuzhiyun memcpy(&data->args.osa_stateid, stateid,
538*4882a593Smuzhiyun sizeof(data->args.osa_stateid));
539*4882a593Smuzhiyun msg.rpc_argp = &data->args;
540*4882a593Smuzhiyun msg.rpc_resp = &data->res;
541*4882a593Smuzhiyun task_setup_data.callback_data = data;
542*4882a593Smuzhiyun nfs4_init_sequence(&data->args.osa_seq_args, &data->res.osr_seq_res,
543*4882a593Smuzhiyun 1, 0);
544*4882a593Smuzhiyun task = rpc_run_task(&task_setup_data);
545*4882a593Smuzhiyun if (IS_ERR(task))
546*4882a593Smuzhiyun return PTR_ERR(task);
547*4882a593Smuzhiyun status = rpc_wait_for_completion_task(task);
548*4882a593Smuzhiyun if (status == -ENOTSUPP)
549*4882a593Smuzhiyun dst_server->caps &= ~NFS_CAP_OFFLOAD_CANCEL;
550*4882a593Smuzhiyun rpc_put_task(task);
551*4882a593Smuzhiyun return status;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun
_nfs42_proc_copy_notify(struct file * src,struct file * dst,struct nfs42_copy_notify_args * args,struct nfs42_copy_notify_res * res)554*4882a593Smuzhiyun static int _nfs42_proc_copy_notify(struct file *src, struct file *dst,
555*4882a593Smuzhiyun struct nfs42_copy_notify_args *args,
556*4882a593Smuzhiyun struct nfs42_copy_notify_res *res)
557*4882a593Smuzhiyun {
558*4882a593Smuzhiyun struct nfs_server *src_server = NFS_SERVER(file_inode(src));
559*4882a593Smuzhiyun struct rpc_message msg = {
560*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY_NOTIFY],
561*4882a593Smuzhiyun .rpc_argp = args,
562*4882a593Smuzhiyun .rpc_resp = res,
563*4882a593Smuzhiyun };
564*4882a593Smuzhiyun int status;
565*4882a593Smuzhiyun struct nfs_open_context *ctx;
566*4882a593Smuzhiyun struct nfs_lock_context *l_ctx;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun ctx = get_nfs_open_context(nfs_file_open_context(src));
569*4882a593Smuzhiyun l_ctx = nfs_get_lock_context(ctx);
570*4882a593Smuzhiyun if (IS_ERR(l_ctx)) {
571*4882a593Smuzhiyun status = PTR_ERR(l_ctx);
572*4882a593Smuzhiyun goto out;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun status = nfs4_set_rw_stateid(&args->cna_src_stateid, ctx, l_ctx,
576*4882a593Smuzhiyun FMODE_READ);
577*4882a593Smuzhiyun nfs_put_lock_context(l_ctx);
578*4882a593Smuzhiyun if (status) {
579*4882a593Smuzhiyun if (status == -EAGAIN)
580*4882a593Smuzhiyun status = -NFS4ERR_BAD_STATEID;
581*4882a593Smuzhiyun goto out;
582*4882a593Smuzhiyun }
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun status = nfs4_call_sync(src_server->client, src_server, &msg,
585*4882a593Smuzhiyun &args->cna_seq_args, &res->cnr_seq_res, 0);
586*4882a593Smuzhiyun if (status == -ENOTSUPP)
587*4882a593Smuzhiyun src_server->caps &= ~NFS_CAP_COPY_NOTIFY;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun out:
590*4882a593Smuzhiyun put_nfs_open_context(nfs_file_open_context(src));
591*4882a593Smuzhiyun return status;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun
nfs42_proc_copy_notify(struct file * src,struct file * dst,struct nfs42_copy_notify_res * res)594*4882a593Smuzhiyun int nfs42_proc_copy_notify(struct file *src, struct file *dst,
595*4882a593Smuzhiyun struct nfs42_copy_notify_res *res)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun struct nfs_server *src_server = NFS_SERVER(file_inode(src));
598*4882a593Smuzhiyun struct nfs42_copy_notify_args *args;
599*4882a593Smuzhiyun struct nfs4_exception exception = {
600*4882a593Smuzhiyun .inode = file_inode(src),
601*4882a593Smuzhiyun };
602*4882a593Smuzhiyun int status;
603*4882a593Smuzhiyun
604*4882a593Smuzhiyun if (!(src_server->caps & NFS_CAP_COPY_NOTIFY))
605*4882a593Smuzhiyun return -EOPNOTSUPP;
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun args = kzalloc(sizeof(struct nfs42_copy_notify_args), GFP_NOFS);
608*4882a593Smuzhiyun if (args == NULL)
609*4882a593Smuzhiyun return -ENOMEM;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun args->cna_src_fh = NFS_FH(file_inode(src)),
612*4882a593Smuzhiyun args->cna_dst.nl4_type = NL4_NETADDR;
613*4882a593Smuzhiyun nfs42_set_netaddr(dst, &args->cna_dst.u.nl4_addr);
614*4882a593Smuzhiyun exception.stateid = &args->cna_src_stateid;
615*4882a593Smuzhiyun
616*4882a593Smuzhiyun do {
617*4882a593Smuzhiyun status = _nfs42_proc_copy_notify(src, dst, args, res);
618*4882a593Smuzhiyun if (status == -ENOTSUPP) {
619*4882a593Smuzhiyun status = -EOPNOTSUPP;
620*4882a593Smuzhiyun goto out;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun status = nfs4_handle_exception(src_server, status, &exception);
623*4882a593Smuzhiyun } while (exception.retry);
624*4882a593Smuzhiyun
625*4882a593Smuzhiyun out:
626*4882a593Smuzhiyun kfree(args);
627*4882a593Smuzhiyun return status;
628*4882a593Smuzhiyun }
629*4882a593Smuzhiyun
_nfs42_proc_llseek(struct file * filep,struct nfs_lock_context * lock,loff_t offset,int whence)630*4882a593Smuzhiyun static loff_t _nfs42_proc_llseek(struct file *filep,
631*4882a593Smuzhiyun struct nfs_lock_context *lock, loff_t offset, int whence)
632*4882a593Smuzhiyun {
633*4882a593Smuzhiyun struct inode *inode = file_inode(filep);
634*4882a593Smuzhiyun struct nfs42_seek_args args = {
635*4882a593Smuzhiyun .sa_fh = NFS_FH(inode),
636*4882a593Smuzhiyun .sa_offset = offset,
637*4882a593Smuzhiyun .sa_what = (whence == SEEK_HOLE) ?
638*4882a593Smuzhiyun NFS4_CONTENT_HOLE : NFS4_CONTENT_DATA,
639*4882a593Smuzhiyun };
640*4882a593Smuzhiyun struct nfs42_seek_res res;
641*4882a593Smuzhiyun struct rpc_message msg = {
642*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEEK],
643*4882a593Smuzhiyun .rpc_argp = &args,
644*4882a593Smuzhiyun .rpc_resp = &res,
645*4882a593Smuzhiyun };
646*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(inode);
647*4882a593Smuzhiyun int status;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun if (!nfs_server_capable(inode, NFS_CAP_SEEK))
650*4882a593Smuzhiyun return -ENOTSUPP;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun status = nfs4_set_rw_stateid(&args.sa_stateid, lock->open_context,
653*4882a593Smuzhiyun lock, FMODE_READ);
654*4882a593Smuzhiyun if (status) {
655*4882a593Smuzhiyun if (status == -EAGAIN)
656*4882a593Smuzhiyun status = -NFS4ERR_BAD_STATEID;
657*4882a593Smuzhiyun return status;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun status = nfs_filemap_write_and_wait_range(inode->i_mapping,
661*4882a593Smuzhiyun offset, LLONG_MAX);
662*4882a593Smuzhiyun if (status)
663*4882a593Smuzhiyun return status;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun status = nfs4_call_sync(server->client, server, &msg,
666*4882a593Smuzhiyun &args.seq_args, &res.seq_res, 0);
667*4882a593Smuzhiyun if (status == -ENOTSUPP)
668*4882a593Smuzhiyun server->caps &= ~NFS_CAP_SEEK;
669*4882a593Smuzhiyun if (status)
670*4882a593Smuzhiyun return status;
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun if (whence == SEEK_DATA && res.sr_eof)
673*4882a593Smuzhiyun return -NFS4ERR_NXIO;
674*4882a593Smuzhiyun else
675*4882a593Smuzhiyun return vfs_setpos(filep, res.sr_offset, inode->i_sb->s_maxbytes);
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun
nfs42_proc_llseek(struct file * filep,loff_t offset,int whence)678*4882a593Smuzhiyun loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
679*4882a593Smuzhiyun {
680*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(file_inode(filep));
681*4882a593Smuzhiyun struct nfs4_exception exception = { };
682*4882a593Smuzhiyun struct nfs_lock_context *lock;
683*4882a593Smuzhiyun loff_t err;
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun lock = nfs_get_lock_context(nfs_file_open_context(filep));
686*4882a593Smuzhiyun if (IS_ERR(lock))
687*4882a593Smuzhiyun return PTR_ERR(lock);
688*4882a593Smuzhiyun
689*4882a593Smuzhiyun exception.inode = file_inode(filep);
690*4882a593Smuzhiyun exception.state = lock->open_context->state;
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun do {
693*4882a593Smuzhiyun err = _nfs42_proc_llseek(filep, lock, offset, whence);
694*4882a593Smuzhiyun if (err >= 0)
695*4882a593Smuzhiyun break;
696*4882a593Smuzhiyun if (err == -ENOTSUPP) {
697*4882a593Smuzhiyun err = -EOPNOTSUPP;
698*4882a593Smuzhiyun break;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun err = nfs4_handle_exception(server, err, &exception);
701*4882a593Smuzhiyun } while (exception.retry);
702*4882a593Smuzhiyun
703*4882a593Smuzhiyun nfs_put_lock_context(lock);
704*4882a593Smuzhiyun return err;
705*4882a593Smuzhiyun }
706*4882a593Smuzhiyun
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun static void
nfs42_layoutstat_prepare(struct rpc_task * task,void * calldata)709*4882a593Smuzhiyun nfs42_layoutstat_prepare(struct rpc_task *task, void *calldata)
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun struct nfs42_layoutstat_data *data = calldata;
712*4882a593Smuzhiyun struct inode *inode = data->inode;
713*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(inode);
714*4882a593Smuzhiyun struct pnfs_layout_hdr *lo;
715*4882a593Smuzhiyun
716*4882a593Smuzhiyun spin_lock(&inode->i_lock);
717*4882a593Smuzhiyun lo = NFS_I(inode)->layout;
718*4882a593Smuzhiyun if (!pnfs_layout_is_valid(lo)) {
719*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
720*4882a593Smuzhiyun rpc_exit(task, 0);
721*4882a593Smuzhiyun return;
722*4882a593Smuzhiyun }
723*4882a593Smuzhiyun nfs4_stateid_copy(&data->args.stateid, &lo->plh_stateid);
724*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
725*4882a593Smuzhiyun nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
726*4882a593Smuzhiyun &data->res.seq_res, task);
727*4882a593Smuzhiyun }
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun static void
nfs42_layoutstat_done(struct rpc_task * task,void * calldata)730*4882a593Smuzhiyun nfs42_layoutstat_done(struct rpc_task *task, void *calldata)
731*4882a593Smuzhiyun {
732*4882a593Smuzhiyun struct nfs42_layoutstat_data *data = calldata;
733*4882a593Smuzhiyun struct inode *inode = data->inode;
734*4882a593Smuzhiyun struct pnfs_layout_hdr *lo;
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun if (!nfs4_sequence_done(task, &data->res.seq_res))
737*4882a593Smuzhiyun return;
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun switch (task->tk_status) {
740*4882a593Smuzhiyun case 0:
741*4882a593Smuzhiyun return;
742*4882a593Smuzhiyun case -NFS4ERR_BADHANDLE:
743*4882a593Smuzhiyun case -ESTALE:
744*4882a593Smuzhiyun pnfs_destroy_layout(NFS_I(inode));
745*4882a593Smuzhiyun break;
746*4882a593Smuzhiyun case -NFS4ERR_EXPIRED:
747*4882a593Smuzhiyun case -NFS4ERR_ADMIN_REVOKED:
748*4882a593Smuzhiyun case -NFS4ERR_DELEG_REVOKED:
749*4882a593Smuzhiyun case -NFS4ERR_STALE_STATEID:
750*4882a593Smuzhiyun case -NFS4ERR_BAD_STATEID:
751*4882a593Smuzhiyun spin_lock(&inode->i_lock);
752*4882a593Smuzhiyun lo = NFS_I(inode)->layout;
753*4882a593Smuzhiyun if (pnfs_layout_is_valid(lo) &&
754*4882a593Smuzhiyun nfs4_stateid_match(&data->args.stateid,
755*4882a593Smuzhiyun &lo->plh_stateid)) {
756*4882a593Smuzhiyun LIST_HEAD(head);
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun /*
759*4882a593Smuzhiyun * Mark the bad layout state as invalid, then retry
760*4882a593Smuzhiyun * with the current stateid.
761*4882a593Smuzhiyun */
762*4882a593Smuzhiyun pnfs_mark_layout_stateid_invalid(lo, &head);
763*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
764*4882a593Smuzhiyun pnfs_free_lseg_list(&head);
765*4882a593Smuzhiyun nfs_commit_inode(inode, 0);
766*4882a593Smuzhiyun } else
767*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
768*4882a593Smuzhiyun break;
769*4882a593Smuzhiyun case -NFS4ERR_OLD_STATEID:
770*4882a593Smuzhiyun spin_lock(&inode->i_lock);
771*4882a593Smuzhiyun lo = NFS_I(inode)->layout;
772*4882a593Smuzhiyun if (pnfs_layout_is_valid(lo) &&
773*4882a593Smuzhiyun nfs4_stateid_match_other(&data->args.stateid,
774*4882a593Smuzhiyun &lo->plh_stateid)) {
775*4882a593Smuzhiyun /* Do we need to delay before resending? */
776*4882a593Smuzhiyun if (!nfs4_stateid_is_newer(&lo->plh_stateid,
777*4882a593Smuzhiyun &data->args.stateid))
778*4882a593Smuzhiyun rpc_delay(task, HZ);
779*4882a593Smuzhiyun rpc_restart_call_prepare(task);
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
782*4882a593Smuzhiyun break;
783*4882a593Smuzhiyun case -ENOTSUPP:
784*4882a593Smuzhiyun case -EOPNOTSUPP:
785*4882a593Smuzhiyun NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTSTATS;
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun trace_nfs4_layoutstats(inode, &data->args.stateid, task->tk_status);
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun
791*4882a593Smuzhiyun static void
nfs42_layoutstat_release(void * calldata)792*4882a593Smuzhiyun nfs42_layoutstat_release(void *calldata)
793*4882a593Smuzhiyun {
794*4882a593Smuzhiyun struct nfs42_layoutstat_data *data = calldata;
795*4882a593Smuzhiyun struct nfs42_layoutstat_devinfo *devinfo = data->args.devinfo;
796*4882a593Smuzhiyun int i;
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun for (i = 0; i < data->args.num_dev; i++) {
799*4882a593Smuzhiyun if (devinfo[i].ld_private.ops && devinfo[i].ld_private.ops->free)
800*4882a593Smuzhiyun devinfo[i].ld_private.ops->free(&devinfo[i].ld_private);
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
803*4882a593Smuzhiyun pnfs_put_layout_hdr(NFS_I(data->args.inode)->layout);
804*4882a593Smuzhiyun smp_mb__before_atomic();
805*4882a593Smuzhiyun clear_bit(NFS_INO_LAYOUTSTATS, &NFS_I(data->args.inode)->flags);
806*4882a593Smuzhiyun smp_mb__after_atomic();
807*4882a593Smuzhiyun nfs_iput_and_deactive(data->inode);
808*4882a593Smuzhiyun kfree(data->args.devinfo);
809*4882a593Smuzhiyun kfree(data);
810*4882a593Smuzhiyun }
811*4882a593Smuzhiyun
812*4882a593Smuzhiyun static const struct rpc_call_ops nfs42_layoutstat_ops = {
813*4882a593Smuzhiyun .rpc_call_prepare = nfs42_layoutstat_prepare,
814*4882a593Smuzhiyun .rpc_call_done = nfs42_layoutstat_done,
815*4882a593Smuzhiyun .rpc_release = nfs42_layoutstat_release,
816*4882a593Smuzhiyun };
817*4882a593Smuzhiyun
nfs42_proc_layoutstats_generic(struct nfs_server * server,struct nfs42_layoutstat_data * data)818*4882a593Smuzhiyun int nfs42_proc_layoutstats_generic(struct nfs_server *server,
819*4882a593Smuzhiyun struct nfs42_layoutstat_data *data)
820*4882a593Smuzhiyun {
821*4882a593Smuzhiyun struct rpc_message msg = {
822*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTSTATS],
823*4882a593Smuzhiyun .rpc_argp = &data->args,
824*4882a593Smuzhiyun .rpc_resp = &data->res,
825*4882a593Smuzhiyun };
826*4882a593Smuzhiyun struct rpc_task_setup task_setup = {
827*4882a593Smuzhiyun .rpc_client = server->client,
828*4882a593Smuzhiyun .rpc_message = &msg,
829*4882a593Smuzhiyun .callback_ops = &nfs42_layoutstat_ops,
830*4882a593Smuzhiyun .callback_data = data,
831*4882a593Smuzhiyun .flags = RPC_TASK_ASYNC,
832*4882a593Smuzhiyun };
833*4882a593Smuzhiyun struct rpc_task *task;
834*4882a593Smuzhiyun
835*4882a593Smuzhiyun data->inode = nfs_igrab_and_active(data->args.inode);
836*4882a593Smuzhiyun if (!data->inode) {
837*4882a593Smuzhiyun nfs42_layoutstat_release(data);
838*4882a593Smuzhiyun return -EAGAIN;
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0);
841*4882a593Smuzhiyun task = rpc_run_task(&task_setup);
842*4882a593Smuzhiyun if (IS_ERR(task))
843*4882a593Smuzhiyun return PTR_ERR(task);
844*4882a593Smuzhiyun rpc_put_task(task);
845*4882a593Smuzhiyun return 0;
846*4882a593Smuzhiyun }
847*4882a593Smuzhiyun
848*4882a593Smuzhiyun static struct nfs42_layouterror_data *
nfs42_alloc_layouterror_data(struct pnfs_layout_segment * lseg,gfp_t gfp_flags)849*4882a593Smuzhiyun nfs42_alloc_layouterror_data(struct pnfs_layout_segment *lseg, gfp_t gfp_flags)
850*4882a593Smuzhiyun {
851*4882a593Smuzhiyun struct nfs42_layouterror_data *data;
852*4882a593Smuzhiyun struct inode *inode = lseg->pls_layout->plh_inode;
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun data = kzalloc(sizeof(*data), gfp_flags);
855*4882a593Smuzhiyun if (data) {
856*4882a593Smuzhiyun data->args.inode = data->inode = nfs_igrab_and_active(inode);
857*4882a593Smuzhiyun if (data->inode) {
858*4882a593Smuzhiyun data->lseg = pnfs_get_lseg(lseg);
859*4882a593Smuzhiyun if (data->lseg)
860*4882a593Smuzhiyun return data;
861*4882a593Smuzhiyun nfs_iput_and_deactive(data->inode);
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun kfree(data);
864*4882a593Smuzhiyun }
865*4882a593Smuzhiyun return NULL;
866*4882a593Smuzhiyun }
867*4882a593Smuzhiyun
868*4882a593Smuzhiyun static void
nfs42_free_layouterror_data(struct nfs42_layouterror_data * data)869*4882a593Smuzhiyun nfs42_free_layouterror_data(struct nfs42_layouterror_data *data)
870*4882a593Smuzhiyun {
871*4882a593Smuzhiyun pnfs_put_lseg(data->lseg);
872*4882a593Smuzhiyun nfs_iput_and_deactive(data->inode);
873*4882a593Smuzhiyun kfree(data);
874*4882a593Smuzhiyun }
875*4882a593Smuzhiyun
876*4882a593Smuzhiyun static void
nfs42_layouterror_prepare(struct rpc_task * task,void * calldata)877*4882a593Smuzhiyun nfs42_layouterror_prepare(struct rpc_task *task, void *calldata)
878*4882a593Smuzhiyun {
879*4882a593Smuzhiyun struct nfs42_layouterror_data *data = calldata;
880*4882a593Smuzhiyun struct inode *inode = data->inode;
881*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(inode);
882*4882a593Smuzhiyun struct pnfs_layout_hdr *lo = data->lseg->pls_layout;
883*4882a593Smuzhiyun unsigned i;
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun spin_lock(&inode->i_lock);
886*4882a593Smuzhiyun if (!pnfs_layout_is_valid(lo)) {
887*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
888*4882a593Smuzhiyun rpc_exit(task, 0);
889*4882a593Smuzhiyun return;
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun for (i = 0; i < data->args.num_errors; i++)
892*4882a593Smuzhiyun nfs4_stateid_copy(&data->args.errors[i].stateid,
893*4882a593Smuzhiyun &lo->plh_stateid);
894*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
895*4882a593Smuzhiyun nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
896*4882a593Smuzhiyun &data->res.seq_res, task);
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun
899*4882a593Smuzhiyun static void
nfs42_layouterror_done(struct rpc_task * task,void * calldata)900*4882a593Smuzhiyun nfs42_layouterror_done(struct rpc_task *task, void *calldata)
901*4882a593Smuzhiyun {
902*4882a593Smuzhiyun struct nfs42_layouterror_data *data = calldata;
903*4882a593Smuzhiyun struct inode *inode = data->inode;
904*4882a593Smuzhiyun struct pnfs_layout_hdr *lo = data->lseg->pls_layout;
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun if (!nfs4_sequence_done(task, &data->res.seq_res))
907*4882a593Smuzhiyun return;
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun switch (task->tk_status) {
910*4882a593Smuzhiyun case 0:
911*4882a593Smuzhiyun return;
912*4882a593Smuzhiyun case -NFS4ERR_BADHANDLE:
913*4882a593Smuzhiyun case -ESTALE:
914*4882a593Smuzhiyun pnfs_destroy_layout(NFS_I(inode));
915*4882a593Smuzhiyun break;
916*4882a593Smuzhiyun case -NFS4ERR_EXPIRED:
917*4882a593Smuzhiyun case -NFS4ERR_ADMIN_REVOKED:
918*4882a593Smuzhiyun case -NFS4ERR_DELEG_REVOKED:
919*4882a593Smuzhiyun case -NFS4ERR_STALE_STATEID:
920*4882a593Smuzhiyun case -NFS4ERR_BAD_STATEID:
921*4882a593Smuzhiyun spin_lock(&inode->i_lock);
922*4882a593Smuzhiyun if (pnfs_layout_is_valid(lo) &&
923*4882a593Smuzhiyun nfs4_stateid_match(&data->args.errors[0].stateid,
924*4882a593Smuzhiyun &lo->plh_stateid)) {
925*4882a593Smuzhiyun LIST_HEAD(head);
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun /*
928*4882a593Smuzhiyun * Mark the bad layout state as invalid, then retry
929*4882a593Smuzhiyun * with the current stateid.
930*4882a593Smuzhiyun */
931*4882a593Smuzhiyun pnfs_mark_layout_stateid_invalid(lo, &head);
932*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
933*4882a593Smuzhiyun pnfs_free_lseg_list(&head);
934*4882a593Smuzhiyun nfs_commit_inode(inode, 0);
935*4882a593Smuzhiyun } else
936*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
937*4882a593Smuzhiyun break;
938*4882a593Smuzhiyun case -NFS4ERR_OLD_STATEID:
939*4882a593Smuzhiyun spin_lock(&inode->i_lock);
940*4882a593Smuzhiyun if (pnfs_layout_is_valid(lo) &&
941*4882a593Smuzhiyun nfs4_stateid_match_other(&data->args.errors[0].stateid,
942*4882a593Smuzhiyun &lo->plh_stateid)) {
943*4882a593Smuzhiyun /* Do we need to delay before resending? */
944*4882a593Smuzhiyun if (!nfs4_stateid_is_newer(&lo->plh_stateid,
945*4882a593Smuzhiyun &data->args.errors[0].stateid))
946*4882a593Smuzhiyun rpc_delay(task, HZ);
947*4882a593Smuzhiyun rpc_restart_call_prepare(task);
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun spin_unlock(&inode->i_lock);
950*4882a593Smuzhiyun break;
951*4882a593Smuzhiyun case -ENOTSUPP:
952*4882a593Smuzhiyun case -EOPNOTSUPP:
953*4882a593Smuzhiyun NFS_SERVER(inode)->caps &= ~NFS_CAP_LAYOUTERROR;
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun
956*4882a593Smuzhiyun trace_nfs4_layouterror(inode, &data->args.errors[0].stateid,
957*4882a593Smuzhiyun task->tk_status);
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun static void
nfs42_layouterror_release(void * calldata)961*4882a593Smuzhiyun nfs42_layouterror_release(void *calldata)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun struct nfs42_layouterror_data *data = calldata;
964*4882a593Smuzhiyun
965*4882a593Smuzhiyun nfs42_free_layouterror_data(data);
966*4882a593Smuzhiyun }
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun static const struct rpc_call_ops nfs42_layouterror_ops = {
969*4882a593Smuzhiyun .rpc_call_prepare = nfs42_layouterror_prepare,
970*4882a593Smuzhiyun .rpc_call_done = nfs42_layouterror_done,
971*4882a593Smuzhiyun .rpc_release = nfs42_layouterror_release,
972*4882a593Smuzhiyun };
973*4882a593Smuzhiyun
nfs42_proc_layouterror(struct pnfs_layout_segment * lseg,const struct nfs42_layout_error * errors,size_t n)974*4882a593Smuzhiyun int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg,
975*4882a593Smuzhiyun const struct nfs42_layout_error *errors, size_t n)
976*4882a593Smuzhiyun {
977*4882a593Smuzhiyun struct inode *inode = lseg->pls_layout->plh_inode;
978*4882a593Smuzhiyun struct nfs42_layouterror_data *data;
979*4882a593Smuzhiyun struct rpc_task *task;
980*4882a593Smuzhiyun struct rpc_message msg = {
981*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTERROR],
982*4882a593Smuzhiyun };
983*4882a593Smuzhiyun struct rpc_task_setup task_setup = {
984*4882a593Smuzhiyun .rpc_message = &msg,
985*4882a593Smuzhiyun .callback_ops = &nfs42_layouterror_ops,
986*4882a593Smuzhiyun .flags = RPC_TASK_ASYNC,
987*4882a593Smuzhiyun };
988*4882a593Smuzhiyun unsigned int i;
989*4882a593Smuzhiyun
990*4882a593Smuzhiyun if (!nfs_server_capable(inode, NFS_CAP_LAYOUTERROR))
991*4882a593Smuzhiyun return -EOPNOTSUPP;
992*4882a593Smuzhiyun if (n > NFS42_LAYOUTERROR_MAX)
993*4882a593Smuzhiyun return -EINVAL;
994*4882a593Smuzhiyun data = nfs42_alloc_layouterror_data(lseg, GFP_NOFS);
995*4882a593Smuzhiyun if (!data)
996*4882a593Smuzhiyun return -ENOMEM;
997*4882a593Smuzhiyun for (i = 0; i < n; i++) {
998*4882a593Smuzhiyun data->args.errors[i] = errors[i];
999*4882a593Smuzhiyun data->args.num_errors++;
1000*4882a593Smuzhiyun data->res.num_errors++;
1001*4882a593Smuzhiyun }
1002*4882a593Smuzhiyun msg.rpc_argp = &data->args;
1003*4882a593Smuzhiyun msg.rpc_resp = &data->res;
1004*4882a593Smuzhiyun task_setup.callback_data = data;
1005*4882a593Smuzhiyun task_setup.rpc_client = NFS_SERVER(inode)->client;
1006*4882a593Smuzhiyun nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0);
1007*4882a593Smuzhiyun task = rpc_run_task(&task_setup);
1008*4882a593Smuzhiyun if (IS_ERR(task))
1009*4882a593Smuzhiyun return PTR_ERR(task);
1010*4882a593Smuzhiyun rpc_put_task(task);
1011*4882a593Smuzhiyun return 0;
1012*4882a593Smuzhiyun }
1013*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(nfs42_proc_layouterror);
1014*4882a593Smuzhiyun
_nfs42_proc_clone(struct rpc_message * msg,struct file * src_f,struct file * dst_f,struct nfs_lock_context * src_lock,struct nfs_lock_context * dst_lock,loff_t src_offset,loff_t dst_offset,loff_t count)1015*4882a593Smuzhiyun static int _nfs42_proc_clone(struct rpc_message *msg, struct file *src_f,
1016*4882a593Smuzhiyun struct file *dst_f, struct nfs_lock_context *src_lock,
1017*4882a593Smuzhiyun struct nfs_lock_context *dst_lock, loff_t src_offset,
1018*4882a593Smuzhiyun loff_t dst_offset, loff_t count)
1019*4882a593Smuzhiyun {
1020*4882a593Smuzhiyun struct inode *src_inode = file_inode(src_f);
1021*4882a593Smuzhiyun struct inode *dst_inode = file_inode(dst_f);
1022*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(dst_inode);
1023*4882a593Smuzhiyun struct nfs42_clone_args args = {
1024*4882a593Smuzhiyun .src_fh = NFS_FH(src_inode),
1025*4882a593Smuzhiyun .dst_fh = NFS_FH(dst_inode),
1026*4882a593Smuzhiyun .src_offset = src_offset,
1027*4882a593Smuzhiyun .dst_offset = dst_offset,
1028*4882a593Smuzhiyun .count = count,
1029*4882a593Smuzhiyun .dst_bitmask = server->cache_consistency_bitmask,
1030*4882a593Smuzhiyun };
1031*4882a593Smuzhiyun struct nfs42_clone_res res = {
1032*4882a593Smuzhiyun .server = server,
1033*4882a593Smuzhiyun };
1034*4882a593Smuzhiyun int status;
1035*4882a593Smuzhiyun
1036*4882a593Smuzhiyun msg->rpc_argp = &args;
1037*4882a593Smuzhiyun msg->rpc_resp = &res;
1038*4882a593Smuzhiyun
1039*4882a593Smuzhiyun status = nfs4_set_rw_stateid(&args.src_stateid, src_lock->open_context,
1040*4882a593Smuzhiyun src_lock, FMODE_READ);
1041*4882a593Smuzhiyun if (status) {
1042*4882a593Smuzhiyun if (status == -EAGAIN)
1043*4882a593Smuzhiyun status = -NFS4ERR_BAD_STATEID;
1044*4882a593Smuzhiyun return status;
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun status = nfs4_set_rw_stateid(&args.dst_stateid, dst_lock->open_context,
1047*4882a593Smuzhiyun dst_lock, FMODE_WRITE);
1048*4882a593Smuzhiyun if (status) {
1049*4882a593Smuzhiyun if (status == -EAGAIN)
1050*4882a593Smuzhiyun status = -NFS4ERR_BAD_STATEID;
1051*4882a593Smuzhiyun return status;
1052*4882a593Smuzhiyun }
1053*4882a593Smuzhiyun
1054*4882a593Smuzhiyun res.dst_fattr = nfs_alloc_fattr();
1055*4882a593Smuzhiyun if (!res.dst_fattr)
1056*4882a593Smuzhiyun return -ENOMEM;
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun status = nfs4_call_sync(server->client, server, msg,
1059*4882a593Smuzhiyun &args.seq_args, &res.seq_res, 0);
1060*4882a593Smuzhiyun if (status == 0)
1061*4882a593Smuzhiyun status = nfs_post_op_update_inode(dst_inode, res.dst_fattr);
1062*4882a593Smuzhiyun
1063*4882a593Smuzhiyun kfree(res.dst_fattr);
1064*4882a593Smuzhiyun return status;
1065*4882a593Smuzhiyun }
1066*4882a593Smuzhiyun
nfs42_proc_clone(struct file * src_f,struct file * dst_f,loff_t src_offset,loff_t dst_offset,loff_t count)1067*4882a593Smuzhiyun int nfs42_proc_clone(struct file *src_f, struct file *dst_f,
1068*4882a593Smuzhiyun loff_t src_offset, loff_t dst_offset, loff_t count)
1069*4882a593Smuzhiyun {
1070*4882a593Smuzhiyun struct rpc_message msg = {
1071*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLONE],
1072*4882a593Smuzhiyun };
1073*4882a593Smuzhiyun struct inode *inode = file_inode(src_f);
1074*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(file_inode(src_f));
1075*4882a593Smuzhiyun struct nfs_lock_context *src_lock;
1076*4882a593Smuzhiyun struct nfs_lock_context *dst_lock;
1077*4882a593Smuzhiyun struct nfs4_exception src_exception = { };
1078*4882a593Smuzhiyun struct nfs4_exception dst_exception = { };
1079*4882a593Smuzhiyun int err, err2;
1080*4882a593Smuzhiyun
1081*4882a593Smuzhiyun if (!nfs_server_capable(inode, NFS_CAP_CLONE))
1082*4882a593Smuzhiyun return -EOPNOTSUPP;
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun src_lock = nfs_get_lock_context(nfs_file_open_context(src_f));
1085*4882a593Smuzhiyun if (IS_ERR(src_lock))
1086*4882a593Smuzhiyun return PTR_ERR(src_lock);
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun src_exception.inode = file_inode(src_f);
1089*4882a593Smuzhiyun src_exception.state = src_lock->open_context->state;
1090*4882a593Smuzhiyun
1091*4882a593Smuzhiyun dst_lock = nfs_get_lock_context(nfs_file_open_context(dst_f));
1092*4882a593Smuzhiyun if (IS_ERR(dst_lock)) {
1093*4882a593Smuzhiyun err = PTR_ERR(dst_lock);
1094*4882a593Smuzhiyun goto out_put_src_lock;
1095*4882a593Smuzhiyun }
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun dst_exception.inode = file_inode(dst_f);
1098*4882a593Smuzhiyun dst_exception.state = dst_lock->open_context->state;
1099*4882a593Smuzhiyun
1100*4882a593Smuzhiyun do {
1101*4882a593Smuzhiyun err = _nfs42_proc_clone(&msg, src_f, dst_f, src_lock, dst_lock,
1102*4882a593Smuzhiyun src_offset, dst_offset, count);
1103*4882a593Smuzhiyun if (err == -ENOTSUPP || err == -EOPNOTSUPP) {
1104*4882a593Smuzhiyun NFS_SERVER(inode)->caps &= ~NFS_CAP_CLONE;
1105*4882a593Smuzhiyun err = -EOPNOTSUPP;
1106*4882a593Smuzhiyun break;
1107*4882a593Smuzhiyun }
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun err2 = nfs4_handle_exception(server, err, &src_exception);
1110*4882a593Smuzhiyun err = nfs4_handle_exception(server, err, &dst_exception);
1111*4882a593Smuzhiyun if (!err)
1112*4882a593Smuzhiyun err = err2;
1113*4882a593Smuzhiyun } while (src_exception.retry || dst_exception.retry);
1114*4882a593Smuzhiyun
1115*4882a593Smuzhiyun nfs_put_lock_context(dst_lock);
1116*4882a593Smuzhiyun out_put_src_lock:
1117*4882a593Smuzhiyun nfs_put_lock_context(src_lock);
1118*4882a593Smuzhiyun return err;
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun
1121*4882a593Smuzhiyun #define NFS4XATTR_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
1122*4882a593Smuzhiyun
_nfs42_proc_removexattr(struct inode * inode,const char * name)1123*4882a593Smuzhiyun static int _nfs42_proc_removexattr(struct inode *inode, const char *name)
1124*4882a593Smuzhiyun {
1125*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(inode);
1126*4882a593Smuzhiyun struct nfs42_removexattrargs args = {
1127*4882a593Smuzhiyun .fh = NFS_FH(inode),
1128*4882a593Smuzhiyun .xattr_name = name,
1129*4882a593Smuzhiyun };
1130*4882a593Smuzhiyun struct nfs42_removexattrres res;
1131*4882a593Smuzhiyun struct rpc_message msg = {
1132*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVEXATTR],
1133*4882a593Smuzhiyun .rpc_argp = &args,
1134*4882a593Smuzhiyun .rpc_resp = &res,
1135*4882a593Smuzhiyun };
1136*4882a593Smuzhiyun int ret;
1137*4882a593Smuzhiyun unsigned long timestamp = jiffies;
1138*4882a593Smuzhiyun
1139*4882a593Smuzhiyun ret = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
1140*4882a593Smuzhiyun &res.seq_res, 1);
1141*4882a593Smuzhiyun if (!ret)
1142*4882a593Smuzhiyun nfs4_update_changeattr(inode, &res.cinfo, timestamp, 0);
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun return ret;
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun
_nfs42_proc_setxattr(struct inode * inode,const char * name,const void * buf,size_t buflen,int flags)1147*4882a593Smuzhiyun static int _nfs42_proc_setxattr(struct inode *inode, const char *name,
1148*4882a593Smuzhiyun const void *buf, size_t buflen, int flags)
1149*4882a593Smuzhiyun {
1150*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(inode);
1151*4882a593Smuzhiyun struct page *pages[NFS4XATTR_MAXPAGES];
1152*4882a593Smuzhiyun struct nfs42_setxattrargs arg = {
1153*4882a593Smuzhiyun .fh = NFS_FH(inode),
1154*4882a593Smuzhiyun .xattr_pages = pages,
1155*4882a593Smuzhiyun .xattr_len = buflen,
1156*4882a593Smuzhiyun .xattr_name = name,
1157*4882a593Smuzhiyun .xattr_flags = flags,
1158*4882a593Smuzhiyun };
1159*4882a593Smuzhiyun struct nfs42_setxattrres res;
1160*4882a593Smuzhiyun struct rpc_message msg = {
1161*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETXATTR],
1162*4882a593Smuzhiyun .rpc_argp = &arg,
1163*4882a593Smuzhiyun .rpc_resp = &res,
1164*4882a593Smuzhiyun };
1165*4882a593Smuzhiyun int ret, np;
1166*4882a593Smuzhiyun unsigned long timestamp = jiffies;
1167*4882a593Smuzhiyun
1168*4882a593Smuzhiyun if (buflen > server->sxasize)
1169*4882a593Smuzhiyun return -ERANGE;
1170*4882a593Smuzhiyun
1171*4882a593Smuzhiyun if (buflen > 0) {
1172*4882a593Smuzhiyun np = nfs4_buf_to_pages_noslab(buf, buflen, arg.xattr_pages);
1173*4882a593Smuzhiyun if (np < 0)
1174*4882a593Smuzhiyun return np;
1175*4882a593Smuzhiyun } else
1176*4882a593Smuzhiyun np = 0;
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args,
1179*4882a593Smuzhiyun &res.seq_res, 1);
1180*4882a593Smuzhiyun
1181*4882a593Smuzhiyun for (; np > 0; np--)
1182*4882a593Smuzhiyun put_page(pages[np - 1]);
1183*4882a593Smuzhiyun
1184*4882a593Smuzhiyun if (!ret)
1185*4882a593Smuzhiyun nfs4_update_changeattr(inode, &res.cinfo, timestamp, 0);
1186*4882a593Smuzhiyun
1187*4882a593Smuzhiyun return ret;
1188*4882a593Smuzhiyun }
1189*4882a593Smuzhiyun
_nfs42_proc_getxattr(struct inode * inode,const char * name,void * buf,size_t buflen)1190*4882a593Smuzhiyun static ssize_t _nfs42_proc_getxattr(struct inode *inode, const char *name,
1191*4882a593Smuzhiyun void *buf, size_t buflen)
1192*4882a593Smuzhiyun {
1193*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(inode);
1194*4882a593Smuzhiyun struct page *pages[NFS4XATTR_MAXPAGES] = {};
1195*4882a593Smuzhiyun struct nfs42_getxattrargs arg = {
1196*4882a593Smuzhiyun .fh = NFS_FH(inode),
1197*4882a593Smuzhiyun .xattr_pages = pages,
1198*4882a593Smuzhiyun .xattr_len = buflen,
1199*4882a593Smuzhiyun .xattr_name = name,
1200*4882a593Smuzhiyun };
1201*4882a593Smuzhiyun struct nfs42_getxattrres res;
1202*4882a593Smuzhiyun struct rpc_message msg = {
1203*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETXATTR],
1204*4882a593Smuzhiyun .rpc_argp = &arg,
1205*4882a593Smuzhiyun .rpc_resp = &res,
1206*4882a593Smuzhiyun };
1207*4882a593Smuzhiyun int ret, np;
1208*4882a593Smuzhiyun
1209*4882a593Smuzhiyun ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args,
1210*4882a593Smuzhiyun &res.seq_res, 0);
1211*4882a593Smuzhiyun if (ret < 0)
1212*4882a593Smuzhiyun return ret;
1213*4882a593Smuzhiyun
1214*4882a593Smuzhiyun /*
1215*4882a593Smuzhiyun * Normally, the caching is done one layer up, but for successful
1216*4882a593Smuzhiyun * RPCS, always cache the result here, even if the caller was
1217*4882a593Smuzhiyun * just querying the length, or if the reply was too big for
1218*4882a593Smuzhiyun * the caller. This avoids a second RPC in the case of the
1219*4882a593Smuzhiyun * common query-alloc-retrieve cycle for xattrs.
1220*4882a593Smuzhiyun *
1221*4882a593Smuzhiyun * Note that xattr_len is always capped to XATTR_SIZE_MAX.
1222*4882a593Smuzhiyun */
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun nfs4_xattr_cache_add(inode, name, NULL, pages, res.xattr_len);
1225*4882a593Smuzhiyun
1226*4882a593Smuzhiyun if (buflen) {
1227*4882a593Smuzhiyun if (res.xattr_len > buflen)
1228*4882a593Smuzhiyun return -ERANGE;
1229*4882a593Smuzhiyun _copy_from_pages(buf, pages, 0, res.xattr_len);
1230*4882a593Smuzhiyun }
1231*4882a593Smuzhiyun
1232*4882a593Smuzhiyun np = DIV_ROUND_UP(res.xattr_len, PAGE_SIZE);
1233*4882a593Smuzhiyun while (--np >= 0)
1234*4882a593Smuzhiyun __free_page(pages[np]);
1235*4882a593Smuzhiyun
1236*4882a593Smuzhiyun return res.xattr_len;
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun
_nfs42_proc_listxattrs(struct inode * inode,void * buf,size_t buflen,u64 * cookiep,bool * eofp)1239*4882a593Smuzhiyun static ssize_t _nfs42_proc_listxattrs(struct inode *inode, void *buf,
1240*4882a593Smuzhiyun size_t buflen, u64 *cookiep, bool *eofp)
1241*4882a593Smuzhiyun {
1242*4882a593Smuzhiyun struct nfs_server *server = NFS_SERVER(inode);
1243*4882a593Smuzhiyun struct page **pages;
1244*4882a593Smuzhiyun struct nfs42_listxattrsargs arg = {
1245*4882a593Smuzhiyun .fh = NFS_FH(inode),
1246*4882a593Smuzhiyun .cookie = *cookiep,
1247*4882a593Smuzhiyun };
1248*4882a593Smuzhiyun struct nfs42_listxattrsres res = {
1249*4882a593Smuzhiyun .eof = false,
1250*4882a593Smuzhiyun .xattr_buf = buf,
1251*4882a593Smuzhiyun .xattr_len = buflen,
1252*4882a593Smuzhiyun };
1253*4882a593Smuzhiyun struct rpc_message msg = {
1254*4882a593Smuzhiyun .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LISTXATTRS],
1255*4882a593Smuzhiyun .rpc_argp = &arg,
1256*4882a593Smuzhiyun .rpc_resp = &res,
1257*4882a593Smuzhiyun };
1258*4882a593Smuzhiyun u32 xdrlen;
1259*4882a593Smuzhiyun int ret, np, i;
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun
1262*4882a593Smuzhiyun ret = -ENOMEM;
1263*4882a593Smuzhiyun res.scratch = alloc_page(GFP_KERNEL);
1264*4882a593Smuzhiyun if (!res.scratch)
1265*4882a593Smuzhiyun goto out;
1266*4882a593Smuzhiyun
1267*4882a593Smuzhiyun xdrlen = nfs42_listxattr_xdrsize(buflen);
1268*4882a593Smuzhiyun if (xdrlen > server->lxasize)
1269*4882a593Smuzhiyun xdrlen = server->lxasize;
1270*4882a593Smuzhiyun np = xdrlen / PAGE_SIZE + 1;
1271*4882a593Smuzhiyun
1272*4882a593Smuzhiyun pages = kcalloc(np, sizeof(struct page *), GFP_KERNEL);
1273*4882a593Smuzhiyun if (!pages)
1274*4882a593Smuzhiyun goto out_free_scratch;
1275*4882a593Smuzhiyun for (i = 0; i < np; i++) {
1276*4882a593Smuzhiyun pages[i] = alloc_page(GFP_KERNEL);
1277*4882a593Smuzhiyun if (!pages[i])
1278*4882a593Smuzhiyun goto out_free_pages;
1279*4882a593Smuzhiyun }
1280*4882a593Smuzhiyun
1281*4882a593Smuzhiyun arg.xattr_pages = pages;
1282*4882a593Smuzhiyun arg.count = xdrlen;
1283*4882a593Smuzhiyun
1284*4882a593Smuzhiyun ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args,
1285*4882a593Smuzhiyun &res.seq_res, 0);
1286*4882a593Smuzhiyun
1287*4882a593Smuzhiyun if (ret >= 0) {
1288*4882a593Smuzhiyun ret = res.copied;
1289*4882a593Smuzhiyun *cookiep = res.cookie;
1290*4882a593Smuzhiyun *eofp = res.eof;
1291*4882a593Smuzhiyun }
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun out_free_pages:
1294*4882a593Smuzhiyun while (--np >= 0) {
1295*4882a593Smuzhiyun if (pages[np])
1296*4882a593Smuzhiyun __free_page(pages[np]);
1297*4882a593Smuzhiyun }
1298*4882a593Smuzhiyun kfree(pages);
1299*4882a593Smuzhiyun out_free_scratch:
1300*4882a593Smuzhiyun __free_page(res.scratch);
1301*4882a593Smuzhiyun out:
1302*4882a593Smuzhiyun return ret;
1303*4882a593Smuzhiyun
1304*4882a593Smuzhiyun }
1305*4882a593Smuzhiyun
nfs42_proc_getxattr(struct inode * inode,const char * name,void * buf,size_t buflen)1306*4882a593Smuzhiyun ssize_t nfs42_proc_getxattr(struct inode *inode, const char *name,
1307*4882a593Smuzhiyun void *buf, size_t buflen)
1308*4882a593Smuzhiyun {
1309*4882a593Smuzhiyun struct nfs4_exception exception = { };
1310*4882a593Smuzhiyun ssize_t err;
1311*4882a593Smuzhiyun
1312*4882a593Smuzhiyun do {
1313*4882a593Smuzhiyun err = _nfs42_proc_getxattr(inode, name, buf, buflen);
1314*4882a593Smuzhiyun if (err >= 0)
1315*4882a593Smuzhiyun break;
1316*4882a593Smuzhiyun err = nfs4_handle_exception(NFS_SERVER(inode), err,
1317*4882a593Smuzhiyun &exception);
1318*4882a593Smuzhiyun } while (exception.retry);
1319*4882a593Smuzhiyun
1320*4882a593Smuzhiyun return err;
1321*4882a593Smuzhiyun }
1322*4882a593Smuzhiyun
nfs42_proc_setxattr(struct inode * inode,const char * name,const void * buf,size_t buflen,int flags)1323*4882a593Smuzhiyun int nfs42_proc_setxattr(struct inode *inode, const char *name,
1324*4882a593Smuzhiyun const void *buf, size_t buflen, int flags)
1325*4882a593Smuzhiyun {
1326*4882a593Smuzhiyun struct nfs4_exception exception = { };
1327*4882a593Smuzhiyun int err;
1328*4882a593Smuzhiyun
1329*4882a593Smuzhiyun do {
1330*4882a593Smuzhiyun err = _nfs42_proc_setxattr(inode, name, buf, buflen, flags);
1331*4882a593Smuzhiyun if (!err)
1332*4882a593Smuzhiyun break;
1333*4882a593Smuzhiyun err = nfs4_handle_exception(NFS_SERVER(inode), err,
1334*4882a593Smuzhiyun &exception);
1335*4882a593Smuzhiyun } while (exception.retry);
1336*4882a593Smuzhiyun
1337*4882a593Smuzhiyun return err;
1338*4882a593Smuzhiyun }
1339*4882a593Smuzhiyun
nfs42_proc_listxattrs(struct inode * inode,void * buf,size_t buflen,u64 * cookiep,bool * eofp)1340*4882a593Smuzhiyun ssize_t nfs42_proc_listxattrs(struct inode *inode, void *buf,
1341*4882a593Smuzhiyun size_t buflen, u64 *cookiep, bool *eofp)
1342*4882a593Smuzhiyun {
1343*4882a593Smuzhiyun struct nfs4_exception exception = { };
1344*4882a593Smuzhiyun ssize_t err;
1345*4882a593Smuzhiyun
1346*4882a593Smuzhiyun do {
1347*4882a593Smuzhiyun err = _nfs42_proc_listxattrs(inode, buf, buflen,
1348*4882a593Smuzhiyun cookiep, eofp);
1349*4882a593Smuzhiyun if (err >= 0)
1350*4882a593Smuzhiyun break;
1351*4882a593Smuzhiyun err = nfs4_handle_exception(NFS_SERVER(inode), err,
1352*4882a593Smuzhiyun &exception);
1353*4882a593Smuzhiyun } while (exception.retry);
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun return err;
1356*4882a593Smuzhiyun }
1357*4882a593Smuzhiyun
nfs42_proc_removexattr(struct inode * inode,const char * name)1358*4882a593Smuzhiyun int nfs42_proc_removexattr(struct inode *inode, const char *name)
1359*4882a593Smuzhiyun {
1360*4882a593Smuzhiyun struct nfs4_exception exception = { };
1361*4882a593Smuzhiyun int err;
1362*4882a593Smuzhiyun
1363*4882a593Smuzhiyun do {
1364*4882a593Smuzhiyun err = _nfs42_proc_removexattr(inode, name);
1365*4882a593Smuzhiyun if (!err)
1366*4882a593Smuzhiyun break;
1367*4882a593Smuzhiyun err = nfs4_handle_exception(NFS_SERVER(inode), err,
1368*4882a593Smuzhiyun &exception);
1369*4882a593Smuzhiyun } while (exception.retry);
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun return err;
1372*4882a593Smuzhiyun }
1373