blob: 82e5ed2ee6ba1e693508ccc8e66dc1cd847d5311 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * fs/nfs/nfs4proc.c
3 *
4 * Client-side procedure declarations for NFSv4.
5 *
6 * Copyright (c) 2002 The Regents of the University of Michigan.
7 * All rights reserved.
8 *
9 * Kendrick Smith <kmsmith@umich.edu>
10 * Andy Adamson <andros@umich.edu>
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its
22 * contributors may be used to endorse or promote products derived
23 * from this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
32 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include <linux/delay.h>
40#include <linux/errno.h>
41#include <linux/string.h>
Trond Myklebust652f89f2011-12-09 19:05:58 -050042#include <linux/ratelimit.h>
43#include <linux/printk.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090044#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <linux/sunrpc/clnt.h>
46#include <linux/nfs.h>
47#include <linux/nfs4.h>
48#include <linux/nfs_fs.h>
49#include <linux/nfs_page.h>
Bryan Schumaker9b7160c2011-04-13 14:31:30 -040050#include <linux/nfs_mount.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051#include <linux/namei.h>
Trond Myklebust02a913a2005-10-18 14:20:17 -070052#include <linux/mount.h>
Benny Halevy99fe60d2009-04-01 09:22:29 -040053#include <linux/module.h>
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +000054#include <linux/xattr.h>
Andy Adamsonc7a360b2011-01-25 19:15:32 -050055#include <linux/utsname.h>
Jeff Laytond3103102011-12-01 22:44:39 +010056#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Trond Myklebust4ce79712005-06-22 17:16:21 +000058#include "nfs4_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#include "delegation.h"
Trond Myklebust101070c2008-02-19 20:04:23 -050060#include "internal.h"
Chuck Lever006ea732006-03-20 13:44:14 -050061#include "iostat.h"
Andy Adamsonfc931582009-04-01 09:22:31 -040062#include "callback.h"
Andy Adamsonb1f69b72010-10-20 00:18:03 -040063#include "pnfs.h"
Chuck Leverf0920752012-05-21 22:45:41 -040064#include "netns.h"
Anna Schumaker40c64c22015-04-15 13:00:05 -040065#include "nfs4idmap.h"
Trond Myklebust73e39aa2012-11-26 12:49:34 -050066#include "nfs4session.h"
David Howellsde242c02012-12-20 21:52:38 +000067#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Trond Myklebustc6d01c62013-08-09 11:51:26 -040069#include "nfs4trace.h"
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#define NFSDBG_FACILITY NFSDBG_PROC
72
Trond Myklebust2066fe82006-09-15 08:30:46 -040073#define NFS4_POLL_RETRY_MIN (HZ/10)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define NFS4_POLL_RETRY_MAX (15*HZ)
75
Tigran Mkrtchyana1d1c4f2016-05-12 11:16:38 +020076/* file attributes which can be mapped to nfs attributes */
77#define NFS4_VALID_ATTRS (ATTR_MODE \
78 | ATTR_UID \
79 | ATTR_GID \
80 | ATTR_SIZE \
81 | ATTR_ATIME \
82 | ATTR_MTIME \
83 | ATTR_CTIME \
84 | ATTR_ATIME_SET \
85 | ATTR_MTIME_SET)
86
Trond Myklebustcdd4e682006-01-03 09:55:12 +010087struct nfs4_opendata;
Trond Myklebust864472e2006-01-03 09:55:15 +010088static int _nfs4_proc_open(struct nfs4_opendata *data);
Alexandros Batsakisb2579572009-12-14 21:27:57 -080089static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
Chuck Lever81934dd2012-03-01 17:01:57 -050091static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
David Quigley1775fd32013-05-22 12:50:42 -040092static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label);
93static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label);
Trond Myklebust0ab64e02010-04-16 16:22:51 -040094static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
95 struct nfs_fattr *fattr, struct iattr *sattr,
NeilBrown29b59f92016-10-13 15:26:47 +110096 struct nfs_open_context *ctx, struct nfs4_label *ilabel,
David Quigley1775fd32013-05-22 12:50:42 -040097 struct nfs4_label *olabel);
Bryan Schumakerf062eb62011-06-02 14:59:10 -040098#ifdef CONFIG_NFS_V4_1
Trond Myklebust3be0f80b2017-10-19 15:46:45 -040099static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
100 struct rpc_cred *cred,
101 struct nfs4_slot *slot,
102 bool is_privileged);
Trond Myklebustab7cb0d2013-05-20 11:20:27 -0400103static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *,
104 struct rpc_cred *);
Trond Myklebustf0b0bf82016-09-22 13:39:04 -0400105static int nfs41_free_stateid(struct nfs_server *, const nfs4_stateid *,
106 struct rpc_cred *, bool);
Bryan Schumakerf062eb62011-06-02 14:59:10 -0400107#endif
David Quigleyaa9c2662013-05-22 12:50:44 -0400108
109#ifdef CONFIG_NFS_V4_SECURITY_LABEL
110static inline struct nfs4_label *
111nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
112 struct iattr *sattr, struct nfs4_label *label)
113{
114 int err;
115
116 if (label == NULL)
117 return NULL;
118
119 if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL) == 0)
120 return NULL;
121
David Quigleyaa9c2662013-05-22 12:50:44 -0400122 err = security_dentry_init_security(dentry, sattr->ia_mode,
123 &dentry->d_name, (void **)&label->label, &label->len);
124 if (err == 0)
125 return label;
126
127 return NULL;
128}
129static inline void
130nfs4_label_release_security(struct nfs4_label *label)
131{
132 if (label)
133 security_release_secctx(label->label, label->len);
134}
135static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
136{
137 if (label)
138 return server->attr_bitmask;
139
140 return server->attr_bitmask_nl;
141}
142#else
143static inline struct nfs4_label *
144nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
145 struct iattr *sattr, struct nfs4_label *l)
146{ return NULL; }
147static inline void
148nfs4_label_release_security(struct nfs4_label *label)
149{ return; }
150static inline u32 *
151nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
152{ return server->attr_bitmask; }
153#endif
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155/* Prevent leaks of NFSv4 errors into userland */
WANG Cong46f72f52008-12-30 16:35:55 -0500156static int nfs4_map_errors(int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157{
Trond Myklebust52567b02009-10-23 14:46:42 -0400158 if (err >= -1000)
159 return err;
160 switch (err) {
161 case -NFS4ERR_RESOURCE:
Weston Andros Adamson30005122013-02-28 20:30:10 -0500162 case -NFS4ERR_LAYOUTTRYLATER:
163 case -NFS4ERR_RECALLCONFLICT:
Trond Myklebust52567b02009-10-23 14:46:42 -0400164 return -EREMOTEIO;
Bryan Schumaker7ebb9312011-03-24 17:12:30 +0000165 case -NFS4ERR_WRONGSEC:
Weston Andros Adamson88975382013-08-13 16:37:38 -0400166 case -NFS4ERR_WRONG_CRED:
Bryan Schumaker7ebb9312011-03-24 17:12:30 +0000167 return -EPERM;
Trond Myklebust3ddeb7c2011-02-22 15:44:31 -0800168 case -NFS4ERR_BADOWNER:
169 case -NFS4ERR_BADNAME:
170 return -EINVAL;
Trond Myklebustfb13bfa2012-05-28 11:36:28 -0400171 case -NFS4ERR_SHARE_DENIED:
172 return -EACCES;
Steve Dicksonf25efd82012-06-06 14:12:07 -0400173 case -NFS4ERR_MINOR_VERS_MISMATCH:
174 return -EPROTONOSUPPORT;
Trond Myklebust6e3cf242013-03-23 15:22:45 -0400175 case -NFS4ERR_FILE_OPEN:
176 return -EBUSY;
Trond Myklebust52567b02009-10-23 14:46:42 -0400177 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 dprintk("%s could not handle NFSv4 error %d\n",
Harvey Harrison3110ff82008-05-02 13:42:44 -0700179 __func__, -err);
Trond Myklebust52567b02009-10-23 14:46:42 -0400180 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 }
Trond Myklebust52567b02009-10-23 14:46:42 -0400182 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183}
184
185/*
186 * This is our standard bitmap for GETATTR requests.
187 */
Trond Myklebust1549210f2012-06-05 09:16:47 -0400188const u32 nfs4_fattr_bitmap[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 FATTR4_WORD0_TYPE
190 | FATTR4_WORD0_CHANGE
191 | FATTR4_WORD0_SIZE
192 | FATTR4_WORD0_FSID
193 | FATTR4_WORD0_FILEID,
194 FATTR4_WORD1_MODE
195 | FATTR4_WORD1_NUMLINKS
196 | FATTR4_WORD1_OWNER
197 | FATTR4_WORD1_OWNER_GROUP
198 | FATTR4_WORD1_RAWDEV
199 | FATTR4_WORD1_SPACE_USED
200 | FATTR4_WORD1_TIME_ACCESS
201 | FATTR4_WORD1_TIME_METADATA
Anna Schumakerea96d1e2015-04-03 14:35:59 -0400202 | FATTR4_WORD1_TIME_MODIFY
203 | FATTR4_WORD1_MOUNTED_ON_FILEID,
David Quigleyaa9c2662013-05-22 12:50:44 -0400204#ifdef CONFIG_NFS_V4_SECURITY_LABEL
205 FATTR4_WORD2_SECURITY_LABEL
206#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207};
208
Trond Myklebust1549210f2012-06-05 09:16:47 -0400209static const u32 nfs4_pnfs_open_bitmap[3] = {
210 FATTR4_WORD0_TYPE
211 | FATTR4_WORD0_CHANGE
212 | FATTR4_WORD0_SIZE
213 | FATTR4_WORD0_FSID
214 | FATTR4_WORD0_FILEID,
215 FATTR4_WORD1_MODE
216 | FATTR4_WORD1_NUMLINKS
217 | FATTR4_WORD1_OWNER
218 | FATTR4_WORD1_OWNER_GROUP
219 | FATTR4_WORD1_RAWDEV
220 | FATTR4_WORD1_SPACE_USED
221 | FATTR4_WORD1_TIME_ACCESS
222 | FATTR4_WORD1_TIME_METADATA
223 | FATTR4_WORD1_TIME_MODIFY,
224 FATTR4_WORD2_MDSTHRESHOLD
Trond Myklebust95864c92015-12-26 15:06:03 -0500225#ifdef CONFIG_NFS_V4_SECURITY_LABEL
226 | FATTR4_WORD2_SECURITY_LABEL
227#endif
Trond Myklebust1549210f2012-06-05 09:16:47 -0400228};
229
Andy Adamsone23008e2012-10-02 21:07:32 -0400230static const u32 nfs4_open_noattr_bitmap[3] = {
231 FATTR4_WORD0_TYPE
Andy Adamsone23008e2012-10-02 21:07:32 -0400232 | FATTR4_WORD0_FILEID,
233};
234
David Quigleya09df2c2013-05-22 12:50:41 -0400235const u32 nfs4_statfs_bitmap[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 FATTR4_WORD0_FILES_AVAIL
237 | FATTR4_WORD0_FILES_FREE
238 | FATTR4_WORD0_FILES_TOTAL,
239 FATTR4_WORD1_SPACE_AVAIL
240 | FATTR4_WORD1_SPACE_FREE
241 | FATTR4_WORD1_SPACE_TOTAL
242};
243
David Quigleya09df2c2013-05-22 12:50:41 -0400244const u32 nfs4_pathconf_bitmap[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 FATTR4_WORD0_MAXLINK
246 | FATTR4_WORD0_MAXNAME,
247 0
248};
249
Fred Isamandae100c2011-07-30 20:52:37 -0400250const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 | FATTR4_WORD0_MAXREAD
252 | FATTR4_WORD0_MAXWRITE
253 | FATTR4_WORD0_LEASE_TIME,
Ricardo Labiaga55b6e772010-10-12 16:30:06 -0700254 FATTR4_WORD1_TIME_DELTA
Fred Isamandae100c2011-07-30 20:52:37 -0400255 | FATTR4_WORD1_FS_LAYOUT_TYPES,
256 FATTR4_WORD2_LAYOUT_BLKSIZE
Peng Tao2a92ee92015-09-26 02:24:37 +0800257 | FATTR4_WORD2_CLONE_BLKSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258};
259
David Quigleya09df2c2013-05-22 12:50:41 -0400260const u32 nfs4_fs_locations_bitmap[3] = {
Manoj Naik830b8e32006-06-09 09:34:25 -0400261 FATTR4_WORD0_TYPE
262 | FATTR4_WORD0_CHANGE
263 | FATTR4_WORD0_SIZE
264 | FATTR4_WORD0_FSID
265 | FATTR4_WORD0_FILEID
266 | FATTR4_WORD0_FS_LOCATIONS,
267 FATTR4_WORD1_MODE
268 | FATTR4_WORD1_NUMLINKS
269 | FATTR4_WORD1_OWNER
270 | FATTR4_WORD1_OWNER_GROUP
271 | FATTR4_WORD1_RAWDEV
272 | FATTR4_WORD1_SPACE_USED
273 | FATTR4_WORD1_TIME_ACCESS
274 | FATTR4_WORD1_TIME_METADATA
275 | FATTR4_WORD1_TIME_MODIFY
David Quigleya09df2c2013-05-22 12:50:41 -0400276 | FATTR4_WORD1_MOUNTED_ON_FILEID,
Manoj Naik830b8e32006-06-09 09:34:25 -0400277};
278
Al Virobc4785c2006-10-19 23:28:51 -0700279static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 struct nfs4_readdir_arg *readdir)
281{
Anna Schumaker18fe6a22017-06-16 12:06:59 -0400282 unsigned int attrs = FATTR4_WORD0_FILEID | FATTR4_WORD0_TYPE;
Al Viro0dbb4c62006-10-19 23:28:49 -0700283 __be32 *start, *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 if (cookie > 2) {
Adrian Bunkb7ef1952005-06-22 17:16:28 +0000286 readdir->cookie = cookie;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));
288 return;
289 }
290
291 readdir->cookie = 0;
292 memset(&readdir->verifier, 0, sizeof(readdir->verifier));
293 if (cookie == 2)
294 return;
295
296 /*
297 * NFSv4 servers do not return entries for '.' and '..'
298 * Therefore, we fake these entries here. We let '.'
299 * have cookie 0 and '..' have cookie 1. Note that
300 * when talking to the server, we always send cookie 0
301 * instead of 1 or 2.
302 */
Cong Wang2b86ce22011-11-25 23:14:33 +0800303 start = p = kmap_atomic(*readdir->pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304
305 if (cookie == 0) {
306 *p++ = xdr_one; /* next */
307 *p++ = xdr_zero; /* cookie, first word */
308 *p++ = xdr_one; /* cookie, second word */
309 *p++ = xdr_one; /* entry len */
310 memcpy(p, ".\0\0\0", 4); /* entry */
311 p++;
312 *p++ = xdr_one; /* bitmap length */
Anna Schumaker18fe6a22017-06-16 12:06:59 -0400313 *p++ = htonl(attrs); /* bitmap */
314 *p++ = htonl(12); /* attribute buffer length */
315 *p++ = htonl(NF4DIR);
David Howells2b0143b2015-03-17 22:25:59 +0000316 p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 }
318
319 *p++ = xdr_one; /* next */
320 *p++ = xdr_zero; /* cookie, first word */
321 *p++ = xdr_two; /* cookie, second word */
322 *p++ = xdr_two; /* entry len */
323 memcpy(p, "..\0\0", 4); /* entry */
324 p++;
325 *p++ = xdr_one; /* bitmap length */
Anna Schumaker18fe6a22017-06-16 12:06:59 -0400326 *p++ = htonl(attrs); /* bitmap */
327 *p++ = htonl(12); /* attribute buffer length */
328 *p++ = htonl(NF4DIR);
David Howells2b0143b2015-03-17 22:25:59 +0000329 p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry->d_parent)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 readdir->pgbase = (char *)p - (char *)start;
332 readdir->count -= readdir->pgbase;
Cong Wang2b86ce22011-11-25 23:14:33 +0800333 kunmap_atomic(start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
Trond Myklebust26d36302016-09-22 13:39:05 -0400336static void nfs4_test_and_free_stateid(struct nfs_server *server,
337 nfs4_stateid *stateid,
338 struct rpc_cred *cred)
339{
340 const struct nfs4_minor_version_ops *ops = server->nfs_client->cl_mvops;
341
342 ops->test_and_free_expired(server, stateid, cred);
343}
344
345static void __nfs4_free_revoked_stateid(struct nfs_server *server,
346 nfs4_stateid *stateid,
347 struct rpc_cred *cred)
348{
349 stateid->type = NFS4_REVOKED_STATEID_TYPE;
350 nfs4_test_and_free_stateid(server, stateid, cred);
351}
352
353static void nfs4_free_revoked_stateid(struct nfs_server *server,
354 const nfs4_stateid *stateid,
355 struct rpc_cred *cred)
356{
357 nfs4_stateid tmp;
358
359 nfs4_stateid_copy(&tmp, stateid);
360 __nfs4_free_revoked_stateid(server, &tmp, cred);
361}
362
NeilBrown8478eaa2014-09-18 16:09:27 +1000363static long nfs4_update_delay(long *timeout)
364{
365 long ret;
366 if (!timeout)
367 return NFS4_POLL_RETRY_MAX;
368 if (*timeout <= 0)
369 *timeout = NFS4_POLL_RETRY_MIN;
370 if (*timeout > NFS4_POLL_RETRY_MAX)
371 *timeout = NFS4_POLL_RETRY_MAX;
372 ret = *timeout;
373 *timeout <<= 1;
374 return ret;
375}
376
Trond Myklebust65de8722008-12-23 15:21:44 -0500377static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
378{
379 int res = 0;
380
381 might_sleep();
382
NeilBrown8478eaa2014-09-18 16:09:27 +1000383 freezable_schedule_timeout_killable_unsafe(
384 nfs4_update_delay(timeout));
Trond Myklebust65de8722008-12-23 15:21:44 -0500385 if (fatal_signal_pending(current))
386 res = -ERESTARTSYS;
Trond Myklebust65de8722008-12-23 15:21:44 -0500387 return res;
388}
389
390/* This is the error handling routine for processes that are allowed
391 * to sleep.
392 */
Trond Myklebustb3c2aa02015-09-20 14:32:45 -0400393static int nfs4_do_handle_exception(struct nfs_server *server,
394 int errorcode, struct nfs4_exception *exception)
Trond Myklebust65de8722008-12-23 15:21:44 -0500395{
396 struct nfs_client *clp = server->nfs_client;
Trond Myklebust9e33bed2008-12-23 15:21:46 -0500397 struct nfs4_state *state = exception->state;
Trond Myklebust8487c472016-06-26 08:44:35 -0400398 const nfs4_stateid *stateid = exception->stateid;
Trond Myklebust3114ea72012-03-07 16:39:06 -0500399 struct inode *inode = exception->inode;
Trond Myklebust65de8722008-12-23 15:21:44 -0500400 int ret = errorcode;
401
Trond Myklebustb3c2aa02015-09-20 14:32:45 -0400402 exception->delay = 0;
403 exception->recovering = 0;
Trond Myklebust65de8722008-12-23 15:21:44 -0500404 exception->retry = 0;
Trond Myklebust272289a2016-09-22 13:39:15 -0400405
406 if (stateid == NULL && state != NULL)
407 stateid = &state->stateid;
408
Trond Myklebust65de8722008-12-23 15:21:44 -0500409 switch(errorcode) {
410 case 0:
411 return 0;
Trond Myklebust5ba12442015-06-16 11:26:35 -0400412 case -NFS4ERR_DELEG_REVOKED:
413 case -NFS4ERR_ADMIN_REVOKED:
Trond Myklebust272289a2016-09-22 13:39:15 -0400414 case -NFS4ERR_EXPIRED:
Trond Myklebust5ba12442015-06-16 11:26:35 -0400415 case -NFS4ERR_BAD_STATEID:
Trond Myklebust272289a2016-09-22 13:39:15 -0400416 if (inode != NULL && stateid != NULL) {
417 nfs_inode_find_state_and_recover(inode,
418 stateid);
419 goto wait_on_recovery;
420 }
421 case -NFS4ERR_OPENMODE:
Trond Myklebust8487c472016-06-26 08:44:35 -0400422 if (inode) {
423 int err;
424
425 err = nfs_async_inode_return_delegation(inode,
426 stateid);
427 if (err == 0)
428 goto wait_on_recovery;
429 if (stateid != NULL && stateid->type == NFS4_DELEGATION_STATEID_TYPE) {
430 exception->retry = 1;
431 break;
432 }
433 }
Trond Myklebust3114ea72012-03-07 16:39:06 -0500434 if (state == NULL)
435 break;
Trond Myklebust5d422302013-03-14 16:57:48 -0400436 ret = nfs4_schedule_stateid_recovery(server, state);
437 if (ret < 0)
438 break;
Trond Myklebust3114ea72012-03-07 16:39:06 -0500439 goto wait_on_recovery;
Trond Myklebust65de8722008-12-23 15:21:44 -0500440 case -NFS4ERR_STALE_STATEID:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -0500441 case -NFS4ERR_STALE_CLIENTID:
Trond Myklebust0400a6b2011-03-09 16:00:53 -0500442 nfs4_schedule_lease_recovery(clp);
443 goto wait_on_recovery;
Chuck Lever519ae252013-10-17 14:13:19 -0400444 case -NFS4ERR_MOVED:
445 ret = nfs4_schedule_migration_recovery(server);
446 if (ret < 0)
447 break;
448 goto wait_on_recovery;
Chuck Lever8ef2f8d2013-10-17 14:13:41 -0400449 case -NFS4ERR_LEASE_MOVED:
450 nfs4_schedule_lease_moved_recovery(clp);
451 goto wait_on_recovery;
Trond Myklebust03391692010-01-26 15:42:38 -0500452#if defined(CONFIG_NFS_V4_1)
Andy Adamson4745e312009-04-01 09:22:42 -0400453 case -NFS4ERR_BADSESSION:
454 case -NFS4ERR_BADSLOT:
455 case -NFS4ERR_BAD_HIGH_SLOT:
456 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
457 case -NFS4ERR_DEADSESSION:
458 case -NFS4ERR_SEQ_FALSE_RETRY:
459 case -NFS4ERR_SEQ_MISORDERED:
460 dprintk("%s ERROR: %d Reset session\n", __func__,
461 errorcode);
Trond Myklebust9f594792012-05-27 13:02:53 -0400462 nfs4_schedule_session_recovery(clp->cl_session, errorcode);
Bryan Schumaker399f11c2012-10-30 16:06:35 -0400463 goto wait_on_recovery;
Trond Myklebust03391692010-01-26 15:42:38 -0500464#endif /* defined(CONFIG_NFS_V4_1) */
Trond Myklebust65de8722008-12-23 15:21:44 -0500465 case -NFS4ERR_FILE_OPEN:
NeilBrown44ed3552009-12-03 15:58:56 -0500466 if (exception->timeout > HZ) {
467 /* We have retried a decent amount, time to
468 * fail
469 */
470 ret = -EBUSY;
471 break;
472 }
Trond Myklebust65de8722008-12-23 15:21:44 -0500473 case -NFS4ERR_DELAY:
Trond Myklebust2598ed32015-09-20 16:10:18 -0400474 nfs_inc_server_stats(server, NFSIOS_DELAY);
475 case -NFS4ERR_GRACE:
Trond Myklebuste85d7ee2016-07-14 18:46:24 -0400476 case -NFS4ERR_LAYOUTTRYLATER:
Jeff Layton183d9e72016-05-17 12:28:47 -0400477 case -NFS4ERR_RECALLCONFLICT:
Trond Myklebustb3c2aa02015-09-20 14:32:45 -0400478 exception->delay = 1;
479 return 0;
480
Andy Adamsona8a4ae32011-05-03 13:43:03 -0400481 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebust65de8722008-12-23 15:21:44 -0500482 case -NFS4ERR_OLD_STATEID:
483 exception->retry = 1;
Trond Myklebustb064eca22011-02-22 15:44:32 -0800484 break;
485 case -NFS4ERR_BADOWNER:
486 /* The following works around a Linux server bug! */
487 case -NFS4ERR_BADNAME:
488 if (server->caps & NFS_CAP_UIDGID_NOMAP) {
489 server->caps &= ~NFS_CAP_UIDGID_NOMAP;
490 exception->retry = 1;
491 printk(KERN_WARNING "NFS: v4 server %s "
492 "does not accept raw "
493 "uid/gids. "
494 "Reenabling the idmapper.\n",
495 server->nfs_client->cl_hostname);
496 }
Trond Myklebust65de8722008-12-23 15:21:44 -0500497 }
498 /* We failed to handle the error */
499 return nfs4_map_errors(ret);
Trond Myklebust0400a6b2011-03-09 16:00:53 -0500500wait_on_recovery:
Trond Myklebustb3c2aa02015-09-20 14:32:45 -0400501 exception->recovering = 1;
502 return 0;
503}
504
505/* This is the error handling routine for processes that are allowed
506 * to sleep.
507 */
508int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
509{
510 struct nfs_client *clp = server->nfs_client;
511 int ret;
512
513 ret = nfs4_do_handle_exception(server, errorcode, exception);
514 if (exception->delay) {
515 ret = nfs4_delay(server->client, &exception->timeout);
516 goto out_retry;
517 }
518 if (exception->recovering) {
519 ret = nfs4_wait_clnt_recover(clp);
520 if (test_bit(NFS_MIG_FAILED, &server->mig_status))
521 return -EIO;
522 goto out_retry;
523 }
524 return ret;
525out_retry:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -0500526 if (ret == 0)
527 exception->retry = 1;
528 return ret;
Trond Myklebust65de8722008-12-23 15:21:44 -0500529}
530
Trond Myklebust037fc982015-09-20 15:51:00 -0400531static int
532nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
533 int errorcode, struct nfs4_exception *exception)
534{
535 struct nfs_client *clp = server->nfs_client;
536 int ret;
537
538 ret = nfs4_do_handle_exception(server, errorcode, exception);
539 if (exception->delay) {
540 rpc_delay(task, nfs4_update_delay(&exception->timeout));
541 goto out_retry;
542 }
543 if (exception->recovering) {
544 rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
545 if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
546 rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
547 goto out_retry;
548 }
549 if (test_bit(NFS_MIG_FAILED, &server->mig_status))
550 ret = -EIO;
551 return ret;
552out_retry:
553 if (ret == 0)
554 exception->retry = 1;
555 return ret;
556}
557
558static int
559nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server,
560 struct nfs4_state *state, long *timeout)
561{
562 struct nfs4_exception exception = {
563 .state = state,
564 };
565
566 if (task->tk_status >= 0)
567 return 0;
568 if (timeout)
569 exception.timeout = *timeout;
570 task->tk_status = nfs4_async_handle_exception(task, server,
571 task->tk_status,
572 &exception);
573 if (exception.delay && timeout)
574 *timeout = exception.timeout;
575 if (exception.retry)
576 return -EAGAIN;
577 return 0;
578}
579
Weston Andros Adamsona5250de2013-09-03 15:18:49 -0400580/*
581 * Return 'true' if 'clp' is using an rpc_client that is integrity protected
582 * or 'false' otherwise.
583 */
584static bool _nfs4_is_integrity_protected(struct nfs_client *clp)
585{
586 rpc_authflavor_t flavor = clp->cl_rpcclient->cl_auth->au_flavor;
Anna Schumakereeea5362017-01-11 16:01:21 -0500587 return (flavor == RPC_AUTH_GSS_KRB5I) || (flavor == RPC_AUTH_GSS_KRB5P);
Weston Andros Adamsona5250de2013-09-03 15:18:49 -0400588}
Trond Myklebust65de8722008-12-23 15:21:44 -0500589
Trond Myklebust452e9352010-07-31 14:29:06 -0400590static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 spin_lock(&clp->cl_lock);
593 if (time_before(clp->cl_last_renewal,timestamp))
594 clp->cl_last_renewal = timestamp;
595 spin_unlock(&clp->cl_lock);
596}
597
Trond Myklebust452e9352010-07-31 14:29:06 -0400598static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
599{
Trond Myklebustbe824162015-07-05 14:50:46 -0400600 struct nfs_client *clp = server->nfs_client;
601
602 if (!nfs4_has_session(clp))
603 do_renew_lease(clp, timestamp);
Trond Myklebust452e9352010-07-31 14:29:06 -0400604}
605
Chuck Lever2a3eb2b2013-08-09 12:48:00 -0400606struct nfs4_call_sync_data {
607 const struct nfs_server *seq_server;
608 struct nfs4_sequence_args *seq_args;
609 struct nfs4_sequence_res *seq_res;
610};
611
Trond Myklebustbe3a5d22015-06-23 19:51:55 +0800612void nfs4_init_sequence(struct nfs4_sequence_args *args,
613 struct nfs4_sequence_res *res, int cache_reply)
Chuck Levera9c92d62013-08-09 12:48:18 -0400614{
615 args->sa_slot = NULL;
616 args->sa_cache_this = cache_reply;
617 args->sa_privileged = 0;
618
619 res->sr_slot = NULL;
620}
621
622static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
623{
624 args->sa_privileged = 1;
625}
626
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400627static void nfs40_sequence_free_slot(struct nfs4_sequence_res *res)
Chuck Lever3bd23842013-08-09 12:49:19 -0400628{
629 struct nfs4_slot *slot = res->sr_slot;
630 struct nfs4_slot_table *tbl;
631
Chuck Lever3bd23842013-08-09 12:49:19 -0400632 tbl = slot->table;
633 spin_lock(&tbl->slot_tbl_lock);
634 if (!nfs41_wake_and_assign_slot(tbl, slot))
635 nfs4_free_slot(tbl, slot);
636 spin_unlock(&tbl->slot_tbl_lock);
637
638 res->sr_slot = NULL;
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400639}
640
641static int nfs40_sequence_done(struct rpc_task *task,
642 struct nfs4_sequence_res *res)
643{
644 if (res->sr_slot != NULL)
645 nfs40_sequence_free_slot(res);
Chuck Lever3bd23842013-08-09 12:49:19 -0400646 return 1;
647}
648
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400649#if defined(CONFIG_NFS_V4_1)
650
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400651static void nfs41_release_slot(struct nfs4_slot *slot)
Andy Adamson13615872009-04-01 09:22:17 -0400652{
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500653 struct nfs4_session *session;
Andy Adamson13615872009-04-01 09:22:17 -0400654 struct nfs4_slot_table *tbl;
Trond Myklebustc10e4492012-11-26 16:16:54 -0500655 bool send_new_highest_used_slotid = false;
Andy Adamson13615872009-04-01 09:22:17 -0400656
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400657 if (!slot)
658 return;
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500659 tbl = slot->table;
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500660 session = tbl->session;
Andy Adamsonea028ac2009-12-04 15:55:38 -0500661
Trond Myklebust07e8dcb2016-08-28 10:28:25 -0400662 /* Bump the slot sequence number */
663 if (slot->seq_done)
664 slot->seq_nr++;
665 slot->seq_done = 0;
666
Trond Myklebust35dc1d72009-12-05 19:32:19 -0500667 spin_lock(&tbl->slot_tbl_lock);
Trond Myklebustc10e4492012-11-26 16:16:54 -0500668 /* Be nice to the server: try to ensure that the last transmitted
669 * value for highest_user_slotid <= target_highest_slotid
670 */
671 if (tbl->highest_used_slotid > tbl->target_highest_slotid)
672 send_new_highest_used_slotid = true;
673
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500674 if (nfs41_wake_and_assign_slot(tbl, slot)) {
Trond Myklebustb75ad4c2012-11-29 17:27:47 -0500675 send_new_highest_used_slotid = false;
676 goto out_unlock;
677 }
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500678 nfs4_free_slot(tbl, slot);
Trond Myklebustc10e4492012-11-26 16:16:54 -0500679
680 if (tbl->highest_used_slotid != NFS4_NO_SLOT)
681 send_new_highest_used_slotid = false;
Trond Myklebustb75ad4c2012-11-29 17:27:47 -0500682out_unlock:
Trond Myklebust35dc1d72009-12-05 19:32:19 -0500683 spin_unlock(&tbl->slot_tbl_lock);
Trond Myklebustc10e4492012-11-26 16:16:54 -0500684 if (send_new_highest_used_slotid)
Anna Schumaker3f10a6a2015-07-13 14:01:31 -0400685 nfs41_notify_server(session->clp);
Trond Myklebust045d2a62016-08-28 13:25:43 -0400686 if (waitqueue_active(&tbl->slot_waitq))
687 wake_up_all(&tbl->slot_waitq);
Andy Adamson13615872009-04-01 09:22:17 -0400688}
689
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400690static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
691{
692 nfs41_release_slot(res->sr_slot);
693 res->sr_slot = NULL;
694}
695
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400696static int nfs41_sequence_process(struct rpc_task *task,
697 struct nfs4_sequence_res *res)
Andy Adamsonb0df8062009-04-01 09:22:18 -0400698{
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500699 struct nfs4_session *session;
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500700 struct nfs4_slot *slot = res->sr_slot;
Trond Myklebust14516c32010-07-31 14:29:06 -0400701 struct nfs_client *clp;
Trond Myklebustac20d162012-12-15 15:36:07 -0500702 bool interrupted = false;
Trond Myklebust85563072012-12-11 10:31:12 -0500703 int ret = 1;
Andy Adamsonb0df8062009-04-01 09:22:18 -0400704
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500705 if (slot == NULL)
706 goto out_noaction;
Bryan Schumaker468f8612011-04-18 15:57:32 -0400707 /* don't increment the sequence number if the task wasn't sent */
708 if (!RPC_WAS_SENT(task))
Andy Adamsonb0df8062009-04-01 09:22:18 -0400709 goto out;
710
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500711 session = slot->table->session;
Trond Myklebust933602e2012-11-16 12:12:38 -0500712
Trond Myklebustac20d162012-12-15 15:36:07 -0500713 if (slot->interrupted) {
Olga Kornievskaia88bd4f82017-04-26 14:21:22 -0400714 if (res->sr_status != -NFS4ERR_DELAY)
715 slot->interrupted = 0;
Trond Myklebustac20d162012-12-15 15:36:07 -0500716 interrupted = true;
717 }
718
Trond Myklebust2f92ae32013-08-14 17:58:28 -0400719 trace_nfs4_sequence_done(session, res);
Andy Adamson691daf32009-12-04 15:55:39 -0500720 /* Check the SEQUENCE operation status */
Trond Myklebust14516c32010-07-31 14:29:06 -0400721 switch (res->sr_status) {
722 case 0:
Andy Adamsonb0df8062009-04-01 09:22:18 -0400723 /* Update the slot's sequence and clientid lease timer */
Trond Myklebust07e8dcb2016-08-28 10:28:25 -0400724 slot->seq_done = 1;
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500725 clp = session->clp;
Trond Myklebust8e63b6a2012-12-15 15:21:52 -0500726 do_renew_lease(clp, res->sr_timestamp);
Alexandros Batsakis0629e372009-12-05 13:46:14 -0500727 /* Check sequence flags */
Trond Myklebust0a014a42016-09-22 13:38:51 -0400728 nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags,
729 !!slot->privileged);
Trond Myklebust464ee9f2012-11-20 12:49:27 -0500730 nfs41_update_target_slotid(slot->table, slot, res);
Trond Myklebust14516c32010-07-31 14:29:06 -0400731 break;
Trond Myklebustac20d162012-12-15 15:36:07 -0500732 case 1:
733 /*
734 * sr_status remains 1 if an RPC level error occurred.
735 * The server may or may not have processed the sequence
736 * operation..
737 * Mark the slot as having hosted an interrupted RPC call.
738 */
739 slot->interrupted = 1;
740 goto out;
Trond Myklebust14516c32010-07-31 14:29:06 -0400741 case -NFS4ERR_DELAY:
742 /* The server detected a resend of the RPC call and
743 * returned NFS4ERR_DELAY as per Section 2.10.6.2
744 * of RFC5661.
745 */
Trond Myklebustdf2fabf2012-11-16 12:45:06 -0500746 dprintk("%s: slot=%u seq=%u: Operation in progress\n",
Benny Halevydfb4f3092010-09-24 09:17:01 -0400747 __func__,
Trond Myklebustdf2fabf2012-11-16 12:45:06 -0500748 slot->slot_nr,
Trond Myklebust933602e2012-11-16 12:12:38 -0500749 slot->seq_nr);
Trond Myklebust14516c32010-07-31 14:29:06 -0400750 goto out_retry;
Trond Myklebust85563072012-12-11 10:31:12 -0500751 case -NFS4ERR_BADSLOT:
752 /*
753 * The slot id we used was probably retired. Try again
754 * using a different slot id.
755 */
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400756 if (slot->seq_nr < slot->table->target_highest_slotid)
757 goto session_recover;
Trond Myklebuste8794442012-12-15 13:56:18 -0500758 goto retry_nowait;
759 case -NFS4ERR_SEQ_MISORDERED:
760 /*
Trond Myklebustac20d162012-12-15 15:36:07 -0500761 * Was the last operation on this sequence interrupted?
762 * If so, retry after bumping the sequence number.
763 */
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400764 if (interrupted)
765 goto retry_new_seq;
Trond Myklebustac20d162012-12-15 15:36:07 -0500766 /*
Trond Myklebuste8794442012-12-15 13:56:18 -0500767 * Could this slot have been previously retired?
768 * If so, then the server may be expecting seq_nr = 1!
769 */
Trond Myklebust8e63b6a2012-12-15 15:21:52 -0500770 if (slot->seq_nr != 1) {
771 slot->seq_nr = 1;
772 goto retry_nowait;
773 }
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400774 goto session_recover;
Trond Myklebuste8794442012-12-15 13:56:18 -0500775 case -NFS4ERR_SEQ_FALSE_RETRY:
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400776 if (interrupted)
777 goto retry_new_seq;
778 goto session_recover;
Trond Myklebust14516c32010-07-31 14:29:06 -0400779 default:
780 /* Just update the slot sequence no. */
Trond Myklebust07e8dcb2016-08-28 10:28:25 -0400781 slot->seq_done = 1;
Andy Adamsonb0df8062009-04-01 09:22:18 -0400782 }
783out:
784 /* The session may be reset by one of the error handlers. */
785 dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500786out_noaction:
Trond Myklebust85563072012-12-11 10:31:12 -0500787 return ret;
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400788session_recover:
789 nfs4_schedule_session_recovery(session, res->sr_status);
790 goto retry_nowait;
791retry_new_seq:
792 ++slot->seq_nr;
Trond Myklebuste8794442012-12-15 13:56:18 -0500793retry_nowait:
794 if (rpc_restart_call_prepare(task)) {
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400795 nfs41_sequence_free_slot(res);
Trond Myklebuste8794442012-12-15 13:56:18 -0500796 task->tk_status = 0;
797 ret = 0;
798 }
799 goto out;
Trond Myklebust14516c32010-07-31 14:29:06 -0400800out_retry:
Trond Myklebustd05dd4e2010-07-31 14:29:07 -0400801 if (!rpc_restart_call(task))
Trond Myklebust14516c32010-07-31 14:29:06 -0400802 goto out;
803 rpc_delay(task, NFS4_POLL_RETRY_MAX);
804 return 0;
Andy Adamsonb0df8062009-04-01 09:22:18 -0400805}
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400806
807int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
808{
809 if (!nfs41_sequence_process(task, res))
810 return 0;
811 if (res->sr_slot != NULL)
812 nfs41_sequence_free_slot(res);
813 return 1;
814
815}
Andy Adamsonf9c96fc2014-01-29 11:34:38 -0500816EXPORT_SYMBOL_GPL(nfs41_sequence_done);
Andy Adamsonb0df8062009-04-01 09:22:18 -0400817
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400818static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
819{
820 if (res->sr_slot == NULL)
821 return 1;
822 if (res->sr_slot->table->session != NULL)
823 return nfs41_sequence_process(task, res);
824 return nfs40_sequence_done(task, res);
825}
826
827static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
828{
829 if (res->sr_slot != NULL) {
830 if (res->sr_slot->table->session != NULL)
831 nfs41_sequence_free_slot(res);
832 else
833 nfs40_sequence_free_slot(res);
834 }
835}
836
Peng Tao2c4b1312014-06-11 05:24:16 +0800837int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
Trond Myklebustdf896452010-06-16 09:52:26 -0400838{
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500839 if (res->sr_slot == NULL)
Trond Myklebust14516c32010-07-31 14:29:06 -0400840 return 1;
Chuck Lever3bd23842013-08-09 12:49:19 -0400841 if (!res->sr_slot->table->session)
842 return nfs40_sequence_done(task, res);
Trond Myklebust14516c32010-07-31 14:29:06 -0400843 return nfs41_sequence_done(task, res);
Trond Myklebustdf896452010-06-16 09:52:26 -0400844}
Peng Tao2c4b1312014-06-11 05:24:16 +0800845EXPORT_SYMBOL_GPL(nfs4_sequence_done);
Trond Myklebustdf896452010-06-16 09:52:26 -0400846
Andy Adamsonce5039c2009-04-01 09:22:13 -0400847static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
848{
Chuck Lever2a3eb2b2013-08-09 12:48:00 -0400849 struct nfs4_call_sync_data *data = calldata;
Andy Adamsonce5039c2009-04-01 09:22:13 -0400850
Trond Myklebust035168ab2010-06-16 09:52:26 -0400851 dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
852
Anna Schumaker7981c8a2017-01-10 11:39:53 -0500853 nfs4_setup_sequence(data->seq_server->nfs_client,
854 data->seq_args, data->seq_res, task);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400855}
856
Andy Adamson69ab40c2009-04-01 09:22:19 -0400857static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
858{
Chuck Lever2a3eb2b2013-08-09 12:48:00 -0400859 struct nfs4_call_sync_data *data = calldata;
Andy Adamson69ab40c2009-04-01 09:22:19 -0400860
Trond Myklebust14516c32010-07-31 14:29:06 -0400861 nfs41_sequence_done(task, data->seq_res);
Andy Adamson69ab40c2009-04-01 09:22:19 -0400862}
863
Trond Myklebust17280172012-03-11 13:11:00 -0400864static const struct rpc_call_ops nfs41_call_sync_ops = {
Andy Adamsonce5039c2009-04-01 09:22:13 -0400865 .rpc_call_prepare = nfs41_call_sync_prepare,
Andy Adamson69ab40c2009-04-01 09:22:19 -0400866 .rpc_call_done = nfs41_call_sync_done,
Andy Adamsonce5039c2009-04-01 09:22:13 -0400867};
868
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400869static void
870nfs4_sequence_process_interrupted(struct nfs_client *client,
871 struct nfs4_slot *slot, struct rpc_cred *cred)
872{
873 struct rpc_task *task;
874
875 task = _nfs41_proc_sequence(client, cred, slot, true);
876 if (!IS_ERR(task))
877 rpc_put_task_async(task);
878}
879
Chuck Lever3bd23842013-08-09 12:49:19 -0400880#else /* !CONFIG_NFS_V4_1 */
881
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400882static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
883{
884 return nfs40_sequence_done(task, res);
885}
886
887static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
888{
889 if (res->sr_slot != NULL)
890 nfs40_sequence_free_slot(res);
891}
892
Peng Tao2c4b1312014-06-11 05:24:16 +0800893int nfs4_sequence_done(struct rpc_task *task,
894 struct nfs4_sequence_res *res)
Trond Myklebustdf896452010-06-16 09:52:26 -0400895{
Chuck Lever3bd23842013-08-09 12:49:19 -0400896 return nfs40_sequence_done(task, res);
Trond Myklebustdf896452010-06-16 09:52:26 -0400897}
Peng Tao2c4b1312014-06-11 05:24:16 +0800898EXPORT_SYMBOL_GPL(nfs4_sequence_done);
Chuck Lever3bd23842013-08-09 12:49:19 -0400899
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400900static void
901nfs4_sequence_process_interrupted(struct nfs_client *client,
902 struct nfs4_slot *slot, struct rpc_cred *cred)
903{
904 WARN_ON_ONCE(1);
905 slot->interrupted = 0;
906}
907
Chuck Lever3bd23842013-08-09 12:49:19 -0400908#endif /* !CONFIG_NFS_V4_1 */
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400909
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400910static
911void nfs4_sequence_attach_slot(struct nfs4_sequence_args *args,
912 struct nfs4_sequence_res *res,
913 struct nfs4_slot *slot)
914{
915 if (!slot)
916 return;
917 slot->privileged = args->sa_privileged ? 1 : 0;
918 args->sa_slot = slot;
919
920 res->sr_slot = slot;
921 res->sr_timestamp = jiffies;
922 res->sr_status_flags = 0;
923 res->sr_status = 1;
924
925}
926
927int nfs4_setup_sequence(struct nfs_client *client,
Anna Schumaker7981c8a2017-01-10 11:39:53 -0500928 struct nfs4_sequence_args *args,
929 struct nfs4_sequence_res *res,
930 struct rpc_task *task)
931{
Anna Schumaker7981c8a2017-01-10 11:39:53 -0500932 struct nfs4_session *session = nfs4_get_session(client);
Anna Schumaker76ee0352017-01-10 16:49:31 -0500933 struct nfs4_slot_table *tbl = client->cl_slot_tbl;
Anna Schumaker3d358082017-01-11 10:54:04 -0500934 struct nfs4_slot *slot;
Anna Schumaker7981c8a2017-01-10 11:39:53 -0500935
Anna Schumaker9dd91072017-01-10 12:01:46 -0500936 /* slot already allocated? */
937 if (res->sr_slot != NULL)
938 goto out_start;
939
Anna Schumaker76ee0352017-01-10 16:49:31 -0500940 if (session) {
941 tbl = &session->fc_slot_table;
942 task->tk_timeout = 0;
943 }
944
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400945 for (;;) {
946 spin_lock(&tbl->slot_tbl_lock);
947 /* The state manager will wait until the slot table is empty */
948 if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
949 goto out_sleep;
Anna Schumaker6994cdd2017-01-10 16:13:27 -0500950
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400951 slot = nfs4_alloc_slot(tbl);
952 if (IS_ERR(slot)) {
953 /* Try again in 1/4 second */
954 if (slot == ERR_PTR(-ENOMEM))
955 task->tk_timeout = HZ >> 2;
956 goto out_sleep;
957 }
958 spin_unlock(&tbl->slot_tbl_lock);
959
960 if (likely(!slot->interrupted))
961 break;
962 nfs4_sequence_process_interrupted(client,
963 slot, task->tk_msg.rpc_cred);
Anna Schumaker3d358082017-01-11 10:54:04 -0500964 }
Anna Schumaker7981c8a2017-01-10 11:39:53 -0500965
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400966 nfs4_sequence_attach_slot(args, res, slot);
Anna Schumaker3d358082017-01-11 10:54:04 -0500967
Anna Schumakerad05cc02017-01-11 13:37:06 -0500968 trace_nfs4_setup_sequence(session, args);
Anna Schumaker9dd91072017-01-10 12:01:46 -0500969out_start:
970 rpc_call_start(task);
971 return 0;
Anna Schumaker0dcee8b2017-01-10 16:29:54 -0500972
973out_sleep:
974 if (args->sa_privileged)
975 rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
976 NULL, RPC_PRIORITY_PRIVILEGED);
977 else
978 rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
979 spin_unlock(&tbl->slot_tbl_lock);
980 return -EAGAIN;
Anna Schumaker7981c8a2017-01-10 11:39:53 -0500981}
982EXPORT_SYMBOL_GPL(nfs4_setup_sequence);
983
Chuck Lever9915ea72013-08-09 12:48:27 -0400984static void nfs40_call_sync_prepare(struct rpc_task *task, void *calldata)
985{
986 struct nfs4_call_sync_data *data = calldata;
Anna Schumaker42e1cca2017-01-09 15:48:22 -0500987 nfs4_setup_sequence(data->seq_server->nfs_client,
Chuck Lever9915ea72013-08-09 12:48:27 -0400988 data->seq_args, data->seq_res, task);
989}
990
991static void nfs40_call_sync_done(struct rpc_task *task, void *calldata)
992{
993 struct nfs4_call_sync_data *data = calldata;
994 nfs4_sequence_done(task, data->seq_res);
995}
996
997static const struct rpc_call_ops nfs40_call_sync_ops = {
998 .rpc_call_prepare = nfs40_call_sync_prepare,
999 .rpc_call_done = nfs40_call_sync_done,
1000};
1001
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001002static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
Trond Myklebustad389da2007-06-05 12:30:00 -04001003 struct nfs_server *server,
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001004 struct rpc_message *msg,
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001005 struct nfs4_sequence_args *args,
1006 struct nfs4_sequence_res *res)
Trond Myklebustad389da2007-06-05 12:30:00 -04001007{
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001008 int ret;
1009 struct rpc_task *task;
Chuck Lever9915ea72013-08-09 12:48:27 -04001010 struct nfs_client *clp = server->nfs_client;
1011 struct nfs4_call_sync_data data = {
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001012 .seq_server = server,
1013 .seq_args = args,
1014 .seq_res = res,
1015 };
1016 struct rpc_task_setup task_setup = {
1017 .rpc_client = clnt,
1018 .rpc_message = msg,
Chuck Lever9915ea72013-08-09 12:48:27 -04001019 .callback_ops = clp->cl_mvops->call_sync_ops,
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001020 .callback_data = &data
1021 };
1022
1023 task = rpc_run_task(&task_setup);
1024 if (IS_ERR(task))
1025 ret = PTR_ERR(task);
1026 else {
1027 ret = task->tk_status;
Trond Myklebustad389da2007-06-05 12:30:00 -04001028 rpc_put_task(task);
1029 }
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001030 return ret;
1031}
1032
Bryan Schumaker7c513052011-03-24 17:12:24 +00001033int nfs4_call_sync(struct rpc_clnt *clnt,
1034 struct nfs_server *server,
Bryan Schumakere73b83f2011-03-24 17:12:23 +00001035 struct rpc_message *msg,
1036 struct nfs4_sequence_args *args,
1037 struct nfs4_sequence_res *res,
1038 int cache_reply)
1039{
Chuck Levera9c92d62013-08-09 12:48:18 -04001040 nfs4_init_sequence(args, res, cache_reply);
Chuck Lever9915ea72013-08-09 12:48:27 -04001041 return nfs4_call_sync_sequence(clnt, server, msg, args, res);
Bryan Schumakere73b83f2011-03-24 17:12:23 +00001042}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Trond Myklebustd3129ef2017-01-11 22:07:28 -05001044static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
1045 unsigned long timestamp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046{
1047 struct nfs_inode *nfsi = NFS_I(dir);
1048
1049 spin_lock(&dir->i_lock);
Trond Myklebust359d7d12012-05-28 10:01:34 -04001050 nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
Trond Myklebuste603a4c2016-12-16 16:55:55 -05001051 if (cinfo->atomic && cinfo->before == dir->i_version) {
1052 nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
1053 nfsi->attrtimeo_timestamp = jiffies;
1054 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055 nfs_force_lookup_revalidate(dir);
Trond Myklebuste603a4c2016-12-16 16:55:55 -05001056 if (cinfo->before != dir->i_version)
1057 nfsi->cache_validity |= NFS_INO_INVALID_ACCESS |
1058 NFS_INO_INVALID_ACL;
1059 }
Trond Myklebusta9a4a872011-10-17 16:08:46 -07001060 dir->i_version = cinfo->after;
Trond Myklebustd3129ef2017-01-11 22:07:28 -05001061 nfsi->read_cache_jiffies = timestamp;
Trond Myklebust3235b402015-02-26 19:52:06 -05001062 nfsi->attr_gencount = nfs_inc_attr_generation_counter();
David Howellsde242c02012-12-20 21:52:38 +00001063 nfs_fscache_invalidate(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 spin_unlock(&dir->i_lock);
1065}
1066
1067struct nfs4_opendata {
1068 struct kref kref;
1069 struct nfs_openargs o_arg;
1070 struct nfs_openres o_res;
1071 struct nfs_open_confirmargs c_arg;
1072 struct nfs_open_confirmres c_res;
Trond Myklebust6926afd2012-01-07 13:22:46 -05001073 struct nfs4_string owner_name;
1074 struct nfs4_string group_name;
Kinglong Meea49c2692015-07-27 15:31:38 +08001075 struct nfs4_label *a_label;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076 struct nfs_fattr f_attr;
David Quigley1775fd32013-05-22 12:50:42 -04001077 struct nfs4_label *f_label;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 struct dentry *dir;
Al Viro82a2c1b2011-06-22 18:30:55 -04001079 struct dentry *dentry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 struct nfs4_state_owner *owner;
1081 struct nfs4_state *state;
1082 struct iattr attrs;
1083 unsigned long timestamp;
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04001084 bool rpc_done;
1085 bool file_created;
1086 bool is_recover;
1087 bool cancelled;
Trond Myklebustdecf4912005-10-27 22:12:39 -04001088 int rpc_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089};
Trond Myklebustdecf4912005-10-27 22:12:39 -04001090
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001091static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
1092 int err, struct nfs4_exception *exception)
1093{
1094 if (err != -EINVAL)
1095 return false;
1096 if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
1097 return false;
1098 server->caps &= ~NFS_CAP_ATOMIC_OPEN_V1;
1099 exception->retry = 1;
1100 return true;
1101}
1102
Trond Myklebust6ae37332015-01-30 14:21:14 -05001103static u32
1104nfs4_map_atomic_open_share(struct nfs_server *server,
1105 fmode_t fmode, int openflags)
1106{
1107 u32 res = 0;
1108
1109 switch (fmode & (FMODE_READ | FMODE_WRITE)) {
1110 case FMODE_READ:
1111 res = NFS4_SHARE_ACCESS_READ;
1112 break;
1113 case FMODE_WRITE:
1114 res = NFS4_SHARE_ACCESS_WRITE;
1115 break;
1116 case FMODE_READ|FMODE_WRITE:
1117 res = NFS4_SHARE_ACCESS_BOTH;
1118 }
1119 if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
1120 goto out;
1121 /* Want no delegation if we're using O_DIRECT */
1122 if (openflags & O_DIRECT)
1123 res |= NFS4_SHARE_WANT_NO_DELEG;
1124out:
1125 return res;
1126}
1127
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001128static enum open_claim_type4
1129nfs4_map_atomic_open_claim(struct nfs_server *server,
1130 enum open_claim_type4 claim)
1131{
1132 if (server->caps & NFS_CAP_ATOMIC_OPEN_V1)
1133 return claim;
1134 switch (claim) {
1135 default:
1136 return claim;
1137 case NFS4_OPEN_CLAIM_FH:
1138 return NFS4_OPEN_CLAIM_NULL;
1139 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
1140 return NFS4_OPEN_CLAIM_DELEGATE_CUR;
1141 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
1142 return NFS4_OPEN_CLAIM_DELEGATE_PREV;
1143 }
1144}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
1146static void nfs4_init_opendata_res(struct nfs4_opendata *p)
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001147{
1148 p->o_res.f_attr = &p->f_attr;
David Quigley1775fd32013-05-22 12:50:42 -04001149 p->o_res.f_label = p->f_label;
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001150 p->o_res.seqid = p->o_arg.seqid;
1151 p->c_res.seqid = p->c_arg.seqid;
1152 p->o_res.server = p->o_arg.server;
Andy Adamson5f657532012-10-03 02:39:34 -04001153 p->o_res.access_request = p->o_arg.access;
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001154 nfs_fattr_init(&p->f_attr);
Trond Myklebust6926afd2012-01-07 13:22:46 -05001155 nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001156}
1157
Al Viro82a2c1b2011-06-22 18:30:55 -04001158static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001159 struct nfs4_state_owner *sp, fmode_t fmode, int flags,
Trond Myklebust8535b2b2010-05-13 12:51:01 -04001160 const struct iattr *attrs,
David Quigley1775fd32013-05-22 12:50:42 -04001161 struct nfs4_label *label,
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001162 enum open_claim_type4 claim,
Trond Myklebust8535b2b2010-05-13 12:51:01 -04001163 gfp_t gfp_mask)
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001164{
Al Viro82a2c1b2011-06-22 18:30:55 -04001165 struct dentry *parent = dget_parent(dentry);
David Howells2b0143b2015-03-17 22:25:59 +00001166 struct inode *dir = d_inode(parent);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001167 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebust63f5f792015-01-23 19:19:25 -05001168 struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001169 struct nfs4_opendata *p;
1170
Trond Myklebust8535b2b2010-05-13 12:51:01 -04001171 p = kzalloc(sizeof(*p), gfp_mask);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001172 if (p == NULL)
1173 goto err;
David Quigley14c43f72013-05-22 12:50:43 -04001174
1175 p->f_label = nfs4_label_alloc(server, gfp_mask);
1176 if (IS_ERR(p->f_label))
1177 goto err_free_p;
1178
Kinglong Meea49c2692015-07-27 15:31:38 +08001179 p->a_label = nfs4_label_alloc(server, gfp_mask);
1180 if (IS_ERR(p->a_label))
1181 goto err_free_f;
1182
Trond Myklebust63f5f792015-01-23 19:19:25 -05001183 alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
1184 p->o_arg.seqid = alloc_seqid(&sp->so_seqid, gfp_mask);
Trond Myklebustbadc76d2015-01-23 18:48:00 -05001185 if (IS_ERR(p->o_arg.seqid))
David Quigley14c43f72013-05-22 12:50:43 -04001186 goto err_free_label;
Al Viro82a2c1b2011-06-22 18:30:55 -04001187 nfs_sb_active(dentry->d_sb);
1188 p->dentry = dget(dentry);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001189 p->dir = parent;
1190 p->owner = sp;
1191 atomic_inc(&sp->so_count);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001192 p->o_arg.open_flags = flags;
1193 p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05001194 p->o_arg.umask = current_umask();
Trond Myklebust536585c2016-11-10 15:40:34 -05001195 p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
Trond Myklebust6ae37332015-01-30 14:21:14 -05001196 p->o_arg.share_access = nfs4_map_atomic_open_share(server,
1197 fmode, flags);
Weston Andros Adamsonae2bb032012-10-02 14:49:52 -07001198 /* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS
1199 * will return permission denied for all bits until close */
1200 if (!(flags & O_EXCL)) {
1201 /* ask server to check for all possible rights as results
1202 * are cached */
Trond Myklebust536585c2016-11-10 15:40:34 -05001203 switch (p->o_arg.claim) {
1204 default:
1205 break;
1206 case NFS4_OPEN_CLAIM_NULL:
1207 case NFS4_OPEN_CLAIM_FH:
1208 p->o_arg.access = NFS4_ACCESS_READ |
1209 NFS4_ACCESS_MODIFY |
1210 NFS4_ACCESS_EXTEND |
1211 NFS4_ACCESS_EXECUTE;
1212 }
Weston Andros Adamsonae2bb032012-10-02 14:49:52 -07001213 }
David Howells7539bba2006-08-22 20:06:09 -04001214 p->o_arg.clientid = server->nfs_client->cl_clientid;
Trond Myklebust95b72eb2012-04-20 19:24:51 -04001215 p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
1216 p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
Al Viro82a2c1b2011-06-22 18:30:55 -04001217 p->o_arg.name = &dentry->d_name;
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001218 p->o_arg.server = server;
David Quigleyaa9c2662013-05-22 12:50:44 -04001219 p->o_arg.bitmask = nfs4_bitmask(server, label);
Trond Myklebust1549210f2012-06-05 09:16:47 -04001220 p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
Kinglong Meea49c2692015-07-27 15:31:38 +08001221 p->o_arg.label = nfs4_label_copy(p->a_label, label);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001222 switch (p->o_arg.claim) {
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001223 case NFS4_OPEN_CLAIM_NULL:
1224 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
1225 case NFS4_OPEN_CLAIM_DELEGATE_PREV:
1226 p->o_arg.fh = NFS_FH(dir);
1227 break;
1228 case NFS4_OPEN_CLAIM_PREVIOUS:
1229 case NFS4_OPEN_CLAIM_FH:
1230 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
1231 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
David Howells2b0143b2015-03-17 22:25:59 +00001232 p->o_arg.fh = NFS_FH(d_inode(dentry));
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001233 }
Trond Myklebust536e43d2012-01-17 22:04:26 -05001234 if (attrs != NULL && attrs->ia_valid != 0) {
Trond Myklebustc281fa9c2013-08-20 21:06:49 -04001235 __u32 verf[2];
Trond Myklebustd77d76f2010-06-16 09:52:27 -04001236
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001237 p->o_arg.u.attrs = &p->attrs;
1238 memcpy(&p->attrs, attrs, sizeof(p->attrs));
Chuck Levercd937102012-03-02 17:14:31 -05001239
1240 verf[0] = jiffies;
1241 verf[1] = current->pid;
1242 memcpy(p->o_arg.u.verifier.data, verf,
1243 sizeof(p->o_arg.u.verifier.data));
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001244 }
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001245 p->c_arg.fh = &p->o_res.fh;
1246 p->c_arg.stateid = &p->o_res.stateid;
1247 p->c_arg.seqid = p->o_arg.seqid;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001248 nfs4_init_opendata_res(p);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001249 kref_init(&p->kref);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001250 return p;
David Quigley14c43f72013-05-22 12:50:43 -04001251
1252err_free_label:
Kinglong Meea49c2692015-07-27 15:31:38 +08001253 nfs4_label_free(p->a_label);
1254err_free_f:
David Quigley14c43f72013-05-22 12:50:43 -04001255 nfs4_label_free(p->f_label);
1256err_free_p:
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001257 kfree(p);
1258err:
1259 dput(parent);
1260 return NULL;
1261}
1262
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001263static void nfs4_opendata_free(struct kref *kref)
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001264{
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001265 struct nfs4_opendata *p = container_of(kref,
1266 struct nfs4_opendata, kref);
Al Viro82a2c1b2011-06-22 18:30:55 -04001267 struct super_block *sb = p->dentry->d_sb;
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001268
1269 nfs_free_seqid(p->o_arg.seqid);
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04001270 nfs4_sequence_free_slot(&p->o_res.seq_res);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001271 if (p->state != NULL)
1272 nfs4_put_open_state(p->state);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001273 nfs4_put_state_owner(p->owner);
David Quigley14c43f72013-05-22 12:50:43 -04001274
Kinglong Meea49c2692015-07-27 15:31:38 +08001275 nfs4_label_free(p->a_label);
David Quigley14c43f72013-05-22 12:50:43 -04001276 nfs4_label_free(p->f_label);
1277
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001278 dput(p->dir);
Al Viro82a2c1b2011-06-22 18:30:55 -04001279 dput(p->dentry);
1280 nfs_sb_deactive(sb);
Trond Myklebust6926afd2012-01-07 13:22:46 -05001281 nfs_fattr_free_names(&p->f_attr);
Trond Myklebuste911b812014-03-26 13:24:37 -07001282 kfree(p->f_attr.mdsthreshold);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001283 kfree(p);
1284}
1285
1286static void nfs4_opendata_put(struct nfs4_opendata *p)
1287{
1288 if (p != NULL)
1289 kref_put(&p->kref, nfs4_opendata_free);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001290}
1291
Trond Myklebust24311f82015-09-20 10:50:17 -04001292static bool nfs4_mode_match_open_stateid(struct nfs4_state *state,
1293 fmode_t fmode)
1294{
1295 switch(fmode & (FMODE_READ|FMODE_WRITE)) {
1296 case FMODE_READ|FMODE_WRITE:
1297 return state->n_rdwr != 0;
1298 case FMODE_WRITE:
1299 return state->n_wronly != 0;
1300 case FMODE_READ:
1301 return state->n_rdonly != 0;
1302 }
1303 WARN_ON_ONCE(1);
1304 return false;
1305}
1306
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001307static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode)
Trond Myklebust6ee41262007-07-08 14:11:36 -04001308{
1309 int ret = 0;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001310
Trond Myklebust536e43d2012-01-17 22:04:26 -05001311 if (open_mode & (O_EXCL|O_TRUNC))
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001312 goto out;
1313 switch (mode & (FMODE_READ|FMODE_WRITE)) {
Trond Myklebust6ee41262007-07-08 14:11:36 -04001314 case FMODE_READ:
Trond Myklebust88069f72009-12-08 08:33:16 -05001315 ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0
1316 && state->n_rdonly != 0;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001317 break;
1318 case FMODE_WRITE:
Trond Myklebust88069f72009-12-08 08:33:16 -05001319 ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0
1320 && state->n_wronly != 0;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001321 break;
1322 case FMODE_READ|FMODE_WRITE:
Trond Myklebust88069f72009-12-08 08:33:16 -05001323 ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0
1324 && state->n_rdwr != 0;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001325 }
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001326out:
Trond Myklebust6ee41262007-07-08 14:11:36 -04001327 return ret;
1328}
1329
Trond Myklebust2a606182015-08-19 22:30:00 -05001330static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode,
1331 enum open_claim_type4 claim)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001332{
Trond Myklebust652f89f2011-12-09 19:05:58 -05001333 if (delegation == NULL)
1334 return 0;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001335 if ((delegation->type & fmode) != fmode)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001336 return 0;
Trond Myklebustd25be542013-02-05 11:43:28 -05001337 if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
1338 return 0;
Trond Myklebust2a606182015-08-19 22:30:00 -05001339 switch (claim) {
1340 case NFS4_OPEN_CLAIM_NULL:
1341 case NFS4_OPEN_CLAIM_FH:
1342 break;
1343 case NFS4_OPEN_CLAIM_PREVIOUS:
1344 if (!test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
1345 break;
1346 default:
1347 return 0;
1348 }
Trond Myklebustb7391f42008-12-23 15:21:52 -05001349 nfs_mark_delegation_referenced(delegation);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001350 return 1;
1351}
1352
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001353static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
Trond Myklebuste7616922006-01-03 09:55:13 +01001354{
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001355 switch (fmode) {
Trond Myklebuste7616922006-01-03 09:55:13 +01001356 case FMODE_WRITE:
1357 state->n_wronly++;
1358 break;
1359 case FMODE_READ:
1360 state->n_rdonly++;
1361 break;
1362 case FMODE_READ|FMODE_WRITE:
1363 state->n_rdwr++;
1364 }
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001365 nfs4_state_set_mode_locked(state, state->state | fmode);
Trond Myklebuste7616922006-01-03 09:55:13 +01001366}
1367
Trond Myklebust8a64c4e2016-09-22 13:39:21 -04001368#ifdef CONFIG_NFS_V4_1
1369static bool nfs_open_stateid_recover_openmode(struct nfs4_state *state)
1370{
1371 if (state->n_rdonly && !test_bit(NFS_O_RDONLY_STATE, &state->flags))
1372 return true;
1373 if (state->n_wronly && !test_bit(NFS_O_WRONLY_STATE, &state->flags))
1374 return true;
1375 if (state->n_rdwr && !test_bit(NFS_O_RDWR_STATE, &state->flags))
1376 return true;
1377 return false;
1378}
1379#endif /* CONFIG_NFS_V4_1 */
1380
Trond Myklebust4f14c192014-02-12 19:15:06 -05001381static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state)
Trond Myklebust003707c2007-07-05 18:07:55 -04001382{
Trond Myklebust4f14c192014-02-12 19:15:06 -05001383 struct nfs_client *clp = state->owner->so_server->nfs_client;
1384 bool need_recover = false;
1385
1386 if (test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags) && state->n_rdonly)
1387 need_recover = true;
1388 if (test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags) && state->n_wronly)
1389 need_recover = true;
1390 if (test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags) && state->n_rdwr)
1391 need_recover = true;
1392 if (need_recover)
1393 nfs4_state_mark_reclaim_nograce(clp, state);
1394}
1395
Trond Myklebuste999e802014-02-10 18:20:47 -05001396static bool nfs_need_update_open_stateid(struct nfs4_state *state,
Trond Myklebust1393d962016-09-22 13:39:13 -04001397 const nfs4_stateid *stateid, nfs4_stateid *freeme)
Trond Myklebuste999e802014-02-10 18:20:47 -05001398{
1399 if (test_and_set_bit(NFS_OPEN_STATE, &state->flags) == 0)
1400 return true;
Trond Myklebust4f14c192014-02-12 19:15:06 -05001401 if (!nfs4_stateid_match_other(stateid, &state->open_stateid)) {
Trond Myklebust1393d962016-09-22 13:39:13 -04001402 nfs4_stateid_copy(freeme, &state->open_stateid);
Trond Myklebust4f14c192014-02-12 19:15:06 -05001403 nfs_test_and_clear_all_open_stateid(state);
Trond Myklebuste999e802014-02-10 18:20:47 -05001404 return true;
Trond Myklebust4f14c192014-02-12 19:15:06 -05001405 }
Trond Myklebuste999e802014-02-10 18:20:47 -05001406 if (nfs4_stateid_is_newer(stateid, &state->open_stateid))
1407 return true;
1408 return false;
1409}
1410
Trond Myklebustf95549c2015-01-23 18:06:09 -05001411static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
1412{
Trond Myklebust3c38cbe2015-07-22 13:46:13 -04001413 if (!(state->n_wronly || state->n_rdonly || state->n_rdwr))
1414 return;
Trond Myklebustf95549c2015-01-23 18:06:09 -05001415 if (state->n_wronly)
1416 set_bit(NFS_O_WRONLY_STATE, &state->flags);
1417 if (state->n_rdonly)
1418 set_bit(NFS_O_RDONLY_STATE, &state->flags);
1419 if (state->n_rdwr)
1420 set_bit(NFS_O_RDWR_STATE, &state->flags);
Trond Myklebust3c38cbe2015-07-22 13:46:13 -04001421 set_bit(NFS_OPEN_STATE, &state->flags);
Trond Myklebustf95549c2015-01-23 18:06:09 -05001422}
1423
Trond Myklebust226056c2014-02-11 10:41:07 -05001424static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
1425 nfs4_stateid *stateid, fmode_t fmode)
1426{
1427 clear_bit(NFS_O_RDWR_STATE, &state->flags);
1428 switch (fmode & (FMODE_READ|FMODE_WRITE)) {
1429 case FMODE_WRITE:
1430 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1431 break;
1432 case FMODE_READ:
1433 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1434 break;
1435 case 0:
1436 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1437 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1438 clear_bit(NFS_OPEN_STATE, &state->flags);
1439 }
1440 if (stateid == NULL)
1441 return;
Trond Myklebust3e7dfb12016-11-14 11:19:55 -05001442 /* Handle OPEN+OPEN_DOWNGRADE races */
1443 if (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
1444 !nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
Trond Myklebustf95549c2015-01-23 18:06:09 -05001445 nfs_resync_open_stateid_locked(state);
Trond Myklebust226056c2014-02-11 10:41:07 -05001446 return;
Trond Myklebustf95549c2015-01-23 18:06:09 -05001447 }
Trond Myklebust003707c2007-07-05 18:07:55 -04001448 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
Trond Myklebustf597c532012-03-04 18:13:56 -05001449 nfs4_stateid_copy(&state->stateid, stateid);
1450 nfs4_stateid_copy(&state->open_stateid, stateid);
Trond Myklebust226056c2014-02-11 10:41:07 -05001451}
1452
Trond Myklebust4a1e2fe2015-08-30 18:37:59 -07001453static void nfs_clear_open_stateid(struct nfs4_state *state,
1454 nfs4_stateid *arg_stateid,
1455 nfs4_stateid *stateid, fmode_t fmode)
Trond Myklebust226056c2014-02-11 10:41:07 -05001456{
1457 write_seqlock(&state->seqlock);
Trond Myklebust3e7dfb12016-11-14 11:19:55 -05001458 /* Ignore, if the CLOSE argment doesn't match the current stateid */
1459 if (nfs4_state_match_open_stateid_other(state, arg_stateid))
1460 nfs_clear_open_stateid_locked(state, stateid, fmode);
Trond Myklebust226056c2014-02-11 10:41:07 -05001461 write_sequnlock(&state->seqlock);
Trond Myklebust4f14c192014-02-12 19:15:06 -05001462 if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
1463 nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
Trond Myklebust226056c2014-02-11 10:41:07 -05001464}
1465
Trond Myklebust1393d962016-09-22 13:39:13 -04001466static void nfs_set_open_stateid_locked(struct nfs4_state *state,
1467 const nfs4_stateid *stateid, fmode_t fmode,
1468 nfs4_stateid *freeme)
Trond Myklebust003707c2007-07-05 18:07:55 -04001469{
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001470 switch (fmode) {
Trond Myklebust003707c2007-07-05 18:07:55 -04001471 case FMODE_READ:
1472 set_bit(NFS_O_RDONLY_STATE, &state->flags);
1473 break;
1474 case FMODE_WRITE:
1475 set_bit(NFS_O_WRONLY_STATE, &state->flags);
1476 break;
1477 case FMODE_READ|FMODE_WRITE:
1478 set_bit(NFS_O_RDWR_STATE, &state->flags);
1479 }
Trond Myklebust1393d962016-09-22 13:39:13 -04001480 if (!nfs_need_update_open_stateid(state, stateid, freeme))
Trond Myklebuste999e802014-02-10 18:20:47 -05001481 return;
1482 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
1483 nfs4_stateid_copy(&state->stateid, stateid);
1484 nfs4_stateid_copy(&state->open_stateid, stateid);
Trond Myklebust003707c2007-07-05 18:07:55 -04001485}
1486
Trond Myklebust1393d962016-09-22 13:39:13 -04001487static void __update_open_stateid(struct nfs4_state *state,
1488 const nfs4_stateid *open_stateid,
1489 const nfs4_stateid *deleg_stateid,
1490 fmode_t fmode,
1491 nfs4_stateid *freeme)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492{
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001493 /*
1494 * Protect the call to nfs4_state_set_mode_locked and
1495 * serialise the stateid update
1496 */
Andrew Elble361cad32015-12-02 09:20:57 -05001497 spin_lock(&state->owner->so_lock);
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001498 write_seqlock(&state->seqlock);
Trond Myklebust003707c2007-07-05 18:07:55 -04001499 if (deleg_stateid != NULL) {
Trond Myklebustf597c532012-03-04 18:13:56 -05001500 nfs4_stateid_copy(&state->stateid, deleg_stateid);
Trond Myklebust003707c2007-07-05 18:07:55 -04001501 set_bit(NFS_DELEGATED_STATE, &state->flags);
1502 }
1503 if (open_stateid != NULL)
Trond Myklebust1393d962016-09-22 13:39:13 -04001504 nfs_set_open_stateid_locked(state, open_stateid, fmode, freeme);
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001505 write_sequnlock(&state->seqlock);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001506 update_open_stateflags(state, fmode);
Trond Myklebustec073422005-10-20 14:22:47 -07001507 spin_unlock(&state->owner->so_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508}
1509
Trond Myklebust1393d962016-09-22 13:39:13 -04001510static int update_open_stateid(struct nfs4_state *state,
1511 const nfs4_stateid *open_stateid,
1512 const nfs4_stateid *delegation,
1513 fmode_t fmode)
Trond Myklebust34310432008-12-23 15:21:38 -05001514{
Trond Myklebust1393d962016-09-22 13:39:13 -04001515 struct nfs_server *server = NFS_SERVER(state->inode);
1516 struct nfs_client *clp = server->nfs_client;
Trond Myklebust34310432008-12-23 15:21:38 -05001517 struct nfs_inode *nfsi = NFS_I(state->inode);
1518 struct nfs_delegation *deleg_cur;
Arnd Bergmann83aa3e02016-10-18 17:21:30 +02001519 nfs4_stateid freeme = { };
Trond Myklebust34310432008-12-23 15:21:38 -05001520 int ret = 0;
1521
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001522 fmode &= (FMODE_READ|FMODE_WRITE);
Trond Myklebust34310432008-12-23 15:21:38 -05001523
1524 rcu_read_lock();
1525 deleg_cur = rcu_dereference(nfsi->delegation);
1526 if (deleg_cur == NULL)
1527 goto no_delegation;
1528
1529 spin_lock(&deleg_cur->lock);
Trond Myklebust17f26b12013-08-21 15:48:42 -04001530 if (rcu_dereference(nfsi->delegation) != deleg_cur ||
Trond Myklebustd25be542013-02-05 11:43:28 -05001531 test_bit(NFS_DELEGATION_RETURNING, &deleg_cur->flags) ||
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001532 (deleg_cur->type & fmode) != fmode)
Trond Myklebust34310432008-12-23 15:21:38 -05001533 goto no_delegation_unlock;
1534
1535 if (delegation == NULL)
1536 delegation = &deleg_cur->stateid;
Trond Myklebustf597c532012-03-04 18:13:56 -05001537 else if (!nfs4_stateid_match(&deleg_cur->stateid, delegation))
Trond Myklebust34310432008-12-23 15:21:38 -05001538 goto no_delegation_unlock;
1539
Trond Myklebustb7391f42008-12-23 15:21:52 -05001540 nfs_mark_delegation_referenced(deleg_cur);
Trond Myklebust1393d962016-09-22 13:39:13 -04001541 __update_open_stateid(state, open_stateid, &deleg_cur->stateid,
1542 fmode, &freeme);
Trond Myklebust34310432008-12-23 15:21:38 -05001543 ret = 1;
1544no_delegation_unlock:
1545 spin_unlock(&deleg_cur->lock);
1546no_delegation:
1547 rcu_read_unlock();
1548
1549 if (!ret && open_stateid != NULL) {
Trond Myklebust1393d962016-09-22 13:39:13 -04001550 __update_open_stateid(state, open_stateid, NULL, fmode, &freeme);
Trond Myklebust34310432008-12-23 15:21:38 -05001551 ret = 1;
1552 }
Trond Myklebust4f14c192014-02-12 19:15:06 -05001553 if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
Trond Myklebust1393d962016-09-22 13:39:13 -04001554 nfs4_schedule_state_manager(clp);
1555 if (freeme.type != 0)
1556 nfs4_test_and_free_stateid(server, &freeme,
1557 state->owner->so_cred);
Trond Myklebust34310432008-12-23 15:21:38 -05001558
1559 return ret;
1560}
1561
Trond Myklebust39071e62015-01-24 15:07:56 -05001562static bool nfs4_update_lock_stateid(struct nfs4_lock_state *lsp,
1563 const nfs4_stateid *stateid)
1564{
1565 struct nfs4_state *state = lsp->ls_state;
1566 bool ret = false;
1567
1568 spin_lock(&state->state_lock);
1569 if (!nfs4_stateid_match_other(stateid, &lsp->ls_stateid))
1570 goto out_noupdate;
1571 if (!nfs4_stateid_is_newer(stateid, &lsp->ls_stateid))
1572 goto out_noupdate;
1573 nfs4_stateid_copy(&lsp->ls_stateid, stateid);
1574 ret = true;
1575out_noupdate:
1576 spin_unlock(&state->state_lock);
1577 return ret;
1578}
Trond Myklebust34310432008-12-23 15:21:38 -05001579
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001580static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001581{
1582 struct nfs_delegation *delegation;
1583
1584 rcu_read_lock();
1585 delegation = rcu_dereference(NFS_I(inode)->delegation);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001586 if (delegation == NULL || (delegation->type & fmode) == fmode) {
Trond Myklebustaac00a82007-07-05 19:02:21 -04001587 rcu_read_unlock();
1588 return;
1589 }
1590 rcu_read_unlock();
Bryan Schumaker57ec14c2012-06-20 15:53:44 -04001591 nfs4_inode_return_delegation(inode);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001592}
1593
Trond Myklebust6ee41262007-07-08 14:11:36 -04001594static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001595{
1596 struct nfs4_state *state = opendata->state;
1597 struct nfs_inode *nfsi = NFS_I(state->inode);
1598 struct nfs_delegation *delegation;
Trond Myklebustf448bad2013-05-29 15:36:40 -04001599 int open_mode = opendata->o_arg.open_flags;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001600 fmode_t fmode = opendata->o_arg.fmode;
Trond Myklebust2a606182015-08-19 22:30:00 -05001601 enum open_claim_type4 claim = opendata->o_arg.claim;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001602 nfs4_stateid stateid;
1603 int ret = -EAGAIN;
1604
Trond Myklebustaac00a82007-07-05 19:02:21 -04001605 for (;;) {
Anna Schumaker61beef72014-09-03 14:15:40 -04001606 spin_lock(&state->owner->so_lock);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001607 if (can_open_cached(state, fmode, open_mode)) {
Anna Schumaker61beef72014-09-03 14:15:40 -04001608 update_open_stateflags(state, fmode);
Trond Myklebust6ee41262007-07-08 14:11:36 -04001609 spin_unlock(&state->owner->so_lock);
Anna Schumaker61beef72014-09-03 14:15:40 -04001610 goto out_return_state;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001611 }
Anna Schumaker61beef72014-09-03 14:15:40 -04001612 spin_unlock(&state->owner->so_lock);
Trond Myklebust34310432008-12-23 15:21:38 -05001613 rcu_read_lock();
1614 delegation = rcu_dereference(nfsi->delegation);
Trond Myklebust2a606182015-08-19 22:30:00 -05001615 if (!can_open_delegated(delegation, fmode, claim)) {
Trond Myklebust34310432008-12-23 15:21:38 -05001616 rcu_read_unlock();
Trond Myklebust6ee41262007-07-08 14:11:36 -04001617 break;
Trond Myklebust34310432008-12-23 15:21:38 -05001618 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04001619 /* Save the delegation */
Trond Myklebustf597c532012-03-04 18:13:56 -05001620 nfs4_stateid_copy(&stateid, &delegation->stateid);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001621 rcu_read_unlock();
Trond Myklebustfa332942013-04-09 12:56:52 -04001622 nfs_release_seqid(opendata->o_arg.seqid);
Trond Myklebustbdeca1b2013-04-23 14:52:44 -04001623 if (!opendata->is_recover) {
1624 ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
1625 if (ret != 0)
1626 goto out;
1627 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04001628 ret = -EAGAIN;
Trond Myklebust34310432008-12-23 15:21:38 -05001629
1630 /* Try to update the stateid using the delegation */
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001631 if (update_open_stateid(state, NULL, &stateid, fmode))
Trond Myklebust34310432008-12-23 15:21:38 -05001632 goto out_return_state;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001633 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04001634out:
1635 return ERR_PTR(ret);
1636out_return_state:
1637 atomic_inc(&state->count);
1638 return state;
1639}
1640
Andy Adamsone23008e2012-10-02 21:07:32 -04001641static void
1642nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
1643{
1644 struct nfs_client *clp = NFS_SERVER(state->inode)->nfs_client;
1645 struct nfs_delegation *delegation;
1646 int delegation_flags = 0;
1647
1648 rcu_read_lock();
1649 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
1650 if (delegation)
1651 delegation_flags = delegation->flags;
1652 rcu_read_unlock();
Trond Myklebust72d79ff2015-10-02 11:44:54 -04001653 switch (data->o_arg.claim) {
1654 default:
1655 break;
1656 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
1657 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
Andy Adamsone23008e2012-10-02 21:07:32 -04001658 pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
1659 "returning a delegation for "
1660 "OPEN(CLAIM_DELEGATE_CUR)\n",
1661 clp->cl_hostname);
Trond Myklebust72d79ff2015-10-02 11:44:54 -04001662 return;
1663 }
1664 if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
Andy Adamsone23008e2012-10-02 21:07:32 -04001665 nfs_inode_set_delegation(state->inode,
1666 data->owner->so_cred,
1667 &data->o_res);
1668 else
1669 nfs_inode_reclaim_delegation(state->inode,
1670 data->owner->so_cred,
1671 &data->o_res);
1672}
1673
1674/*
1675 * Check the inode attributes against the CLAIM_PREVIOUS returned attributes
1676 * and update the nfs4_state.
1677 */
1678static struct nfs4_state *
1679_nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
1680{
1681 struct inode *inode = data->state->inode;
1682 struct nfs4_state *state = data->state;
1683 int ret;
1684
Weston Andros Adamsond2bfda22013-10-21 13:10:13 -04001685 if (!data->rpc_done) {
Anna Schumaker37a84842017-01-11 16:08:35 -05001686 if (data->rpc_status)
1687 return ERR_PTR(data->rpc_status);
Weston Andros Adamsond2bfda22013-10-21 13:10:13 -04001688 /* cached opens have already been processed */
1689 goto update;
Andy Adamsone23008e2012-10-02 21:07:32 -04001690 }
1691
Andy Adamsone23008e2012-10-02 21:07:32 -04001692 ret = nfs_refresh_inode(inode, &data->f_attr);
1693 if (ret)
Anna Schumaker37a84842017-01-11 16:08:35 -05001694 return ERR_PTR(ret);
Andy Adamsone23008e2012-10-02 21:07:32 -04001695
1696 if (data->o_res.delegation_type != 0)
1697 nfs4_opendata_check_deleg(data, state);
Weston Andros Adamsond2bfda22013-10-21 13:10:13 -04001698update:
Andy Adamsone23008e2012-10-02 21:07:32 -04001699 update_open_stateid(state, &data->o_res.stateid, NULL,
1700 data->o_arg.fmode);
Trond Myklebustd49f0422013-10-28 14:57:12 -04001701 atomic_inc(&state->count);
Andy Adamsone23008e2012-10-02 21:07:32 -04001702
1703 return state;
Andy Adamsone23008e2012-10-02 21:07:32 -04001704}
1705
Trond Myklebust4e2fcac2017-08-08 09:06:18 -04001706static struct inode *
1707nfs4_opendata_get_inode(struct nfs4_opendata *data)
1708{
1709 struct inode *inode;
1710
1711 switch (data->o_arg.claim) {
1712 case NFS4_OPEN_CLAIM_NULL:
1713 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
1714 case NFS4_OPEN_CLAIM_DELEGATE_PREV:
1715 if (!(data->f_attr.valid & NFS_ATTR_FATTR))
1716 return ERR_PTR(-EAGAIN);
1717 inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh,
1718 &data->f_attr, data->f_label);
1719 break;
1720 default:
1721 inode = d_inode(data->dentry);
1722 ihold(inode);
1723 nfs_refresh_inode(inode, &data->f_attr);
1724 }
1725 return inode;
1726}
1727
Andy Adamsone23008e2012-10-02 21:07:32 -04001728static struct nfs4_state *
Trond Myklebust75e8c482017-08-08 10:38:07 -04001729nfs4_opendata_find_nfs4_state(struct nfs4_opendata *data)
1730{
1731 struct nfs4_state *state;
1732 struct inode *inode;
1733
1734 inode = nfs4_opendata_get_inode(data);
1735 if (IS_ERR(inode))
1736 return ERR_CAST(inode);
1737 if (data->state != NULL && data->state->inode == inode) {
1738 state = data->state;
1739 atomic_inc(&state->count);
1740 } else
1741 state = nfs4_get_open_state(inode, data->owner);
1742 iput(inode);
1743 if (state == NULL)
1744 state = ERR_PTR(-ENOMEM);
1745 return state;
1746}
1747
Andy Adamsone23008e2012-10-02 21:07:32 -04001748static struct nfs4_state *
1749_nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001750{
Trond Myklebust75e8c482017-08-08 10:38:07 -04001751 struct nfs4_state *state;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001752
Trond Myklebustaac00a82007-07-05 19:02:21 -04001753 if (!data->rpc_done) {
Trond Myklebust6ee41262007-07-08 14:11:36 -04001754 state = nfs4_try_open_cached(data);
Olga Kornievskaia9759b0f2015-11-24 13:29:42 -05001755 trace_nfs4_cached_open(data->state);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001756 goto out;
1757 }
1758
Trond Myklebust75e8c482017-08-08 10:38:07 -04001759 state = nfs4_opendata_find_nfs4_state(data);
1760 if (IS_ERR(state))
1761 goto out;
1762
Andy Adamsone23008e2012-10-02 21:07:32 -04001763 if (data->o_res.delegation_type != 0)
1764 nfs4_opendata_check_deleg(data, state);
Trond Myklebust34310432008-12-23 15:21:38 -05001765 update_open_stateid(state, &data->o_res.stateid, NULL,
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001766 data->o_arg.fmode);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001767out:
Trond Myklebust7aa262b52013-02-28 16:19:59 -08001768 nfs_release_seqid(data->o_arg.seqid);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001769 return state;
1770}
1771
Andy Adamsone23008e2012-10-02 21:07:32 -04001772static struct nfs4_state *
1773nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
1774{
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04001775 struct nfs4_state *ret;
1776
Andy Adamsone23008e2012-10-02 21:07:32 -04001777 if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04001778 ret =_nfs4_opendata_reclaim_to_nfs4_state(data);
1779 else
1780 ret = _nfs4_opendata_to_nfs4_state(data);
1781 nfs4_sequence_free_slot(&data->o_res.seq_res);
1782 return ret;
Andy Adamsone23008e2012-10-02 21:07:32 -04001783}
1784
Trond Myklebust864472e2006-01-03 09:55:15 +01001785static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
1786{
1787 struct nfs_inode *nfsi = NFS_I(state->inode);
1788 struct nfs_open_context *ctx;
1789
1790 spin_lock(&state->inode->i_lock);
1791 list_for_each_entry(ctx, &nfsi->open_files, list) {
1792 if (ctx->state != state)
1793 continue;
1794 get_nfs_open_context(ctx);
1795 spin_unlock(&state->inode->i_lock);
1796 return ctx;
1797 }
1798 spin_unlock(&state->inode->i_lock);
1799 return ERR_PTR(-ENOENT);
1800}
1801
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001802static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx,
1803 struct nfs4_state *state, enum open_claim_type4 claim)
Trond Myklebust6f220ed2007-07-17 21:50:45 -04001804{
1805 struct nfs4_opendata *opendata;
1806
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001807 opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0,
David Quigley1775fd32013-05-22 12:50:42 -04001808 NULL, NULL, claim, GFP_NOFS);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04001809 if (opendata == NULL)
1810 return ERR_PTR(-ENOMEM);
1811 opendata->state = state;
1812 atomic_inc(&state->count);
1813 return opendata;
1814}
1815
Trond Myklebust24311f82015-09-20 10:50:17 -04001816static int nfs4_open_recover_helper(struct nfs4_opendata *opendata,
1817 fmode_t fmode)
Trond Myklebust864472e2006-01-03 09:55:15 +01001818{
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001819 struct nfs4_state *newstate;
Trond Myklebust864472e2006-01-03 09:55:15 +01001820 int ret;
1821
Trond Myklebust24311f82015-09-20 10:50:17 -04001822 if (!nfs4_mode_match_open_stateid(opendata->state, fmode))
NeilBrown39f897f2015-06-29 14:28:54 +10001823 return 0;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001824 opendata->o_arg.open_flags = 0;
1825 opendata->o_arg.fmode = fmode;
Trond Myklebustbe36e182015-02-27 17:04:17 -05001826 opendata->o_arg.share_access = nfs4_map_atomic_open_share(
1827 NFS_SB(opendata->dentry->d_sb),
1828 fmode, 0);
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001829 memset(&opendata->o_res, 0, sizeof(opendata->o_res));
1830 memset(&opendata->c_res, 0, sizeof(opendata->c_res));
1831 nfs4_init_opendata_res(opendata);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08001832 ret = _nfs4_recover_proc_open(opendata);
Trond Myklebust864472e2006-01-03 09:55:15 +01001833 if (ret != 0)
1834 return ret;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001835 newstate = nfs4_opendata_to_nfs4_state(opendata);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001836 if (IS_ERR(newstate))
1837 return PTR_ERR(newstate);
Trond Myklebust24311f82015-09-20 10:50:17 -04001838 if (newstate != opendata->state)
1839 ret = -ESTALE;
Al Viro643168c2011-06-22 18:20:23 -04001840 nfs4_close_state(newstate, fmode);
Trond Myklebust24311f82015-09-20 10:50:17 -04001841 return ret;
Trond Myklebust864472e2006-01-03 09:55:15 +01001842}
1843
1844static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state)
1845{
Trond Myklebust864472e2006-01-03 09:55:15 +01001846 int ret;
1847
Trond Myklebust4f14c192014-02-12 19:15:06 -05001848 /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */
1849 clear_bit(NFS_O_RDWR_STATE, &state->flags);
1850 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1851 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
Trond Myklebust864472e2006-01-03 09:55:15 +01001852 /* memory barrier prior to reading state->n_* */
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001853 clear_bit(NFS_DELEGATED_STATE, &state->flags);
Trond Myklebustfd068b22013-04-22 11:29:51 -04001854 clear_bit(NFS_OPEN_STATE, &state->flags);
Trond Myklebust864472e2006-01-03 09:55:15 +01001855 smp_rmb();
Trond Myklebust24311f82015-09-20 10:50:17 -04001856 ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
1857 if (ret != 0)
1858 return ret;
1859 ret = nfs4_open_recover_helper(opendata, FMODE_WRITE);
1860 if (ret != 0)
1861 return ret;
1862 ret = nfs4_open_recover_helper(opendata, FMODE_READ);
1863 if (ret != 0)
1864 return ret;
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001865 /*
1866 * We may have performed cached opens for all three recoveries.
1867 * Check if we need to update the current stateid.
1868 */
1869 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
Trond Myklebustf597c532012-03-04 18:13:56 -05001870 !nfs4_stateid_match(&state->stateid, &state->open_stateid)) {
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001871 write_seqlock(&state->seqlock);
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001872 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
Trond Myklebustf597c532012-03-04 18:13:56 -05001873 nfs4_stateid_copy(&state->stateid, &state->open_stateid);
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001874 write_sequnlock(&state->seqlock);
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001875 }
Trond Myklebust864472e2006-01-03 09:55:15 +01001876 return 0;
1877}
1878
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879/*
1880 * OPEN_RECLAIM:
1881 * reclaim state on the server after a reboot.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 */
Trond Myklebust539cd032007-06-05 11:46:42 -04001883static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884{
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001885 struct nfs_delegation *delegation;
Trond Myklebust864472e2006-01-03 09:55:15 +01001886 struct nfs4_opendata *opendata;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001887 fmode_t delegation_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 int status;
1889
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001890 opendata = nfs4_open_recoverdata_alloc(ctx, state,
1891 NFS4_OPEN_CLAIM_PREVIOUS);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04001892 if (IS_ERR(opendata))
1893 return PTR_ERR(opendata);
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001894 rcu_read_lock();
1895 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
Trond Myklebust15c831b2008-12-23 15:21:39 -05001896 if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0)
Trond Myklebust65bbf6b2007-08-27 09:57:46 -04001897 delegation_type = delegation->type;
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001898 rcu_read_unlock();
Trond Myklebust864472e2006-01-03 09:55:15 +01001899 opendata->o_arg.u.delegation_type = delegation_type;
1900 status = nfs4_open_recover(opendata, state);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001901 nfs4_opendata_put(opendata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 return status;
1903}
1904
Trond Myklebust539cd032007-06-05 11:46:42 -04001905static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906{
1907 struct nfs_server *server = NFS_SERVER(state->inode);
1908 struct nfs4_exception exception = { };
1909 int err;
1910 do {
Trond Myklebust539cd032007-06-05 11:46:42 -04001911 err = _nfs4_do_open_reclaim(ctx, state);
Trond Myklebust42113a72013-08-12 16:19:27 -04001912 trace_nfs4_open_reclaim(ctx, 0, err);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001913 if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
1914 continue;
Trond Myklebust168667c2010-10-19 19:47:49 -04001915 if (err != -NFS4ERR_DELAY)
Trond Myklebust202b50d2005-06-22 17:16:29 +00001916 break;
1917 nfs4_handle_exception(server, err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 } while (exception.retry);
1919 return err;
1920}
1921
Trond Myklebust864472e2006-01-03 09:55:15 +01001922static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
1923{
1924 struct nfs_open_context *ctx;
1925 int ret;
1926
1927 ctx = nfs4_state_find_open_context(state);
1928 if (IS_ERR(ctx))
Trond Myklebust91876b12013-03-28 14:01:33 -04001929 return -EAGAIN;
Trond Myklebust539cd032007-06-05 11:46:42 -04001930 ret = nfs4_do_open_reclaim(ctx, state);
Trond Myklebust864472e2006-01-03 09:55:15 +01001931 put_nfs_open_context(ctx);
1932 return ret;
1933}
1934
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04001935static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936{
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001937 switch (err) {
1938 default:
1939 printk(KERN_ERR "NFS: %s: unhandled error "
1940 "%d.\n", __func__, err);
1941 case 0:
1942 case -ENOENT:
Trond Myklebust8eee52a2015-06-04 13:51:13 -04001943 case -EAGAIN:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001944 case -ESTALE:
1945 break;
1946 case -NFS4ERR_BADSESSION:
1947 case -NFS4ERR_BADSLOT:
1948 case -NFS4ERR_BAD_HIGH_SLOT:
1949 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1950 case -NFS4ERR_DEADSESSION:
1951 set_bit(NFS_DELEGATED_STATE, &state->flags);
1952 nfs4_schedule_session_recovery(server->nfs_client->cl_session, err);
1953 return -EAGAIN;
1954 case -NFS4ERR_STALE_CLIENTID:
1955 case -NFS4ERR_STALE_STATEID:
1956 set_bit(NFS_DELEGATED_STATE, &state->flags);
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001957 /* Don't recall a delegation if it was lost */
1958 nfs4_schedule_lease_recovery(server->nfs_client);
1959 return -EAGAIN;
Chuck Lever352297b2013-10-17 14:13:24 -04001960 case -NFS4ERR_MOVED:
1961 nfs4_schedule_migration_recovery(server);
1962 return -EAGAIN;
Chuck Lever8ef2f8d2013-10-17 14:13:41 -04001963 case -NFS4ERR_LEASE_MOVED:
1964 nfs4_schedule_lease_moved_recovery(server->nfs_client);
1965 return -EAGAIN;
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001966 case -NFS4ERR_DELEG_REVOKED:
1967 case -NFS4ERR_ADMIN_REVOKED:
Trond Myklebust404ea3562016-09-22 13:39:08 -04001968 case -NFS4ERR_EXPIRED:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001969 case -NFS4ERR_BAD_STATEID:
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04001970 case -NFS4ERR_OPENMODE:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001971 nfs_inode_find_state_and_recover(state->inode,
1972 stateid);
1973 nfs4_schedule_stateid_recovery(server, state);
Trond Myklebust869f9df2014-11-10 18:43:56 -05001974 return -EAGAIN;
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001975 case -NFS4ERR_DELAY:
1976 case -NFS4ERR_GRACE:
1977 set_bit(NFS_DELEGATED_STATE, &state->flags);
1978 ssleep(1);
1979 return -EAGAIN;
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04001980 case -ENOMEM:
1981 case -NFS4ERR_DENIED:
1982 /* kill_proc(fl->fl_pid, SIGLOST, 1); */
1983 return 0;
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001984 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001985 return err;
1986}
1987
Trond Myklebust24311f82015-09-20 10:50:17 -04001988int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
1989 struct nfs4_state *state, const nfs4_stateid *stateid,
1990 fmode_t type)
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04001991{
1992 struct nfs_server *server = NFS_SERVER(state->inode);
1993 struct nfs4_opendata *opendata;
Trond Myklebust24311f82015-09-20 10:50:17 -04001994 int err = 0;
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04001995
1996 opendata = nfs4_open_recoverdata_alloc(ctx, state,
1997 NFS4_OPEN_CLAIM_DELEG_CUR_FH);
1998 if (IS_ERR(opendata))
1999 return PTR_ERR(opendata);
2000 nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
Jeff Layton5e99b532015-10-02 13:14:37 -04002001 write_seqlock(&state->seqlock);
2002 nfs4_stateid_copy(&state->stateid, &state->open_stateid);
2003 write_sequnlock(&state->seqlock);
Trond Myklebust24311f82015-09-20 10:50:17 -04002004 clear_bit(NFS_DELEGATED_STATE, &state->flags);
2005 switch (type & (FMODE_READ|FMODE_WRITE)) {
2006 case FMODE_READ|FMODE_WRITE:
2007 case FMODE_WRITE:
2008 err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
2009 if (err)
2010 break;
2011 err = nfs4_open_recover_helper(opendata, FMODE_WRITE);
2012 if (err)
2013 break;
2014 case FMODE_READ:
2015 err = nfs4_open_recover_helper(opendata, FMODE_READ);
2016 }
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04002017 nfs4_opendata_put(opendata);
2018 return nfs4_handle_delegation_recall_error(server, state, stateid, err);
2019}
2020
Chuck Leverbe05c862013-08-09 12:49:47 -04002021static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata)
2022{
2023 struct nfs4_opendata *data = calldata;
2024
Anna Schumaker7981c8a2017-01-10 11:39:53 -05002025 nfs4_setup_sequence(data->o_arg.server->nfs_client,
2026 &data->c_arg.seq_args, &data->c_res.seq_res, task);
Chuck Leverbe05c862013-08-09 12:49:47 -04002027}
2028
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002029static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
2030{
2031 struct nfs4_opendata *data = calldata;
2032
Trond Myklebust17ead6c2014-02-01 14:53:23 -05002033 nfs40_sequence_done(task, &data->c_res.seq_res);
Chuck Leverbe05c862013-08-09 12:49:47 -04002034
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002035 data->rpc_status = task->tk_status;
Trond Myklebust26e976a2006-01-03 09:55:21 +01002036 if (data->rpc_status == 0) {
Trond Myklebustf597c532012-03-04 18:13:56 -05002037 nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
Trond Myklebustbb226292008-01-02 15:19:18 -05002038 nfs_confirm_seqid(&data->owner->so_seqid, 0);
Trond Myklebust26e976a2006-01-03 09:55:21 +01002039 renew_lease(data->o_res.server, data->timestamp);
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002040 data->rpc_done = true;
Trond Myklebust26e976a2006-01-03 09:55:21 +01002041 }
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002042}
2043
2044static void nfs4_open_confirm_release(void *calldata)
2045{
2046 struct nfs4_opendata *data = calldata;
2047 struct nfs4_state *state = NULL;
2048
2049 /* If this request hasn't been cancelled, do nothing */
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002050 if (!data->cancelled)
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002051 goto out_free;
2052 /* In case of error, no cleanup! */
Trond Myklebust3e309912007-07-07 13:19:59 -04002053 if (!data->rpc_done)
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002054 goto out_free;
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002055 state = nfs4_opendata_to_nfs4_state(data);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04002056 if (!IS_ERR(state))
Al Viro643168c2011-06-22 18:20:23 -04002057 nfs4_close_state(state, data->o_arg.fmode);
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002058out_free:
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002059 nfs4_opendata_put(data);
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002060}
2061
2062static const struct rpc_call_ops nfs4_open_confirm_ops = {
Chuck Leverbe05c862013-08-09 12:49:47 -04002063 .rpc_call_prepare = nfs4_open_confirm_prepare,
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002064 .rpc_call_done = nfs4_open_confirm_done,
2065 .rpc_release = nfs4_open_confirm_release,
2066};
2067
2068/*
2069 * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata
2070 */
2071static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
2072{
David Howells2b0143b2015-03-17 22:25:59 +00002073 struct nfs_server *server = NFS_SERVER(d_inode(data->dir));
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002074 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04002075 struct rpc_message msg = {
2076 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM],
2077 .rpc_argp = &data->c_arg,
2078 .rpc_resp = &data->c_res,
2079 .rpc_cred = data->owner->so_cred,
2080 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04002081 struct rpc_task_setup task_setup_data = {
2082 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04002083 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002084 .callback_ops = &nfs4_open_confirm_ops,
2085 .callback_data = data,
Trond Myklebust101070c2008-02-19 20:04:23 -05002086 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002087 .flags = RPC_TASK_ASYNC,
2088 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002089 int status;
2090
Trond Myklebust17ead6c2014-02-01 14:53:23 -05002091 nfs4_init_sequence(&data->c_arg.seq_args, &data->c_res.seq_res, 1);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002092 kref_get(&data->kref);
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002093 data->rpc_done = false;
Trond Myklebust3e309912007-07-07 13:19:59 -04002094 data->rpc_status = 0;
Trond Myklebust5138fde2007-07-14 15:40:01 -04002095 data->timestamp = jiffies;
Benjamin Coddingtone92c1e02015-10-01 09:17:33 -04002096 if (data->is_recover)
2097 nfs4_set_sequence_privileged(&data->c_arg.seq_args);
Trond Myklebustc970aa82007-07-14 15:39:59 -04002098 task = rpc_run_task(&task_setup_data);
Trond Myklebust7a1218a2006-03-20 18:11:10 -05002099 if (IS_ERR(task))
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002100 return PTR_ERR(task);
Anna Schumaker820bf852017-01-11 15:01:43 -05002101 status = rpc_wait_for_completion_task(task);
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002102 if (status != 0) {
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002103 data->cancelled = true;
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002104 smp_wmb();
2105 } else
2106 status = data->rpc_status;
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05002107 rpc_put_task(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 return status;
2109}
2110
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002111static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112{
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002113 struct nfs4_opendata *data = calldata;
2114 struct nfs4_state_owner *sp = data->owner;
Trond Myklebust549b19c2013-04-16 18:42:34 -04002115 struct nfs_client *clp = sp->so_server->nfs_client;
Trond Myklebust2a606182015-08-19 22:30:00 -05002116 enum open_claim_type4 claim = data->o_arg.claim;
Trond Myklebust5138fde2007-07-14 15:40:01 -04002117
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002118 if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05002119 goto out_wait;
Trond Myklebustaac00a82007-07-05 19:02:21 -04002120 /*
2121 * Check if we still need to send an OPEN call, or if we can use
2122 * a delegation instead.
2123 */
2124 if (data->state != NULL) {
2125 struct nfs_delegation *delegation;
2126
Trond Myklebustdc0b0272008-12-23 15:21:56 -05002127 if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags))
Trond Myklebust6ee41262007-07-08 14:11:36 -04002128 goto out_no_action;
Trond Myklebustaac00a82007-07-05 19:02:21 -04002129 rcu_read_lock();
2130 delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
Trond Myklebust2a606182015-08-19 22:30:00 -05002131 if (can_open_delegated(delegation, data->o_arg.fmode, claim))
Trond Myklebust652f89f2011-12-09 19:05:58 -05002132 goto unlock_no_action;
Trond Myklebustaac00a82007-07-05 19:02:21 -04002133 rcu_read_unlock();
2134 }
Trond Myklebust95b72eb2012-04-20 19:24:51 -04002135 /* Update client id. */
Trond Myklebust549b19c2013-04-16 18:42:34 -04002136 data->o_arg.clientid = clp->cl_clientid;
Trond Myklebust2a606182015-08-19 22:30:00 -05002137 switch (claim) {
2138 default:
2139 break;
Trond Myklebust8188df12013-04-23 14:31:19 -04002140 case NFS4_OPEN_CLAIM_PREVIOUS:
2141 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
2142 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
Andy Adamsone23008e2012-10-02 21:07:32 -04002143 data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
Trond Myklebust8188df12013-04-23 14:31:19 -04002144 case NFS4_OPEN_CLAIM_FH:
2145 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
Trond Myklebust6f220ed2007-07-17 21:50:45 -04002146 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01002147 data->timestamp = jiffies;
Anna Schumaker42e1cca2017-01-09 15:48:22 -05002148 if (nfs4_setup_sequence(data->o_arg.server->nfs_client,
Andy Adamsond8985282009-04-01 09:22:21 -04002149 &data->o_arg.seq_args,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04002150 &data->o_res.seq_res,
2151 task) != 0)
2152 nfs_release_seqid(data->o_arg.seqid);
Trond Myklebust549b19c2013-04-16 18:42:34 -04002153
2154 /* Set the create mode (note dependency on the session type) */
2155 data->o_arg.createmode = NFS4_CREATE_UNCHECKED;
2156 if (data->o_arg.open_flags & O_EXCL) {
2157 data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE;
2158 if (nfs4_has_persistent_session(clp))
2159 data->o_arg.createmode = NFS4_CREATE_GUARDED;
2160 else if (clp->cl_mvops->minor_version > 0)
2161 data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE4_1;
2162 }
Trond Myklebust6ee41262007-07-08 14:11:36 -04002163 return;
Trond Myklebust652f89f2011-12-09 19:05:58 -05002164unlock_no_action:
Olga Kornievskaia9759b0f2015-11-24 13:29:42 -05002165 trace_nfs4_cached_open(data->state);
Trond Myklebust652f89f2011-12-09 19:05:58 -05002166 rcu_read_unlock();
Trond Myklebust6ee41262007-07-08 14:11:36 -04002167out_no_action:
2168 task->tk_action = NULL;
Trond Myklebustc8da19b2013-02-11 19:01:21 -05002169out_wait:
Trond Myklebustb75ad4c2012-11-29 17:27:47 -05002170 nfs4_sequence_done(task, &data->o_res.seq_res);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002171}
2172
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002173static void nfs4_open_done(struct rpc_task *task, void *calldata)
2174{
2175 struct nfs4_opendata *data = calldata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002177 data->rpc_status = task->tk_status;
Andy Adamsond8985282009-04-01 09:22:21 -04002178
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04002179 if (!nfs4_sequence_process(task, &data->o_res.seq_res))
Trond Myklebust14516c32010-07-31 14:29:06 -04002180 return;
Andy Adamsond8985282009-04-01 09:22:21 -04002181
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002182 if (task->tk_status == 0) {
Trond Myklebust807d66d82012-10-02 17:09:00 -07002183 if (data->o_res.f_attr->valid & NFS_ATTR_FATTR_TYPE) {
2184 switch (data->o_res.f_attr->mode & S_IFMT) {
Trond Myklebust6f926b52005-10-18 14:20:18 -07002185 case S_IFREG:
2186 break;
2187 case S_IFLNK:
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002188 data->rpc_status = -ELOOP;
Trond Myklebust6f926b52005-10-18 14:20:18 -07002189 break;
2190 case S_IFDIR:
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002191 data->rpc_status = -EISDIR;
Trond Myklebust6f926b52005-10-18 14:20:18 -07002192 break;
2193 default:
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002194 data->rpc_status = -ENOTDIR;
Trond Myklebust807d66d82012-10-02 17:09:00 -07002195 }
Trond Myklebust6f926b52005-10-18 14:20:18 -07002196 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01002197 renew_lease(data->o_res.server, data->timestamp);
Trond Myklebust0f9f95e2007-07-08 16:19:56 -04002198 if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
2199 nfs_confirm_seqid(&data->owner->so_seqid, 0);
Trond Myklebust6f926b52005-10-18 14:20:18 -07002200 }
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002201 data->rpc_done = true;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002202}
Trond Myklebust6f926b52005-10-18 14:20:18 -07002203
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002204static void nfs4_open_release(void *calldata)
2205{
2206 struct nfs4_opendata *data = calldata;
2207 struct nfs4_state *state = NULL;
2208
2209 /* If this request hasn't been cancelled, do nothing */
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002210 if (!data->cancelled)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002211 goto out_free;
2212 /* In case of error, no cleanup! */
Trond Myklebust3e309912007-07-07 13:19:59 -04002213 if (data->rpc_status != 0 || !data->rpc_done)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002214 goto out_free;
2215 /* In case we need an open_confirm, no cleanup! */
2216 if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)
2217 goto out_free;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002218 state = nfs4_opendata_to_nfs4_state(data);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04002219 if (!IS_ERR(state))
Al Viro643168c2011-06-22 18:20:23 -04002220 nfs4_close_state(state, data->o_arg.fmode);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002221out_free:
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002222 nfs4_opendata_put(data);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002223}
2224
2225static const struct rpc_call_ops nfs4_open_ops = {
2226 .rpc_call_prepare = nfs4_open_prepare,
2227 .rpc_call_done = nfs4_open_done,
2228 .rpc_release = nfs4_open_release,
2229};
2230
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002231static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002232{
David Howells2b0143b2015-03-17 22:25:59 +00002233 struct inode *dir = d_inode(data->dir);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002234 struct nfs_server *server = NFS_SERVER(dir);
2235 struct nfs_openargs *o_arg = &data->o_arg;
2236 struct nfs_openres *o_res = &data->o_res;
2237 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04002238 struct rpc_message msg = {
2239 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN],
2240 .rpc_argp = o_arg,
2241 .rpc_resp = o_res,
2242 .rpc_cred = data->owner->so_cred,
2243 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04002244 struct rpc_task_setup task_setup_data = {
2245 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04002246 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002247 .callback_ops = &nfs4_open_ops,
2248 .callback_data = data,
Trond Myklebust101070c2008-02-19 20:04:23 -05002249 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002250 .flags = RPC_TASK_ASYNC,
2251 };
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002252 int status;
2253
Chuck Levera9c92d62013-08-09 12:48:18 -04002254 nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002255 kref_get(&data->kref);
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002256 data->rpc_done = false;
Trond Myklebust3e309912007-07-07 13:19:59 -04002257 data->rpc_status = 0;
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002258 data->cancelled = false;
2259 data->is_recover = false;
Trond Myklebustbdeca1b2013-04-23 14:52:44 -04002260 if (isrecover) {
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04002261 nfs4_set_sequence_privileged(&o_arg->seq_args);
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002262 data->is_recover = true;
Trond Myklebustbdeca1b2013-04-23 14:52:44 -04002263 }
Trond Myklebustc970aa82007-07-14 15:39:59 -04002264 task = rpc_run_task(&task_setup_data);
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002265 if (IS_ERR(task))
2266 return PTR_ERR(task);
Anna Schumaker820bf852017-01-11 15:01:43 -05002267 status = rpc_wait_for_completion_task(task);
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002268 if (status != 0) {
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002269 data->cancelled = true;
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002270 smp_wmb();
2271 } else
2272 status = data->rpc_status;
2273 rpc_put_task(task);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002274
2275 return status;
2276}
2277
2278static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
2279{
David Howells2b0143b2015-03-17 22:25:59 +00002280 struct inode *dir = d_inode(data->dir);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002281 struct nfs_openres *o_res = &data->o_res;
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002282 int status;
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002283
2284 status = nfs4_run_open_task(data, 1);
2285 if (status != 0 || !data->rpc_done)
2286 return status;
2287
Trond Myklebust6926afd2012-01-07 13:22:46 -05002288 nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr);
2289
Anna Schumakerd7e98252017-01-11 16:13:29 -05002290 if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM)
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002291 status = _nfs4_proc_open_confirm(data);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002292
2293 return status;
2294}
2295
Trond Myklebustf3792d62014-07-10 08:54:32 -04002296/*
2297 * Additional permission checks in order to distinguish between an
2298 * open for read, and an open for execute. This works around the
2299 * fact that NFSv4 OPEN treats read and execute permissions as being
2300 * the same.
2301 * Note that in the non-execute case, we want to turn off permission
2302 * checking if we just created a new file (POSIX open() semantics).
2303 */
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002304static int nfs4_opendata_access(struct rpc_cred *cred,
2305 struct nfs4_opendata *opendata,
Weston Andros Adamsonf8d9a892013-01-03 16:42:29 -05002306 struct nfs4_state *state, fmode_t fmode,
2307 int openflags)
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002308{
2309 struct nfs_access_entry cache;
Anna Schumaker1e6f2092017-07-25 16:10:47 -04002310 u32 mask, flags;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002311
2312 /* access call failed or for some reason the server doesn't
2313 * support any access modes -- defer access call until later */
2314 if (opendata->o_res.access_supported == 0)
2315 return 0;
2316
2317 mask = 0;
Trond Myklebustf3792d62014-07-10 08:54:32 -04002318 /*
2319 * Use openflags to check for exec, because fmode won't
2320 * always have FMODE_EXEC set when file open for exec.
2321 */
Weston Andros Adamsonf8d9a892013-01-03 16:42:29 -05002322 if (openflags & __FMODE_EXEC) {
2323 /* ONLY check for exec rights */
Anna Schumaker1e6f2092017-07-25 16:10:47 -04002324 if (S_ISDIR(state->inode->i_mode))
2325 mask = NFS4_ACCESS_LOOKUP;
2326 else
2327 mask = NFS4_ACCESS_EXECUTE;
Trond Myklebustf3792d62014-07-10 08:54:32 -04002328 } else if ((fmode & FMODE_READ) && !opendata->file_created)
Anna Schumaker1e6f2092017-07-25 16:10:47 -04002329 mask = NFS4_ACCESS_READ;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002330
2331 cache.cred = cred;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002332 nfs_access_set_mask(&cache, opendata->o_res.access_result);
2333 nfs_access_add_cache(state->inode, &cache);
2334
Anna Schumaker1e6f2092017-07-25 16:10:47 -04002335 flags = NFS4_ACCESS_READ | NFS4_ACCESS_EXECUTE | NFS4_ACCESS_LOOKUP;
2336 if ((mask & ~cache.mask & flags) == 0)
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002337 return 0;
2338
Weston Andros Adamson998f40b2012-11-02 18:00:56 -04002339 return -EACCES;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002340}
2341
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002342/*
2343 * Note: On error, nfs4_proc_open will free the struct nfs4_opendata
2344 */
2345static int _nfs4_proc_open(struct nfs4_opendata *data)
2346{
David Howells2b0143b2015-03-17 22:25:59 +00002347 struct inode *dir = d_inode(data->dir);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002348 struct nfs_server *server = NFS_SERVER(dir);
2349 struct nfs_openargs *o_arg = &data->o_arg;
2350 struct nfs_openres *o_res = &data->o_res;
2351 int status;
2352
2353 status = nfs4_run_open_task(data, 0);
Trond Myklebust08ef7bd2011-10-18 16:11:49 -07002354 if (!data->rpc_done)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002355 return status;
Trond Myklebust08ef7bd2011-10-18 16:11:49 -07002356 if (status != 0) {
2357 if (status == -NFS4ERR_BADNAME &&
2358 !(o_arg->open_flags & O_CREAT))
2359 return -ENOENT;
2360 return status;
2361 }
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002362
Trond Myklebust6926afd2012-01-07 13:22:46 -05002363 nfs_fattr_map_and_free_names(server, &data->f_attr);
2364
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002365 if (o_arg->open_flags & O_CREAT) {
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002366 if (o_arg->open_flags & O_EXCL)
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002367 data->file_created = true;
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002368 else if (o_res->cinfo.before != o_res->cinfo.after)
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002369 data->file_created = true;
Trond Myklebust2dfc6172017-01-11 08:47:00 -05002370 if (data->file_created || dir->i_version != o_res->cinfo.after)
Trond Myklebustd3129ef2017-01-11 22:07:28 -05002371 update_changeattr(dir, &o_res->cinfo,
2372 o_res->f_attr->time_start);
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002373 }
Trond Myklebust0df5dd42010-04-11 16:48:44 -04002374 if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
2375 server->caps &= ~NFS_CAP_POSIX_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002376 if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002377 status = _nfs4_proc_open_confirm(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002378 if (status != 0)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002379 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002380 }
Trond Myklebust56e0d712017-04-15 19:20:01 -04002381 if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) {
2382 nfs4_sequence_free_slot(&o_res->seq_res);
Andy Adamson8935ef62014-05-23 06:22:59 -07002383 nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, o_res->f_label);
Trond Myklebust56e0d712017-04-15 19:20:01 -04002384 }
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002385 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002386}
2387
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388/*
2389 * OPEN_EXPIRED:
2390 * reclaim state on the server after a network partition.
2391 * Assumes caller holds the appropriate lock
2392 */
Trond Myklebust539cd032007-06-05 11:46:42 -04002393static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002394{
Trond Myklebuste56e0b782006-01-03 09:55:08 +01002395 struct nfs4_opendata *opendata;
Trond Myklebust864472e2006-01-03 09:55:15 +01002396 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397
Trond Myklebust4a1c0892013-03-15 14:57:33 -04002398 opendata = nfs4_open_recoverdata_alloc(ctx, state,
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002399 NFS4_OPEN_CLAIM_FH);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04002400 if (IS_ERR(opendata))
2401 return PTR_ERR(opendata);
Trond Myklebust864472e2006-01-03 09:55:15 +01002402 ret = nfs4_open_recover(opendata, state);
Trond Myklebust35d05772008-04-05 15:54:17 -04002403 if (ret == -ESTALE)
Al Viro3d4ff432011-06-22 18:40:12 -04002404 d_drop(ctx->dentry);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002405 nfs4_opendata_put(opendata);
Trond Myklebust864472e2006-01-03 09:55:15 +01002406 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407}
2408
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05002409static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
Trond Myklebust202b50d2005-06-22 17:16:29 +00002410{
Trond Myklebust539cd032007-06-05 11:46:42 -04002411 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust202b50d2005-06-22 17:16:29 +00002412 struct nfs4_exception exception = { };
2413 int err;
2414
2415 do {
Trond Myklebust539cd032007-06-05 11:46:42 -04002416 err = _nfs4_open_expired(ctx, state);
Trond Myklebust42113a72013-08-12 16:19:27 -04002417 trace_nfs4_open_expired(ctx, 0, err);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002418 if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
2419 continue;
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05002420 switch (err) {
2421 default:
2422 goto out;
2423 case -NFS4ERR_GRACE:
2424 case -NFS4ERR_DELAY:
2425 nfs4_handle_exception(server, err, &exception);
2426 err = 0;
2427 }
Trond Myklebust202b50d2005-06-22 17:16:29 +00002428 } while (exception.retry);
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05002429out:
Trond Myklebust202b50d2005-06-22 17:16:29 +00002430 return err;
2431}
2432
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
2434{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002435 struct nfs_open_context *ctx;
Trond Myklebust864472e2006-01-03 09:55:15 +01002436 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002437
Trond Myklebust864472e2006-01-03 09:55:15 +01002438 ctx = nfs4_state_find_open_context(state);
2439 if (IS_ERR(ctx))
Trond Myklebust91876b12013-03-28 14:01:33 -04002440 return -EAGAIN;
Trond Myklebust539cd032007-06-05 11:46:42 -04002441 ret = nfs4_do_open_expired(ctx, state);
Trond Myklebust864472e2006-01-03 09:55:15 +01002442 put_nfs_open_context(ctx);
2443 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444}
2445
Trond Myklebust41020b62016-09-22 13:38:58 -04002446static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state,
2447 const nfs4_stateid *stateid)
Trond Myklebust4dfd4f72014-10-17 15:10:25 +03002448{
Trond Myklebust41020b62016-09-22 13:38:58 -04002449 nfs_remove_bad_delegation(state->inode, stateid);
Trond Myklebust4dfd4f72014-10-17 15:10:25 +03002450 write_seqlock(&state->seqlock);
2451 nfs4_stateid_copy(&state->stateid, &state->open_stateid);
2452 write_sequnlock(&state->seqlock);
2453 clear_bit(NFS_DELEGATED_STATE, &state->flags);
2454}
2455
2456static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
2457{
2458 if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL)
Trond Myklebust41020b62016-09-22 13:38:58 -04002459 nfs_finish_clear_delegation_stateid(state, NULL);
Trond Myklebust4dfd4f72014-10-17 15:10:25 +03002460}
2461
2462static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
2463{
2464 /* NFSv4.0 doesn't allow for delegation recovery on open expire */
2465 nfs40_clear_delegation_stateid(state);
2466 return nfs4_open_expired(sp, state);
2467}
2468
Trond Myklebust45870d62016-09-22 13:38:59 -04002469static int nfs40_test_and_free_expired_stateid(struct nfs_server *server,
2470 nfs4_stateid *stateid,
2471 struct rpc_cred *cred)
2472{
2473 return -NFS4ERR_BAD_STATEID;
2474}
2475
Bryan Schumakerf062eb62011-06-02 14:59:10 -04002476#if defined(CONFIG_NFS_V4_1)
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002477static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
2478 nfs4_stateid *stateid,
2479 struct rpc_cred *cred)
2480{
2481 int status;
2482
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002483 switch (stateid->type) {
2484 default:
2485 break;
2486 case NFS4_INVALID_STATEID_TYPE:
2487 case NFS4_SPECIAL_STATEID_TYPE:
2488 return -NFS4ERR_BAD_STATEID;
2489 case NFS4_REVOKED_STATEID_TYPE:
2490 goto out_free;
2491 }
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002492
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002493 status = nfs41_test_stateid(server, stateid, cred);
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002494 switch (status) {
2495 case -NFS4ERR_EXPIRED:
2496 case -NFS4ERR_ADMIN_REVOKED:
2497 case -NFS4ERR_DELEG_REVOKED:
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002498 break;
2499 default:
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002500 return status;
2501 }
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002502out_free:
2503 /* Ack the revoked state to the server */
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04002504 nfs41_free_stateid(server, stateid, cred, true);
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002505 return -NFS4ERR_EXPIRED;
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002506}
2507
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002508static void nfs41_check_delegation_stateid(struct nfs4_state *state)
Bryan Schumakerf062eb62011-06-02 14:59:10 -04002509{
Bryan Schumakerf062eb62011-06-02 14:59:10 -04002510 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002511 nfs4_stateid stateid;
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002512 struct nfs_delegation *delegation;
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002513 struct rpc_cred *cred;
2514 int status;
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002515
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002516 /* Get the delegation credential for use by test/free_stateid */
2517 rcu_read_lock();
2518 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002519 if (delegation == NULL) {
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002520 rcu_read_unlock();
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002521 return;
2522 }
2523
2524 nfs4_stateid_copy(&stateid, &delegation->stateid);
Olga Kornievskaia0e3d3e52017-03-30 13:49:03 -04002525 if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) ||
2526 !test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
2527 &delegation->flags)) {
Trond Myklebust4c8e5442016-09-22 13:38:55 -04002528 rcu_read_unlock();
Trond Myklebust41020b62016-09-22 13:38:58 -04002529 nfs_finish_clear_delegation_stateid(state, &stateid);
Trond Myklebust4c8e5442016-09-22 13:38:55 -04002530 return;
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002531 }
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002532
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002533 cred = get_rpccred(delegation->cred);
2534 rcu_read_unlock();
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002535 status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002536 trace_nfs4_test_delegation_stateid(state, NULL, status);
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002537 if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
Trond Myklebust41020b62016-09-22 13:38:58 -04002538 nfs_finish_clear_delegation_stateid(state, &stateid);
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002539
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002540 put_rpccred(cred);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002541}
2542
2543/**
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002544 * nfs41_check_expired_locks - possibly free a lock stateid
2545 *
2546 * @state: NFSv4 state for an inode
2547 *
2548 * Returns NFS_OK if recovery for this stateid is now finished.
2549 * Otherwise a negative NFS4ERR value is returned.
2550 */
2551static int nfs41_check_expired_locks(struct nfs4_state *state)
2552{
2553 int status, ret = NFS_OK;
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002554 struct nfs4_lock_state *lsp, *prev = NULL;
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002555 struct nfs_server *server = NFS_SERVER(state->inode);
2556
2557 if (!test_bit(LK_STATE_IN_USE, &state->flags))
2558 goto out;
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002559
2560 spin_lock(&state->state_lock);
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002561 list_for_each_entry(lsp, &state->lock_states, ls_locks) {
2562 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
2563 struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
2564
Elena Reshetova194bc1f2017-10-20 12:53:36 +03002565 refcount_inc(&lsp->ls_count);
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002566 spin_unlock(&state->state_lock);
2567
2568 nfs4_put_lock_state(prev);
2569 prev = lsp;
2570
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002571 status = nfs41_test_and_free_expired_stateid(server,
2572 &lsp->ls_stateid,
2573 cred);
2574 trace_nfs4_test_lock_stateid(state, lsp, status);
2575 if (status == -NFS4ERR_EXPIRED ||
2576 status == -NFS4ERR_BAD_STATEID) {
2577 clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
Trond Myklebust67dd4832016-09-22 13:39:17 -04002578 lsp->ls_stateid.type = NFS4_INVALID_STATEID_TYPE;
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002579 if (!recover_lost_locks)
2580 set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
2581 } else if (status != NFS_OK) {
2582 ret = status;
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002583 nfs4_put_lock_state(prev);
2584 goto out;
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002585 }
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002586 spin_lock(&state->state_lock);
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002587 }
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002588 }
2589 spin_unlock(&state->state_lock);
2590 nfs4_put_lock_state(prev);
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002591out:
2592 return ret;
2593}
2594
2595/**
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002596 * nfs41_check_open_stateid - possibly free an open stateid
2597 *
2598 * @state: NFSv4 state for an inode
2599 *
2600 * Returns NFS_OK if recovery for this stateid is now finished.
2601 * Otherwise a negative NFS4ERR value is returned.
2602 */
2603static int nfs41_check_open_stateid(struct nfs4_state *state)
2604{
2605 struct nfs_server *server = NFS_SERVER(state->inode);
Bryan Schumakerfcb6d9c2012-09-26 15:25:53 -04002606 nfs4_stateid *stateid = &state->open_stateid;
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002607 struct rpc_cred *cred = state->owner->so_cred;
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002608 int status;
2609
Trond Myklebustb134fc42016-09-22 13:39:16 -04002610 if (test_bit(NFS_OPEN_STATE, &state->flags) == 0) {
Trond Myklebust8a64c4e2016-09-22 13:39:21 -04002611 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) {
2612 if (nfs4_have_delegation(state->inode, state->state))
2613 return NFS_OK;
2614 return -NFS4ERR_OPENMODE;
2615 }
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002616 return -NFS4ERR_BAD_STATEID;
Trond Myklebustb134fc42016-09-22 13:39:16 -04002617 }
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002618 status = nfs41_test_and_free_expired_stateid(server, stateid, cred);
Trond Myklebust08cb47f2013-08-20 21:59:40 -04002619 trace_nfs4_test_open_stateid(state, NULL, status);
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002620 if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) {
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002621 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
2622 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
2623 clear_bit(NFS_O_RDWR_STATE, &state->flags);
Trond Myklebustfd068b22013-04-22 11:29:51 -04002624 clear_bit(NFS_OPEN_STATE, &state->flags);
Trond Myklebust67dd4832016-09-22 13:39:17 -04002625 stateid->type = NFS4_INVALID_STATEID_TYPE;
Trond Myklebust8a64c4e2016-09-22 13:39:21 -04002626 return status;
Trond Myklebustc0ca0e52017-08-08 21:39:28 -04002627 }
Trond Myklebust8a64c4e2016-09-22 13:39:21 -04002628 if (nfs_open_stateid_recover_openmode(state))
2629 return -NFS4ERR_OPENMODE;
2630 return NFS_OK;
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05002631}
2632
2633static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
2634{
Chuck Levereb64cf92012-07-11 16:30:05 -04002635 int status;
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05002636
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002637 nfs41_check_delegation_stateid(state);
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002638 status = nfs41_check_expired_locks(state);
2639 if (status != NFS_OK)
2640 return status;
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002641 status = nfs41_check_open_stateid(state);
Chuck Levereb64cf92012-07-11 16:30:05 -04002642 if (status != NFS_OK)
2643 status = nfs4_open_expired(sp, state);
2644 return status;
Bryan Schumakerf062eb62011-06-02 14:59:10 -04002645}
2646#endif
2647
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648/*
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002649 * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-*
2650 * fields corresponding to attributes that were used to store the verifier.
2651 * Make sure we clobber those fields in the later setattr call
2652 */
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002653static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata,
2654 struct iattr *sattr, struct nfs4_label **label)
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002655{
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002656 const u32 *attrset = opendata->o_res.attrset;
2657
2658 if ((attrset[1] & FATTR4_WORD1_TIME_ACCESS) &&
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002659 !(sattr->ia_valid & ATTR_ATIME_SET))
2660 sattr->ia_valid |= ATTR_ATIME;
2661
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002662 if ((attrset[1] & FATTR4_WORD1_TIME_MODIFY) &&
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002663 !(sattr->ia_valid & ATTR_MTIME_SET))
2664 sattr->ia_valid |= ATTR_MTIME;
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002665
2666 /* Except MODE, it seems harmless of setting twice. */
Benjamin Coddingtona4306072017-01-24 11:34:20 -05002667 if (opendata->o_arg.createmode != NFS4_CREATE_EXCLUSIVE &&
Benjamin Coddington501e7a42017-06-02 11:21:34 -04002668 (attrset[1] & FATTR4_WORD1_MODE ||
2669 attrset[2] & FATTR4_WORD2_MODE_UMASK))
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002670 sattr->ia_valid &= ~ATTR_MODE;
2671
2672 if (attrset[2] & FATTR4_WORD2_SECURITY_LABEL)
2673 *label = NULL;
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002674}
2675
Trond Myklebustc21443c2013-02-07 14:26:21 -05002676static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
2677 fmode_t fmode,
2678 int flags,
Trond Myklebust3efb9722013-05-29 13:17:04 -04002679 struct nfs_open_context *ctx)
Trond Myklebustc21443c2013-02-07 14:26:21 -05002680{
2681 struct nfs4_state_owner *sp = opendata->owner;
2682 struct nfs_server *server = sp->so_server;
Trond Myklebust275bb302013-05-29 13:11:28 -04002683 struct dentry *dentry;
Trond Myklebustc21443c2013-02-07 14:26:21 -05002684 struct nfs4_state *state;
2685 unsigned int seq;
2686 int ret;
2687
2688 seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
2689
2690 ret = _nfs4_proc_open(opendata);
Trond Myklebustdca780012014-10-23 19:23:03 +03002691 if (ret != 0)
Trond Myklebustc21443c2013-02-07 14:26:21 -05002692 goto out;
2693
2694 state = nfs4_opendata_to_nfs4_state(opendata);
2695 ret = PTR_ERR(state);
2696 if (IS_ERR(state))
2697 goto out;
Trond Myklebusta974dee2017-02-08 11:29:46 -05002698 ctx->state = state;
Trond Myklebustc21443c2013-02-07 14:26:21 -05002699 if (server->caps & NFS_CAP_POSIX_LOCK)
2700 set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
Jeff Laytona8ce3772016-09-17 18:17:35 -04002701 if (opendata->o_res.rflags & NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK)
2702 set_bit(NFS_STATE_MAY_NOTIFY_LOCK, &state->flags);
Trond Myklebustc21443c2013-02-07 14:26:21 -05002703
Trond Myklebust275bb302013-05-29 13:11:28 -04002704 dentry = opendata->dentry;
David Howells2b0143b2015-03-17 22:25:59 +00002705 if (d_really_is_negative(dentry)) {
Al Viro668d0cd2016-03-08 12:44:17 -05002706 struct dentry *alias;
Trond Myklebust275bb302013-05-29 13:11:28 -04002707 d_drop(dentry);
Al Viro668d0cd2016-03-08 12:44:17 -05002708 alias = d_exact_alias(dentry, state->inode);
2709 if (!alias)
2710 alias = d_splice_alias(igrab(state->inode), dentry);
2711 /* d_splice_alias() can't fail here - it's a non-directory */
2712 if (alias) {
Trond Myklebust275bb302013-05-29 13:11:28 -04002713 dput(ctx->dentry);
Al Viro668d0cd2016-03-08 12:44:17 -05002714 ctx->dentry = dentry = alias;
Trond Myklebust275bb302013-05-29 13:11:28 -04002715 }
2716 nfs_set_verifier(dentry,
David Howells2b0143b2015-03-17 22:25:59 +00002717 nfs_save_change_attribute(d_inode(opendata->dir)));
Trond Myklebust275bb302013-05-29 13:11:28 -04002718 }
2719
Trond Myklebustc21443c2013-02-07 14:26:21 -05002720 ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags);
2721 if (ret != 0)
2722 goto out;
2723
David Howells2b0143b2015-03-17 22:25:59 +00002724 if (d_inode(dentry) == state->inode) {
Trond Myklebustc45ffdd2013-05-29 13:34:46 -04002725 nfs_inode_attach_open_context(ctx);
2726 if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
2727 nfs4_schedule_stateid_recovery(server, state);
2728 }
Trond Myklebustc21443c2013-02-07 14:26:21 -05002729out:
2730 return ret;
2731}
2732
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002733/*
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002734 * Returns a referenced nfs4_state
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735 */
Andy Adamson82be4172012-05-23 05:02:35 -04002736static int _nfs4_do_open(struct inode *dir,
Trond Myklebust4197a052013-05-29 12:37:49 -04002737 struct nfs_open_context *ctx,
Andy Adamson82be4172012-05-23 05:02:35 -04002738 int flags,
2739 struct iattr *sattr,
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002740 struct nfs4_label *label,
2741 int *opened)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002742{
2743 struct nfs4_state_owner *sp;
2744 struct nfs4_state *state = NULL;
2745 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01002746 struct nfs4_opendata *opendata;
Trond Myklebust4197a052013-05-29 12:37:49 -04002747 struct dentry *dentry = ctx->dentry;
2748 struct rpc_cred *cred = ctx->cred;
2749 struct nfs4_threshold **ctx_th = &ctx->mdsthreshold;
2750 fmode_t fmode = ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002751 enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL;
David Quigley1775fd32013-05-22 12:50:42 -04002752 struct nfs4_label *olabel = NULL;
Trond Myklebustaac00a82007-07-05 19:02:21 -04002753 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754
2755 /* Protect against reboot recovery conflicts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002756 status = -ENOMEM;
Trond Myklebustd1e284d2012-01-17 22:04:24 -05002757 sp = nfs4_get_state_owner(server, cred, GFP_KERNEL);
2758 if (sp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
2760 goto out_err;
2761 }
Anna Schumaker334f87d2017-01-11 16:17:17 -05002762 status = nfs4_client_recover_expired_lease(server->nfs_client);
Trond Myklebust58d97142006-01-03 09:55:24 +01002763 if (status != 0)
Trond Myklebustb4454fe2006-01-03 09:55:25 +01002764 goto err_put_state_owner;
David Howells2b0143b2015-03-17 22:25:59 +00002765 if (d_really_is_positive(dentry))
2766 nfs4_return_incompatible_delegation(d_inode(dentry), fmode);
Trond Myklebust58d97142006-01-03 09:55:24 +01002767 status = -ENOMEM;
David Howells2b0143b2015-03-17 22:25:59 +00002768 if (d_really_is_positive(dentry))
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002769 claim = NFS4_OPEN_CLAIM_FH;
Trond Myklebust4a1c0892013-03-15 14:57:33 -04002770 opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr,
David Quigley1775fd32013-05-22 12:50:42 -04002771 label, claim, GFP_KERNEL);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01002772 if (opendata == NULL)
Trond Myklebust95d35cb2008-12-23 15:21:45 -05002773 goto err_put_state_owner;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774
David Quigley14c43f72013-05-22 12:50:43 -04002775 if (label) {
2776 olabel = nfs4_label_alloc(server, GFP_KERNEL);
2777 if (IS_ERR(olabel)) {
2778 status = PTR_ERR(olabel);
2779 goto err_opendata_put;
2780 }
2781 }
2782
Trond Myklebuste911b812014-03-26 13:24:37 -07002783 if (server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
2784 if (!opendata->f_attr.mdsthreshold) {
2785 opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
2786 if (!opendata->f_attr.mdsthreshold)
2787 goto err_free_label;
2788 }
Trond Myklebust1549210f2012-06-05 09:16:47 -04002789 opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0];
Andy Adamson82be4172012-05-23 05:02:35 -04002790 }
David Howells2b0143b2015-03-17 22:25:59 +00002791 if (d_really_is_positive(dentry))
2792 opendata->state = nfs4_get_open_state(d_inode(dentry), sp);
Trond Myklebustaac00a82007-07-05 19:02:21 -04002793
Trond Myklebust3efb9722013-05-29 13:17:04 -04002794 status = _nfs4_open_and_get_state(opendata, fmode, flags, ctx);
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002795 if (status != 0)
David Quigley14c43f72013-05-22 12:50:43 -04002796 goto err_free_label;
Trond Myklebust3efb9722013-05-29 13:17:04 -04002797 state = ctx->state;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002798
NeilBrownefcbc042015-07-30 13:00:56 +10002799 if ((opendata->o_arg.open_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) &&
Trond Myklebust549b19c2013-04-16 18:42:34 -04002800 (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) {
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002801 nfs4_exclusive_attrset(opendata, sattr, &label);
Tigran Mkrtchyana1d1c4f2016-05-12 11:16:38 +02002802 /*
2803 * send create attributes which was not set by open
2804 * with an extra setattr.
2805 */
2806 if (sattr->ia_valid & NFS4_VALID_ATTRS) {
2807 nfs_fattr_init(opendata->o_res.f_attr);
2808 status = nfs4_do_setattr(state->inode, cred,
2809 opendata->o_res.f_attr, sattr,
NeilBrown29b59f92016-10-13 15:26:47 +11002810 ctx, label, olabel);
Tigran Mkrtchyana1d1c4f2016-05-12 11:16:38 +02002811 if (status == 0) {
2812 nfs_setattr_update_inode(state->inode, sattr,
2813 opendata->o_res.f_attr);
2814 nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
2815 }
David Quigley1775fd32013-05-22 12:50:42 -04002816 }
Trond Myklebust0ab64e02010-04-16 16:22:51 -04002817 }
Kinglong Meec5c3fb52015-08-26 21:11:39 +08002818 if (opened && opendata->file_created)
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002819 *opened |= FILE_CREATED;
Andy Adamson82be4172012-05-23 05:02:35 -04002820
Trond Myklebuste911b812014-03-26 13:24:37 -07002821 if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) {
Andy Adamson82be4172012-05-23 05:02:35 -04002822 *ctx_th = opendata->f_attr.mdsthreshold;
Trond Myklebuste911b812014-03-26 13:24:37 -07002823 opendata->f_attr.mdsthreshold = NULL;
2824 }
Andy Adamson82be4172012-05-23 05:02:35 -04002825
David Quigley14c43f72013-05-22 12:50:43 -04002826 nfs4_label_free(olabel);
2827
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002828 nfs4_opendata_put(opendata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002829 nfs4_put_state_owner(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 return 0;
David Quigley14c43f72013-05-22 12:50:43 -04002831err_free_label:
2832 nfs4_label_free(olabel);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002833err_opendata_put:
2834 nfs4_opendata_put(opendata);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01002835err_put_state_owner:
2836 nfs4_put_state_owner(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837out_err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838 return status;
2839}
2840
2841
Andy Adamson82be4172012-05-23 05:02:35 -04002842static struct nfs4_state *nfs4_do_open(struct inode *dir,
Trond Myklebust4197a052013-05-29 12:37:49 -04002843 struct nfs_open_context *ctx,
Andy Adamson82be4172012-05-23 05:02:35 -04002844 int flags,
2845 struct iattr *sattr,
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002846 struct nfs4_label *label,
2847 int *opened)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848{
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002849 struct nfs_server *server = NFS_SERVER(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850 struct nfs4_exception exception = { };
2851 struct nfs4_state *res;
2852 int status;
2853
2854 do {
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002855 status = _nfs4_do_open(dir, ctx, flags, sattr, label, opened);
Trond Myklebust3efb9722013-05-29 13:17:04 -04002856 res = ctx->state;
Trond Myklebust42113a72013-08-12 16:19:27 -04002857 trace_nfs4_open_file(ctx, flags, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858 if (status == 0)
2859 break;
2860 /* NOTE: BAD_SEQID means the server and client disagree about the
2861 * book-keeping w.r.t. state-changing operations
2862 * (OPEN/CLOSE/LOCK/LOCKU...)
2863 * It is actually a sign of a bug on the client or on the server.
2864 *
2865 * If we receive a BAD_SEQID error in the particular case of
Trond Myklebustcee54fc2005-10-18 14:20:12 -07002866 * doing an OPEN, we assume that nfs_increment_open_seqid() will
Linus Torvalds1da177e2005-04-16 15:20:36 -07002867 * have unhashed the old state_owner for us, and that we can
2868 * therefore safely retry using a new one. We should still warn
2869 * the user though...
2870 */
2871 if (status == -NFS4ERR_BAD_SEQID) {
Trond Myklebust9a3ba432012-03-12 18:01:48 -04002872 pr_warn_ratelimited("NFS: v4 server %s "
Trond Myklebust6f43ddc2007-07-08 16:49:11 -04002873 " returned a bad sequence-id error!\n",
2874 NFS_SERVER(dir)->nfs_client->cl_hostname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002875 exception.retry = 1;
2876 continue;
2877 }
Trond Myklebust550f5742005-10-18 14:20:21 -07002878 /*
2879 * BAD_STATEID on OPEN means that the server cancelled our
2880 * state before it received the OPEN_CONFIRM.
2881 * Recover by retrying the request as per the discussion
2882 * on Page 181 of RFC3530.
2883 */
2884 if (status == -NFS4ERR_BAD_STATEID) {
2885 exception.retry = 1;
2886 continue;
2887 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04002888 if (status == -EAGAIN) {
2889 /* We must have found a delegation */
2890 exception.retry = 1;
2891 continue;
2892 }
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002893 if (nfs4_clear_cap_atomic_open_v1(server, status, &exception))
2894 continue;
2895 res = ERR_PTR(nfs4_handle_exception(server,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002896 status, &exception));
2897 } while (exception.retry);
2898 return res;
2899}
2900
Trond Myklebust8487c472016-06-26 08:44:35 -04002901static int _nfs4_do_setattr(struct inode *inode,
2902 struct nfs_setattrargs *arg,
2903 struct nfs_setattrres *res,
2904 struct rpc_cred *cred,
NeilBrown29b59f92016-10-13 15:26:47 +11002905 struct nfs_open_context *ctx)
Trond Myklebust8487c472016-06-26 08:44:35 -04002906{
2907 struct nfs_server *server = NFS_SERVER(inode);
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002908 struct rpc_message msg = {
Trond Myklebust8487c472016-06-26 08:44:35 -04002909 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
2910 .rpc_argp = arg,
2911 .rpc_resp = res,
2912 .rpc_cred = cred,
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002913 };
Trond Myklebust8487c472016-06-26 08:44:35 -04002914 struct rpc_cred *delegation_cred = NULL;
2915 unsigned long timestamp = jiffies;
2916 fmode_t fmode;
2917 bool truncate;
2918 int status;
2919
2920 nfs_fattr_init(res->fattr);
2921
2922 /* Servers should only apply open mode checks for file size changes */
2923 truncate = (arg->iap->ia_valid & ATTR_SIZE) ? true : false;
2924 fmode = truncate ? FMODE_WRITE : FMODE_READ;
2925
2926 if (nfs4_copy_delegation_stateid(inode, fmode, &arg->stateid, &delegation_cred)) {
2927 /* Use that stateid */
NeilBrown29b59f92016-10-13 15:26:47 +11002928 } else if (truncate && ctx != NULL) {
NeilBrown17393472016-10-13 15:26:47 +11002929 struct nfs_lock_context *l_ctx;
NeilBrown29b59f92016-10-13 15:26:47 +11002930 if (!nfs4_valid_open_stateid(ctx->state))
Trond Myklebust8487c472016-06-26 08:44:35 -04002931 return -EBADF;
NeilBrown17393472016-10-13 15:26:47 +11002932 l_ctx = nfs_get_lock_context(ctx);
2933 if (IS_ERR(l_ctx))
2934 return PTR_ERR(l_ctx);
NeilBrown7a0566b2016-12-06 15:50:06 -05002935 status = nfs4_select_rw_stateid(ctx->state, FMODE_WRITE, l_ctx,
2936 &arg->stateid, &delegation_cred);
2937 nfs_put_lock_context(l_ctx);
2938 if (status == -EIO)
Trond Myklebust8487c472016-06-26 08:44:35 -04002939 return -EBADF;
2940 } else
2941 nfs4_stateid_copy(&arg->stateid, &zero_stateid);
2942 if (delegation_cred)
2943 msg.rpc_cred = delegation_cred;
2944
2945 status = nfs4_call_sync(server->client, server, &msg, &arg->seq_args, &res->seq_res, 1);
2946
2947 put_rpccred(delegation_cred);
NeilBrown29b59f92016-10-13 15:26:47 +11002948 if (status == 0 && ctx != NULL)
Trond Myklebust8487c472016-06-26 08:44:35 -04002949 renew_lease(server, timestamp);
2950 trace_nfs4_setattr(inode, &arg->stateid, status);
2951 return status;
2952}
2953
2954static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
2955 struct nfs_fattr *fattr, struct iattr *sattr,
NeilBrown29b59f92016-10-13 15:26:47 +11002956 struct nfs_open_context *ctx, struct nfs4_label *ilabel,
Trond Myklebust8487c472016-06-26 08:44:35 -04002957 struct nfs4_label *olabel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002958{
Trond Myklebust3e4f6292006-03-20 13:44:46 -05002959 struct nfs_server *server = NFS_SERVER(inode);
NeilBrown29b59f92016-10-13 15:26:47 +11002960 struct nfs4_state *state = ctx ? ctx->state : NULL;
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002961 struct nfs_setattrargs arg = {
2962 .fh = NFS_FH(inode),
2963 .iap = sattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964 .server = server,
2965 .bitmask = server->attr_bitmask,
David Quigley1775fd32013-05-22 12:50:42 -04002966 .label = ilabel,
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002967 };
2968 struct nfs_setattrres res = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969 .fattr = fattr,
David Quigley1775fd32013-05-22 12:50:42 -04002970 .label = olabel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 .server = server,
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002972 };
Trond Myklebust8487c472016-06-26 08:44:35 -04002973 struct nfs4_exception exception = {
2974 .state = state,
2975 .inode = inode,
2976 .stateid = &arg.stateid,
2977 };
2978 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979
David Quigleyaa9c2662013-05-22 12:50:44 -04002980 arg.bitmask = nfs4_bitmask(server, ilabel);
2981 if (ilabel)
2982 arg.bitmask = nfs4_bitmask(server, olabel);
2983
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 do {
NeilBrown29b59f92016-10-13 15:26:47 +11002985 err = _nfs4_do_setattr(inode, &arg, &res, cred, ctx);
Trond Myklebust451146b2012-04-18 16:29:11 -04002986 switch (err) {
2987 case -NFS4ERR_OPENMODE:
Trond Myklebust721ccfb2013-04-29 11:11:58 -04002988 if (!(sattr->ia_valid & ATTR_SIZE)) {
2989 pr_warn_once("NFSv4: server %s is incorrectly "
2990 "applying open mode checks to "
2991 "a SETATTR that is not "
2992 "changing file size.\n",
2993 server->nfs_client->cl_hostname);
2994 }
Trond Myklebust451146b2012-04-18 16:29:11 -04002995 if (state && !(state->state & FMODE_WRITE)) {
2996 err = -EBADF;
2997 if (sattr->ia_valid & ATTR_OPEN)
2998 err = -EACCES;
2999 goto out;
3000 }
3001 }
3002 err = nfs4_handle_exception(server, err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 } while (exception.retry);
Trond Myklebust451146b2012-04-18 16:29:11 -04003004out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 return err;
3006}
3007
Peng Tao500d7012015-09-22 11:35:22 +08003008static bool
3009nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
3010{
3011 if (inode == NULL || !nfs_have_layout(inode))
3012 return false;
3013
3014 return pnfs_wait_on_layoutreturn(inode, task);
3015}
3016
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017struct nfs4_closedata {
3018 struct inode *inode;
3019 struct nfs4_state *state;
3020 struct nfs_closeargs arg;
3021 struct nfs_closeres res;
Trond Myklebustcf805162016-11-15 14:56:07 -05003022 struct {
3023 struct nfs4_layoutreturn_args arg;
3024 struct nfs4_layoutreturn_res res;
Trond Myklebust4d796d72016-09-23 11:38:08 -04003025 struct nfs4_xdr_opaque_data ld_private;
Trond Myklebustcf805162016-11-15 14:56:07 -05003026 u32 roc_barrier;
3027 bool roc;
3028 } lr;
Trond Myklebust516a6af2005-10-27 22:12:41 -04003029 struct nfs_fattr fattr;
Trond Myklebust26e976a2006-01-03 09:55:21 +01003030 unsigned long timestamp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031};
3032
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003033static void nfs4_free_closedata(void *data)
Trond Myklebust95121352005-10-18 14:20:12 -07003034{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003035 struct nfs4_closedata *calldata = data;
3036 struct nfs4_state_owner *sp = calldata->state->owner;
Al Viro643168c2011-06-22 18:20:23 -04003037 struct super_block *sb = calldata->state->inode->i_sb;
Trond Myklebust95121352005-10-18 14:20:12 -07003038
Trond Myklebustcf805162016-11-15 14:56:07 -05003039 if (calldata->lr.roc)
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05003040 pnfs_roc_release(&calldata->lr.arg, &calldata->lr.res,
3041 calldata->res.lr_ret);
Trond Myklebust95121352005-10-18 14:20:12 -07003042 nfs4_put_open_state(calldata->state);
3043 nfs_free_seqid(calldata->arg.seqid);
Trond Myklebust95121352005-10-18 14:20:12 -07003044 nfs4_put_state_owner(sp);
Trond Myklebust322b2b92013-01-11 16:39:51 -05003045 nfs_sb_deactive(sb);
Trond Myklebust95121352005-10-18 14:20:12 -07003046 kfree(calldata);
3047}
3048
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003049static void nfs4_close_done(struct rpc_task *task, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003051 struct nfs4_closedata *calldata = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003052 struct nfs4_state *state = calldata->state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 struct nfs_server *server = NFS_SERVER(calldata->inode);
Trond Myklebust412f6c42014-08-25 22:09:08 -04003054 nfs4_stateid *res_stateid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003055
Chuck Levera3ca5652012-03-01 17:00:40 -05003056 dprintk("%s: begin!\n", __func__);
Trond Myklebust14516c32010-07-31 14:29:06 -04003057 if (!nfs4_sequence_done(task, &calldata->res.seq_res))
3058 return;
Trond Myklebust42113a72013-08-12 16:19:27 -04003059 trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status);
Trond Myklebustcf805162016-11-15 14:56:07 -05003060
3061 /* Handle Layoutreturn errors */
3062 if (calldata->arg.lr_args && task->tk_status != 0) {
3063 switch (calldata->res.lr_ret) {
3064 default:
3065 calldata->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT;
3066 break;
3067 case 0:
3068 calldata->arg.lr_args = NULL;
3069 calldata->res.lr_res = NULL;
3070 break;
3071 case -NFS4ERR_ADMIN_REVOKED:
3072 case -NFS4ERR_DELEG_REVOKED:
3073 case -NFS4ERR_EXPIRED:
3074 case -NFS4ERR_BAD_STATEID:
3075 case -NFS4ERR_OLD_STATEID:
3076 case -NFS4ERR_UNKNOWN_LAYOUTTYPE:
3077 case -NFS4ERR_WRONG_CRED:
3078 calldata->arg.lr_args = NULL;
3079 calldata->res.lr_res = NULL;
3080 calldata->res.lr_ret = 0;
3081 rpc_restart_call_prepare(task);
3082 return;
3083 }
3084 }
3085
Anna Schumakerd9b67e12017-01-11 15:04:25 -05003086 /* hmm. we are done with the inode, and in the process of freeing
Linus Torvalds1da177e2005-04-16 15:20:36 -07003087 * the state_owner. we keep this around to process errors
3088 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003089 switch (task->tk_status) {
3090 case 0:
Trond Myklebust412f6c42014-08-25 22:09:08 -04003091 res_stateid = &calldata->res.stateid;
Trond Myklebust26e976a2006-01-03 09:55:21 +01003092 renew_lease(server, calldata->timestamp);
Trond Myklebust412f6c42014-08-25 22:09:08 -04003093 break;
Trond Myklebustf07d4a32016-12-19 10:34:14 -05003094 case -NFS4ERR_ACCESS:
3095 if (calldata->arg.bitmask != NULL) {
3096 calldata->arg.bitmask = NULL;
3097 calldata->res.fattr = NULL;
3098 task->tk_status = 0;
3099 rpc_restart_call_prepare(task);
3100 goto out_release;
3101
3102 }
3103 break;
Trond Myklebust69794ad2013-11-20 12:57:19 -05003104 case -NFS4ERR_ADMIN_REVOKED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 case -NFS4ERR_STALE_STATEID:
Trond Myklebust26d36302016-09-22 13:39:05 -04003106 case -NFS4ERR_EXPIRED:
3107 nfs4_free_revoked_stateid(server,
3108 &calldata->arg.stateid,
3109 task->tk_msg.rpc_cred);
Trond Myklebust9e33bed2008-12-23 15:21:46 -05003110 case -NFS4ERR_OLD_STATEID:
3111 case -NFS4ERR_BAD_STATEID:
Trond Myklebust566fcec2015-01-23 15:32:46 -05003112 if (!nfs4_stateid_match(&calldata->arg.stateid,
Anna Schumaker369d6b72015-03-02 16:46:09 -05003113 &state->open_stateid)) {
Trond Myklebust566fcec2015-01-23 15:32:46 -05003114 rpc_restart_call_prepare(task);
3115 goto out_release;
3116 }
Trond Myklebustdc0b0272008-12-23 15:21:56 -05003117 if (calldata->arg.fmode == 0)
Trond Myklebust9e33bed2008-12-23 15:21:46 -05003118 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119 default:
NeilBrown8478eaa2014-09-18 16:09:27 +10003120 if (nfs4_async_handle_error(task, server, state, NULL) == -EAGAIN) {
Trond Myklebust72211db2009-12-15 14:47:36 -05003121 rpc_restart_call_prepare(task);
Trond Myklebust69794ad2013-11-20 12:57:19 -05003122 goto out_release;
3123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003124 }
Trond Myklebust4a1e2fe2015-08-30 18:37:59 -07003125 nfs_clear_open_stateid(state, &calldata->arg.stateid,
3126 res_stateid, calldata->arg.fmode);
Trond Myklebust69794ad2013-11-20 12:57:19 -05003127out_release:
Trond Myklebust72211db2009-12-15 14:47:36 -05003128 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebustd8d84982016-12-19 12:14:44 -05003129 nfs_refresh_inode(calldata->inode, &calldata->fattr);
Chuck Levera3ca5652012-03-01 17:00:40 -05003130 dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131}
3132
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01003133static void nfs4_close_prepare(struct rpc_task *task, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134{
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01003135 struct nfs4_closedata *calldata = data;
Trond Myklebust95121352005-10-18 14:20:12 -07003136 struct nfs4_state *state = calldata->state;
Trond Myklebust7fdab062012-09-20 20:15:57 -04003137 struct inode *inode = calldata->inode;
Trond Myklebustaee7af32014-08-25 22:33:12 -04003138 bool is_rdonly, is_wronly, is_rdwr;
Trond Myklebust88069f72009-12-08 08:33:16 -05003139 int call_close = 0;
Trond Myklebust95121352005-10-18 14:20:12 -07003140
Chuck Levera3ca5652012-03-01 17:00:40 -05003141 dprintk("%s: begin!\n", __func__);
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003142 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05003143 goto out_wait;
Trond Myklebust003707c2007-07-05 18:07:55 -04003144
Trond Myklebust88069f72009-12-08 08:33:16 -05003145 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
Trond Myklebust4cecb762005-11-04 15:32:58 -05003146 spin_lock(&state->owner->so_lock);
Trond Myklebustaee7af32014-08-25 22:33:12 -04003147 is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
3148 is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
3149 is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
Anna Schumaker369d6b72015-03-02 16:46:09 -05003150 nfs4_stateid_copy(&calldata->arg.stateid, &state->open_stateid);
Trond Myklebust003707c2007-07-05 18:07:55 -04003151 /* Calculate the change in open mode */
Trond Myklebustcd9288f2014-09-18 11:51:32 -04003152 calldata->arg.fmode = 0;
Trond Myklebuste7616922006-01-03 09:55:13 +01003153 if (state->n_rdwr == 0) {
Trond Myklebustcd9288f2014-09-18 11:51:32 -04003154 if (state->n_rdonly == 0)
3155 call_close |= is_rdonly;
3156 else if (is_rdonly)
3157 calldata->arg.fmode |= FMODE_READ;
3158 if (state->n_wronly == 0)
3159 call_close |= is_wronly;
3160 else if (is_wronly)
3161 calldata->arg.fmode |= FMODE_WRITE;
Trond Myklebuste547f262016-06-25 19:19:28 -04003162 if (calldata->arg.fmode != (FMODE_READ|FMODE_WRITE))
3163 call_close |= is_rdwr;
Trond Myklebustcd9288f2014-09-18 11:51:32 -04003164 } else if (is_rdwr)
3165 calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
3166
Trond Myklebust5cc78612016-11-14 11:19:56 -05003167 if (!nfs4_valid_open_stateid(state) ||
3168 test_bit(NFS_OPEN_STATE, &state->flags) == 0)
Trond Myklebust5d422302013-03-14 16:57:48 -04003169 call_close = 0;
Trond Myklebust4cecb762005-11-04 15:32:58 -05003170 spin_unlock(&state->owner->so_lock);
Trond Myklebust88069f72009-12-08 08:33:16 -05003171
3172 if (!call_close) {
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003173 /* Note: exit _without_ calling nfs4_close_done */
Trond Myklebustc8da19b2013-02-11 19:01:21 -05003174 goto out_no_action;
Trond Myklebust95121352005-10-18 14:20:12 -07003175 }
Trond Myklebust88069f72009-12-08 08:33:16 -05003176
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05003177 if (!calldata->lr.roc && nfs4_wait_on_layoutreturn(inode, task)) {
Peng Tao500d7012015-09-22 11:35:22 +08003178 nfs_release_seqid(calldata->arg.seqid);
3179 goto out_wait;
3180 }
3181
Trond Myklebust9413a1a2016-12-19 11:36:41 -05003182 if (calldata->arg.fmode == 0)
Trond Myklebust88069f72009-12-08 08:33:16 -05003183 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
Trond Myklebust3ecefc92016-10-27 18:25:04 -04003184
Trond Myklebust9413a1a2016-12-19 11:36:41 -05003185 if (calldata->arg.fmode == 0 || calldata->arg.fmode == FMODE_READ) {
Trond Myklebust3ecefc92016-10-27 18:25:04 -04003186 /* Close-to-open cache consistency revalidation */
3187 if (!nfs4_have_delegation(inode, FMODE_READ))
3188 calldata->arg.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
3189 else
3190 calldata->arg.bitmask = NULL;
3191 }
Trond Myklebust3c13cb52015-08-18 23:45:13 -05003192
Trond Myklebust6ae37332015-01-30 14:21:14 -05003193 calldata->arg.share_access =
3194 nfs4_map_atomic_open_share(NFS_SERVER(inode),
3195 calldata->arg.fmode, 0);
Trond Myklebust88069f72009-12-08 08:33:16 -05003196
Trond Myklebustd8d84982016-12-19 12:14:44 -05003197 if (calldata->res.fattr == NULL)
3198 calldata->arg.bitmask = NULL;
3199 else if (calldata->arg.bitmask == NULL)
3200 calldata->res.fattr = NULL;
Trond Myklebust26e976a2006-01-03 09:55:21 +01003201 calldata->timestamp = jiffies;
Anna Schumaker42e1cca2017-01-09 15:48:22 -05003202 if (nfs4_setup_sequence(NFS_SERVER(inode)->nfs_client,
Trond Myklebust9d12b212012-01-17 22:04:25 -05003203 &calldata->arg.seq_args,
3204 &calldata->res.seq_res,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04003205 task) != 0)
3206 nfs_release_seqid(calldata->arg.seqid);
Chuck Levera3ca5652012-03-01 17:00:40 -05003207 dprintk("%s: done!\n", __func__);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05003208 return;
3209out_no_action:
3210 task->tk_action = NULL;
3211out_wait:
3212 nfs4_sequence_done(task, &calldata->res.seq_res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003213}
3214
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003215static const struct rpc_call_ops nfs4_close_ops = {
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01003216 .rpc_call_prepare = nfs4_close_prepare,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003217 .rpc_call_done = nfs4_close_done,
3218 .rpc_release = nfs4_free_closedata,
3219};
3220
Linus Torvalds1da177e2005-04-16 15:20:36 -07003221/*
3222 * It is possible for data to be read/written from a mem-mapped file
3223 * after the sys_close call (which hits the vfs layer as a flush).
3224 * This means that we can't safely call nfsv4 close on a file until
3225 * the inode is cleared. This in turn means that we are not good
3226 * NFSv4 citizens - we do not indicate to the server to update the file's
3227 * share state even when we are done with one of the three share
3228 * stateid's in the inode.
3229 *
3230 * NOTE: Caller must be holding the sp->so_owner semaphore!
3231 */
Trond Myklebust1f7977c2012-09-20 20:31:51 -04003232int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003233{
Trond Myklebust4a35bd42007-06-05 10:31:33 -04003234 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust63f5f792015-01-23 19:19:25 -05003235 struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003236 struct nfs4_closedata *calldata;
Trond Myklebustb39e6252007-06-11 23:05:07 -04003237 struct nfs4_state_owner *sp = state->owner;
3238 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04003239 struct rpc_message msg = {
3240 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE],
3241 .rpc_cred = state->owner->so_cred,
3242 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04003243 struct rpc_task_setup task_setup_data = {
3244 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04003245 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04003246 .callback_ops = &nfs4_close_ops,
Trond Myklebust101070c2008-02-19 20:04:23 -05003247 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04003248 .flags = RPC_TASK_ASYNC,
3249 };
Trond Myklebust95121352005-10-18 14:20:12 -07003250 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04003252 nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_CLEANUP,
3253 &task_setup_data.rpc_client, &msg);
3254
Trond Myklebust8535b2b2010-05-13 12:51:01 -04003255 calldata = kzalloc(sizeof(*calldata), gfp_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003256 if (calldata == NULL)
Trond Myklebust95121352005-10-18 14:20:12 -07003257 goto out;
Chuck Levera9c92d62013-08-09 12:48:18 -04003258 nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
Trond Myklebust4a35bd42007-06-05 10:31:33 -04003259 calldata->inode = state->inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003260 calldata->state = state;
Trond Myklebust4a35bd42007-06-05 10:31:33 -04003261 calldata->arg.fh = NFS_FH(state->inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003262 /* Serialization for the sequence id */
Trond Myklebust63f5f792015-01-23 19:19:25 -05003263 alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
3264 calldata->arg.seqid = alloc_seqid(&state->owner->so_seqid, gfp_mask);
Trond Myklebustbadc76d2015-01-23 18:48:00 -05003265 if (IS_ERR(calldata->arg.seqid))
Trond Myklebust95121352005-10-18 14:20:12 -07003266 goto out_free_calldata;
Trond Myklebustd8d84982016-12-19 12:14:44 -05003267 nfs_fattr_init(&calldata->fattr);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05003268 calldata->arg.fmode = 0;
Trond Myklebust4d796d72016-09-23 11:38:08 -04003269 calldata->lr.arg.ld_private = &calldata->lr.ld_private;
Trond Myklebust516a6af2005-10-27 22:12:41 -04003270 calldata->res.fattr = &calldata->fattr;
Trond Myklebustc1d51932008-04-07 13:20:54 -04003271 calldata->res.seqid = calldata->arg.seqid;
Trond Myklebust516a6af2005-10-27 22:12:41 -04003272 calldata->res.server = server;
Trond Myklebustcf805162016-11-15 14:56:07 -05003273 calldata->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT;
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05003274 calldata->lr.roc = pnfs_roc(state->inode,
3275 &calldata->lr.arg, &calldata->lr.res, msg.rpc_cred);
3276 if (calldata->lr.roc) {
3277 calldata->arg.lr_args = &calldata->lr.arg;
3278 calldata->res.lr_res = &calldata->lr.res;
3279 }
Al Viro643168c2011-06-22 18:20:23 -04003280 nfs_sb_active(calldata->inode->i_sb);
Trond Myklebust95121352005-10-18 14:20:12 -07003281
Trond Myklebust1174dd12010-12-21 10:52:24 -05003282 msg.rpc_argp = &calldata->arg;
3283 msg.rpc_resp = &calldata->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04003284 task_setup_data.callback_data = calldata;
3285 task = rpc_run_task(&task_setup_data);
Trond Myklebustb39e6252007-06-11 23:05:07 -04003286 if (IS_ERR(task))
3287 return PTR_ERR(task);
Trond Myklebusta49c3c72007-10-18 18:03:27 -04003288 status = 0;
3289 if (wait)
3290 status = rpc_wait_for_completion_task(task);
Trond Myklebustb39e6252007-06-11 23:05:07 -04003291 rpc_put_task(task);
Trond Myklebusta49c3c72007-10-18 18:03:27 -04003292 return status;
Trond Myklebust95121352005-10-18 14:20:12 -07003293out_free_calldata:
3294 kfree(calldata);
3295out:
Trond Myklebustb39e6252007-06-11 23:05:07 -04003296 nfs4_put_open_state(state);
3297 nfs4_put_state_owner(sp);
Trond Myklebust95121352005-10-18 14:20:12 -07003298 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003299}
3300
Trond Myklebust2b484292010-09-17 10:56:51 -04003301static struct inode *
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04003302nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
3303 int open_flags, struct iattr *attr, int *opened)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003304{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003305 struct nfs4_state *state;
David Quigleyaa9c2662013-05-22 12:50:44 -04003306 struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
3307
3308 label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309
Trond Myklebust565277f2007-10-15 18:17:53 -04003310 /* Protect against concurrent sillydeletes */
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04003311 state = nfs4_do_open(dir, ctx, open_flags, attr, label, opened);
David Quigleyaa9c2662013-05-22 12:50:44 -04003312
3313 nfs4_label_release_security(label);
3314
Trond Myklebustf46e0bd2010-09-17 10:56:50 -04003315 if (IS_ERR(state))
3316 return ERR_CAST(state);
Trond Myklebust275bb302013-05-29 13:11:28 -04003317 return state->inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003318}
3319
Trond Myklebust1185a552009-12-03 15:54:02 -05003320static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
Trond Myklebust7fe5c392009-03-19 15:35:50 -04003321{
3322 if (ctx->state == NULL)
3323 return;
3324 if (is_sync)
Al Viro643168c2011-06-22 18:20:23 -04003325 nfs4_close_sync(ctx->state, ctx->mode);
Trond Myklebust7fe5c392009-03-19 15:35:50 -04003326 else
Al Viro643168c2011-06-22 18:20:23 -04003327 nfs4_close_state(ctx->state, ctx->mode);
Trond Myklebust7fe5c392009-03-19 15:35:50 -04003328}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003329
Trond Myklebustb944dba2013-11-04 15:20:20 -05003330#define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
3331#define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL)
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05003332#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_MODE_UMASK - 1UL)
Trond Myklebustb944dba2013-11-04 15:20:20 -05003333
Linus Torvalds1da177e2005-04-16 15:20:36 -07003334static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
3335{
Kinglong Mee8c612822015-08-26 21:12:58 +08003336 u32 bitmask[3] = {}, minorversion = server->nfs_client->cl_minorversion;
Benny Halevy43652ad2009-04-01 09:21:54 -04003337 struct nfs4_server_caps_arg args = {
3338 .fhandle = fhandle,
Kinglong Mee8c612822015-08-26 21:12:58 +08003339 .bitmask = bitmask,
Benny Halevy43652ad2009-04-01 09:21:54 -04003340 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341 struct nfs4_server_caps_res res = {};
3342 struct rpc_message msg = {
3343 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS],
Benny Halevy43652ad2009-04-01 09:21:54 -04003344 .rpc_argp = &args,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003345 .rpc_resp = &res,
3346 };
3347 int status;
Trond Myklebustf4b23de2017-05-09 15:47:15 -04003348 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003349
Kinglong Mee8c612822015-08-26 21:12:58 +08003350 bitmask[0] = FATTR4_WORD0_SUPPORTED_ATTRS |
3351 FATTR4_WORD0_FH_EXPIRE_TYPE |
3352 FATTR4_WORD0_LINK_SUPPORT |
3353 FATTR4_WORD0_SYMLINK_SUPPORT |
3354 FATTR4_WORD0_ACLSUPPORT;
3355 if (minorversion)
3356 bitmask[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT;
3357
Bryan Schumaker7c513052011-03-24 17:12:24 +00003358 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003359 if (status == 0) {
Trond Myklebustb944dba2013-11-04 15:20:20 -05003360 /* Sanity check the server answers */
Kinglong Mee8c612822015-08-26 21:12:58 +08003361 switch (minorversion) {
Trond Myklebustb944dba2013-11-04 15:20:20 -05003362 case 0:
3363 res.attr_bitmask[1] &= FATTR4_WORD1_NFS40_MASK;
3364 res.attr_bitmask[2] = 0;
3365 break;
3366 case 1:
3367 res.attr_bitmask[2] &= FATTR4_WORD2_NFS41_MASK;
3368 break;
3369 case 2:
3370 res.attr_bitmask[2] &= FATTR4_WORD2_NFS42_MASK;
3371 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003372 memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
Trond Myklebust62ab4602009-08-09 15:06:19 -04003373 server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS|
3374 NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
3375 NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|
3376 NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME|
Trond Myklebustb944dba2013-11-04 15:20:20 -05003377 NFS_CAP_CTIME|NFS_CAP_MTIME|
3378 NFS_CAP_SECURITY_LABEL);
Malahal Naineni7dd7d952014-01-23 08:54:55 -06003379 if (res.attr_bitmask[0] & FATTR4_WORD0_ACL &&
3380 res.acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003381 server->caps |= NFS_CAP_ACLS;
3382 if (res.has_links != 0)
3383 server->caps |= NFS_CAP_HARDLINKS;
3384 if (res.has_symlinks != 0)
3385 server->caps |= NFS_CAP_SYMLINKS;
Trond Myklebust62ab4602009-08-09 15:06:19 -04003386 if (res.attr_bitmask[0] & FATTR4_WORD0_FILEID)
3387 server->caps |= NFS_CAP_FILEID;
3388 if (res.attr_bitmask[1] & FATTR4_WORD1_MODE)
3389 server->caps |= NFS_CAP_MODE;
3390 if (res.attr_bitmask[1] & FATTR4_WORD1_NUMLINKS)
3391 server->caps |= NFS_CAP_NLINK;
3392 if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER)
3393 server->caps |= NFS_CAP_OWNER;
3394 if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER_GROUP)
3395 server->caps |= NFS_CAP_OWNER_GROUP;
3396 if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_ACCESS)
3397 server->caps |= NFS_CAP_ATIME;
3398 if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_METADATA)
3399 server->caps |= NFS_CAP_CTIME;
3400 if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY)
3401 server->caps |= NFS_CAP_MTIME;
David Quigleyaa9c2662013-05-22 12:50:44 -04003402#ifdef CONFIG_NFS_V4_SECURITY_LABEL
3403 if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
3404 server->caps |= NFS_CAP_SECURITY_LABEL;
3405#endif
3406 memcpy(server->attr_bitmask_nl, res.attr_bitmask,
3407 sizeof(server->attr_bitmask));
Trond Myklebustb944dba2013-11-04 15:20:20 -05003408 server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
Trond Myklebust62ab4602009-08-09 15:06:19 -04003409
Trond Myklebusta65318b2009-03-11 14:10:28 -04003410 memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
3411 server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
3412 server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
Trond Myklebustb944dba2013-11-04 15:20:20 -05003413 server->cache_consistency_bitmask[2] = 0;
Trond Myklebustf4b23de2017-05-09 15:47:15 -04003414
3415 /* Avoid a regression due to buggy server */
3416 for (i = 0; i < ARRAY_SIZE(res.exclcreat_bitmask); i++)
3417 res.exclcreat_bitmask[i] &= res.attr_bitmask[i];
Kinglong Mee8c612822015-08-26 21:12:58 +08003418 memcpy(server->exclcreat_bitmask, res.exclcreat_bitmask,
3419 sizeof(server->exclcreat_bitmask));
Trond Myklebustf4b23de2017-05-09 15:47:15 -04003420
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 server->acl_bitmask = res.acl_bitmask;
Chuck Lever264e6352012-03-01 17:02:05 -05003422 server->fh_expire_type = res.fh_expire_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003423 }
Andy Adamsoncccef3b2009-04-01 09:22:03 -04003424
Linus Torvalds1da177e2005-04-16 15:20:36 -07003425 return status;
3426}
3427
Trond Myklebust55a97592006-06-09 09:34:19 -04003428int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429{
3430 struct nfs4_exception exception = { };
3431 int err;
3432 do {
3433 err = nfs4_handle_exception(server,
3434 _nfs4_server_capabilities(server, fhandle),
3435 &exception);
3436 } while (exception.retry);
3437 return err;
3438}
3439
3440static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
3441 struct nfs_fsinfo *info)
3442{
David Quigleyaa9c2662013-05-22 12:50:44 -04003443 u32 bitmask[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003444 struct nfs4_lookup_root_arg args = {
David Quigleyaa9c2662013-05-22 12:50:44 -04003445 .bitmask = bitmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003446 };
3447 struct nfs4_lookup_res res = {
3448 .server = server,
Trond Myklebust0e574af2005-10-27 22:12:38 -04003449 .fattr = info->fattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003450 .fh = fhandle,
3451 };
3452 struct rpc_message msg = {
3453 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT],
3454 .rpc_argp = &args,
3455 .rpc_resp = &res,
3456 };
Benny Halevy008f55d2009-04-01 09:22:50 -04003457
David Quigleyaa9c2662013-05-22 12:50:44 -04003458 bitmask[0] = nfs4_fattr_bitmap[0];
3459 bitmask[1] = nfs4_fattr_bitmap[1];
3460 /*
3461 * Process the label in the upcoming getfattr
3462 */
3463 bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
3464
Trond Myklebust0e574af2005-10-27 22:12:38 -04003465 nfs_fattr_init(info->fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00003466 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467}
3468
3469static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
3470 struct nfs_fsinfo *info)
3471{
3472 struct nfs4_exception exception = { };
3473 int err;
3474 do {
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04003475 err = _nfs4_lookup_root(server, fhandle, info);
Trond Myklebustb5f875a2013-08-13 13:01:39 -04003476 trace_nfs4_lookup_root(server, fhandle, info->fattr, err);
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04003477 switch (err) {
3478 case 0:
3479 case -NFS4ERR_WRONGSEC:
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04003480 goto out;
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04003481 default:
3482 err = nfs4_handle_exception(server, err, &exception);
3483 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 } while (exception.retry);
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04003485out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486 return err;
3487}
3488
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003489static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
3490 struct nfs_fsinfo *info, rpc_authflavor_t flavor)
3491{
Trond Myklebustc2190662013-08-26 19:23:04 -04003492 struct rpc_auth_create_args auth_args = {
3493 .pseudoflavor = flavor,
3494 };
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003495 struct rpc_auth *auth;
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003496
Trond Myklebustc2190662013-08-26 19:23:04 -04003497 auth = rpcauth_create(&auth_args, server->client);
Anna Schumaker9df13362017-01-11 16:30:08 -05003498 if (IS_ERR(auth))
3499 return -EACCES;
3500 return nfs4_lookup_root(server, fhandle, info);
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003501}
3502
Chuck Lever9a744ba2013-03-16 15:56:02 -04003503/*
3504 * Retry pseudoroot lookup with various security flavors. We do this when:
3505 *
3506 * NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
3507 * NFSv4.1: the server does not support the SECINFO_NO_NAME operation
3508 *
3509 * Returns zero on success, or a negative NFS4ERR value, or a
3510 * negative errno value.
3511 */
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04003512static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
David Howells54ceac42006-08-22 20:06:13 -04003513 struct nfs_fsinfo *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514{
Chuck Lever9a744ba2013-03-16 15:56:02 -04003515 /* Per 3530bis 15.33.5 */
3516 static const rpc_authflavor_t flav_array[] = {
3517 RPC_AUTH_GSS_KRB5P,
3518 RPC_AUTH_GSS_KRB5I,
3519 RPC_AUTH_GSS_KRB5,
Chuck Leverc4eafe12013-03-16 15:56:11 -04003520 RPC_AUTH_UNIX, /* courtesy */
Chuck Lever9a744ba2013-03-16 15:56:02 -04003521 RPC_AUTH_NULL,
3522 };
3523 int status = -EPERM;
3524 size_t i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003525
Weston Andros Adamson4d4b69d2013-10-18 15:15:19 -04003526 if (server->auth_info.flavor_len > 0) {
3527 /* try each flavor specified by user */
3528 for (i = 0; i < server->auth_info.flavor_len; i++) {
3529 status = nfs4_lookup_root_sec(server, fhandle, info,
3530 server->auth_info.flavors[i]);
3531 if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
3532 continue;
3533 break;
3534 }
3535 } else {
3536 /* no flavors specified by user, try default list */
3537 for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
3538 status = nfs4_lookup_root_sec(server, fhandle, info,
3539 flav_array[i]);
3540 if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
3541 continue;
3542 break;
3543 }
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003544 }
Chuck Lever9a744ba2013-03-16 15:56:02 -04003545
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04003546 /*
3547 * -EACCESS could mean that the user doesn't have correct permissions
3548 * to access the mount. It could also mean that we tried to mount
3549 * with a gss auth flavor, but rpc.gssd isn't running. Either way,
3550 * existing mount programs don't handle -EACCES very well so it should
3551 * be mapped to -EPERM instead.
3552 */
3553 if (status == -EACCES)
3554 status = -EPERM;
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04003555 return status;
3556}
3557
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04003558/**
3559 * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
3560 * @server: initialized nfs_server handle
3561 * @fhandle: we fill in the pseudo-fs root file handle
3562 * @info: we fill in an FSINFO struct
Trond Myklebust5e6b1992013-09-07 12:58:57 -04003563 * @auth_probe: probe the auth flavours
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04003564 *
3565 * Returns zero on success, or a negative errno.
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04003566 */
Bryan Schumaker3028eb22012-05-10 15:07:30 -04003567int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
Trond Myklebust5e6b1992013-09-07 12:58:57 -04003568 struct nfs_fsinfo *info,
3569 bool auth_probe)
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04003570{
Andre Przywarac7757072015-04-23 17:17:40 +01003571 int status = 0;
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04003572
Andre Przywarac7757072015-04-23 17:17:40 +01003573 if (!auth_probe)
Trond Myklebust5e6b1992013-09-07 12:58:57 -04003574 status = nfs4_lookup_root(server, fhandle, info);
Andre Przywarac7757072015-04-23 17:17:40 +01003575
3576 if (auth_probe || status == NFS4ERR_WRONGSEC)
Trond Myklebust698c9372016-07-25 13:31:14 -04003577 status = server->nfs_client->cl_mvops->find_root_sec(server,
3578 fhandle, info);
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04003579
Linus Torvalds1da177e2005-04-16 15:20:36 -07003580 if (status == 0)
3581 status = nfs4_server_capabilities(server, fhandle);
3582 if (status == 0)
3583 status = nfs4_do_fsinfo(server, fhandle, info);
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04003584
Trond Myklebustc12e87f2006-03-13 21:20:47 -08003585 return nfs4_map_errors(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003586}
3587
Bryan Schumakerbae36242012-05-10 15:07:31 -04003588static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
3589 struct nfs_fsinfo *info)
3590{
3591 int error;
3592 struct nfs_fattr *fattr = info->fattr;
David Quigley1775fd32013-05-22 12:50:42 -04003593 struct nfs4_label *label = NULL;
Bryan Schumakerbae36242012-05-10 15:07:31 -04003594
3595 error = nfs4_server_capabilities(server, mntfh);
3596 if (error < 0) {
3597 dprintk("nfs4_get_root: getcaps error = %d\n", -error);
3598 return error;
3599 }
3600
David Quigley14c43f72013-05-22 12:50:43 -04003601 label = nfs4_label_alloc(server, GFP_KERNEL);
3602 if (IS_ERR(label))
3603 return PTR_ERR(label);
3604
David Quigley1775fd32013-05-22 12:50:42 -04003605 error = nfs4_proc_getattr(server, mntfh, fattr, label);
Bryan Schumakerbae36242012-05-10 15:07:31 -04003606 if (error < 0) {
3607 dprintk("nfs4_get_root: getattr error = %d\n", -error);
David Quigley14c43f72013-05-22 12:50:43 -04003608 goto err_free_label;
Bryan Schumakerbae36242012-05-10 15:07:31 -04003609 }
3610
3611 if (fattr->valid & NFS_ATTR_FATTR_FSID &&
3612 !nfs_fsid_equal(&server->fsid, &fattr->fsid))
3613 memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
3614
David Quigley14c43f72013-05-22 12:50:43 -04003615err_free_label:
3616 nfs4_label_free(label);
3617
Bryan Schumakerbae36242012-05-10 15:07:31 -04003618 return error;
3619}
3620
Manoj Naik6b97fd32006-06-09 09:34:29 -04003621/*
3622 * Get locations and (maybe) other attributes of a referral.
3623 * Note that we'll actually follow the referral later when
3624 * we detect fsid mismatch in inode revalidation
3625 */
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003626static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
3627 const struct qstr *name, struct nfs_fattr *fattr,
3628 struct nfs_fh *fhandle)
Manoj Naik6b97fd32006-06-09 09:34:29 -04003629{
3630 int status = -ENOMEM;
3631 struct page *page = NULL;
3632 struct nfs4_fs_locations *locations = NULL;
Manoj Naik6b97fd32006-06-09 09:34:29 -04003633
3634 page = alloc_page(GFP_KERNEL);
3635 if (page == NULL)
3636 goto out;
3637 locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
3638 if (locations == NULL)
3639 goto out;
3640
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003641 status = nfs4_proc_fs_locations(client, dir, name, locations, page);
Manoj Naik6b97fd32006-06-09 09:34:29 -04003642 if (status != 0)
3643 goto out;
Chuck Lever519ae252013-10-17 14:13:19 -04003644
3645 /*
3646 * If the fsid didn't change, this is a migration event, not a
3647 * referral. Cause us to drop into the exception handler, which
3648 * will kick off migration recovery.
3649 */
Manoj Naik6b97fd32006-06-09 09:34:29 -04003650 if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
Andy Adamson533eb462011-06-13 18:25:56 -04003651 dprintk("%s: server did not return a different fsid for"
3652 " a referral at %s\n", __func__, name->name);
Chuck Lever519ae252013-10-17 14:13:19 -04003653 status = -NFS4ERR_MOVED;
Manoj Naik6b97fd32006-06-09 09:34:29 -04003654 goto out;
3655 }
Andy Adamson533eb462011-06-13 18:25:56 -04003656 /* Fixup attributes for the nfs_lookup() call to nfs_fhget() */
3657 nfs_fixup_referral_attributes(&locations->fattr);
Manoj Naik6b97fd32006-06-09 09:34:29 -04003658
Andy Adamson533eb462011-06-13 18:25:56 -04003659 /* replace the lookup nfs_fattr with the locations nfs_fattr */
Manoj Naik6b97fd32006-06-09 09:34:29 -04003660 memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
Manoj Naik6b97fd32006-06-09 09:34:29 -04003661 memset(fhandle, 0, sizeof(struct nfs_fh));
3662out:
3663 if (page)
3664 __free_page(page);
Davidlohr Bueso5d7ca352010-08-11 12:42:15 -04003665 kfree(locations);
Manoj Naik6b97fd32006-06-09 09:34:29 -04003666 return status;
3667}
3668
David Quigley1775fd32013-05-22 12:50:42 -04003669static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
3670 struct nfs_fattr *fattr, struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003671{
3672 struct nfs4_getattr_arg args = {
3673 .fh = fhandle,
3674 .bitmask = server->attr_bitmask,
3675 };
3676 struct nfs4_getattr_res res = {
3677 .fattr = fattr,
David Quigley1775fd32013-05-22 12:50:42 -04003678 .label = label,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003679 .server = server,
3680 };
3681 struct rpc_message msg = {
3682 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
3683 .rpc_argp = &args,
3684 .rpc_resp = &res,
3685 };
David Quigleyaa9c2662013-05-22 12:50:44 -04003686
3687 args.bitmask = nfs4_bitmask(server, label);
3688
Trond Myklebust0e574af2005-10-27 22:12:38 -04003689 nfs_fattr_init(fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00003690 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691}
3692
David Quigley1775fd32013-05-22 12:50:42 -04003693static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
3694 struct nfs_fattr *fattr, struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003695{
3696 struct nfs4_exception exception = { };
3697 int err;
3698 do {
Trond Myklebustb5f875a2013-08-13 13:01:39 -04003699 err = _nfs4_proc_getattr(server, fhandle, fattr, label);
3700 trace_nfs4_getattr(server, fhandle, fattr, err);
3701 err = nfs4_handle_exception(server, err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 &exception);
3703 } while (exception.retry);
3704 return err;
3705}
3706
3707/*
3708 * The file is not closed if it is opened due to the a request to change
3709 * the size of the file. The open call will not be needed once the
3710 * VFS layer lookup-intents are implemented.
3711 *
3712 * Close is called when the inode is destroyed.
3713 * If we haven't opened the file for O_WRONLY, we
3714 * need to in the size_change case to obtain a stateid.
3715 *
3716 * Got race?
3717 * Because OPEN is always done by name in nfsv4, it is
3718 * possible that we opened a different file by the same
3719 * name. We can recognize this race condition, but we
3720 * can't do anything about it besides returning an error.
3721 *
3722 * This will be fixed with VFS changes (lookup-intent).
3723 */
3724static int
3725nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
3726 struct iattr *sattr)
3727{
David Howells2b0143b2015-03-17 22:25:59 +00003728 struct inode *inode = d_inode(dentry);
Trond Myklebust659bfcd2008-06-10 19:39:41 -04003729 struct rpc_cred *cred = NULL;
NeilBrown29b59f92016-10-13 15:26:47 +11003730 struct nfs_open_context *ctx = NULL;
David Quigley14c43f72013-05-22 12:50:43 -04003731 struct nfs4_label *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003732 int status;
3733
Peng Tao88ac8152014-09-12 11:04:10 +08003734 if (pnfs_ld_layoutret_on_setattr(inode) &&
3735 sattr->ia_valid & ATTR_SIZE &&
3736 sattr->ia_size < i_size_read(inode))
Trond Myklebust24028672013-03-20 13:23:33 -04003737 pnfs_commit_and_return_layout(inode);
Benny Halevy8a1636c2010-07-14 15:43:57 -04003738
Trond Myklebust0e574af2005-10-27 22:12:38 -04003739 nfs_fattr_init(fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740
Andy Adamson26699402012-05-30 16:12:24 -04003741 /* Deal with open(O_TRUNC) */
3742 if (sattr->ia_valid & ATTR_OPEN)
Nadav Shemercc7936f2013-07-21 17:21:43 +03003743 sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME);
Andy Adamson26699402012-05-30 16:12:24 -04003744
3745 /* Optimization: if the end result is no change, don't RPC */
Nadav Shemercc7936f2013-07-21 17:21:43 +03003746 if ((sattr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
Andy Adamson26699402012-05-30 16:12:24 -04003747 return 0;
3748
Trond Myklebustd5308382005-11-04 15:33:38 -05003749 /* Search for an existing open(O_WRITE) file */
Trond Myklebust659bfcd2008-06-10 19:39:41 -04003750 if (sattr->ia_valid & ATTR_FILE) {
Trond Myklebust08e9eac2005-06-22 17:16:29 +00003751
Trond Myklebust659bfcd2008-06-10 19:39:41 -04003752 ctx = nfs_file_open_context(sattr->ia_file);
NeilBrown29b59f92016-10-13 15:26:47 +11003753 if (ctx)
Neil Brown504e5182008-10-16 14:15:16 +11003754 cred = ctx->cred;
Trond Myklebust659bfcd2008-06-10 19:39:41 -04003755 }
3756
David Quigley14c43f72013-05-22 12:50:43 -04003757 label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
3758 if (IS_ERR(label))
3759 return PTR_ERR(label);
3760
NeilBrown29b59f92016-10-13 15:26:47 +11003761 status = nfs4_do_setattr(inode, cred, fattr, sattr, ctx, NULL, label);
David Quigleyaa9c2662013-05-22 12:50:44 -04003762 if (status == 0) {
Trond Myklebustf0446362015-02-26 16:09:04 -05003763 nfs_setattr_update_inode(inode, sattr, fattr);
David Quigleyaa9c2662013-05-22 12:50:44 -04003764 nfs_setsecurity(inode, fattr, label);
3765 }
David Quigley14c43f72013-05-22 12:50:43 -04003766 nfs4_label_free(label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003767 return status;
3768}
3769
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003770static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
3771 const struct qstr *name, struct nfs_fh *fhandle,
David Quigley1775fd32013-05-22 12:50:42 -04003772 struct nfs_fattr *fattr, struct nfs4_label *label)
David Howells2b3de442006-08-22 20:06:09 -04003773{
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003774 struct nfs_server *server = NFS_SERVER(dir);
David Howells2b3de442006-08-22 20:06:09 -04003775 int status;
3776 struct nfs4_lookup_arg args = {
3777 .bitmask = server->attr_bitmask,
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003778 .dir_fh = NFS_FH(dir),
David Howells2b3de442006-08-22 20:06:09 -04003779 .name = name,
3780 };
3781 struct nfs4_lookup_res res = {
3782 .server = server,
3783 .fattr = fattr,
David Quigleyaa9c2662013-05-22 12:50:44 -04003784 .label = label,
David Howells2b3de442006-08-22 20:06:09 -04003785 .fh = fhandle,
3786 };
3787 struct rpc_message msg = {
3788 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
3789 .rpc_argp = &args,
3790 .rpc_resp = &res,
3791 };
3792
David Quigleyaa9c2662013-05-22 12:50:44 -04003793 args.bitmask = nfs4_bitmask(server, label);
3794
David Howells2b3de442006-08-22 20:06:09 -04003795 nfs_fattr_init(fattr);
3796
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 dprintk("NFS call lookup %s\n", name->name);
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003798 status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799 dprintk("NFS reply lookup: %d\n", status);
3800 return status;
3801}
3802
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003803static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
Bryan Schumaker7ebb9312011-03-24 17:12:30 +00003804{
Bryan Schumaker7ebb9312011-03-24 17:12:30 +00003805 fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003806 NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_MOUNTPOINT;
Bryan Schumaker7ebb9312011-03-24 17:12:30 +00003807 fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
3808 fattr->nlink = 2;
3809}
3810
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003811static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
Al Virobeffb8f2016-07-20 16:34:42 -04003812 const struct qstr *name, struct nfs_fh *fhandle,
David Quigley1775fd32013-05-22 12:50:42 -04003813 struct nfs_fattr *fattr, struct nfs4_label *label)
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003814{
3815 struct nfs4_exception exception = { };
3816 struct rpc_clnt *client = *clnt;
3817 int err;
3818 do {
David Quigley1775fd32013-05-22 12:50:42 -04003819 err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label);
Trond Myklebust078ea3d2013-08-12 16:45:55 -04003820 trace_nfs4_lookup(dir, name, err);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003821 switch (err) {
3822 case -NFS4ERR_BADNAME:
3823 err = -ENOENT;
3824 goto out;
3825 case -NFS4ERR_MOVED:
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003826 err = nfs4_get_referral(client, dir, name, fattr, fhandle);
Dominique Martinetc86c90c2015-06-04 17:04:17 +02003827 if (err == -NFS4ERR_MOVED)
3828 err = nfs4_handle_exception(NFS_SERVER(dir), err, &exception);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003829 goto out;
3830 case -NFS4ERR_WRONGSEC:
3831 err = -EPERM;
3832 if (client != *clnt)
3833 goto out;
Andy Adamson66b06862014-06-12 15:02:32 -04003834 client = nfs4_negotiate_security(client, dir, name);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003835 if (IS_ERR(client))
3836 return PTR_ERR(client);
3837
3838 exception.retry = 1;
3839 break;
3840 default:
3841 err = nfs4_handle_exception(NFS_SERVER(dir), err, &exception);
3842 }
3843 } while (exception.retry);
3844
3845out:
3846 if (err == 0)
3847 *clnt = client;
3848 else if (client != *clnt)
3849 rpc_shutdown_client(client);
3850
3851 return err;
3852}
3853
Al Virobeffb8f2016-07-20 16:34:42 -04003854static int nfs4_proc_lookup(struct inode *dir, const struct qstr *name,
David Quigley1775fd32013-05-22 12:50:42 -04003855 struct nfs_fh *fhandle, struct nfs_fattr *fattr,
3856 struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857{
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003858 int status;
3859 struct rpc_clnt *client = NFS_CLIENT(dir);
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003860
David Quigley1775fd32013-05-22 12:50:42 -04003861 status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003862 if (client != NFS_CLIENT(dir)) {
3863 rpc_shutdown_client(client);
3864 nfs_fixup_secinfo_attributes(fattr);
3865 }
3866 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003867}
3868
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003869struct rpc_clnt *
Al Virobeffb8f2016-07-20 16:34:42 -04003870nfs4_proc_lookup_mountpoint(struct inode *dir, const struct qstr *name,
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003871 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
3872{
Trond Myklebustb72888c2013-08-07 20:38:07 -04003873 struct rpc_clnt *client = NFS_CLIENT(dir);
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003874 int status;
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003875
David Quigley1775fd32013-05-22 12:50:42 -04003876 status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL);
Trond Myklebustb72888c2013-08-07 20:38:07 -04003877 if (status < 0)
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003878 return ERR_PTR(status);
Trond Myklebustb72888c2013-08-07 20:38:07 -04003879 return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003880}
3881
Jeff Layton5b5faaf2017-06-29 06:34:52 -07003882static int _nfs4_proc_lookupp(struct inode *inode,
3883 struct nfs_fh *fhandle, struct nfs_fattr *fattr,
3884 struct nfs4_label *label)
3885{
3886 struct rpc_clnt *clnt = NFS_CLIENT(inode);
3887 struct nfs_server *server = NFS_SERVER(inode);
3888 int status;
3889 struct nfs4_lookupp_arg args = {
3890 .bitmask = server->attr_bitmask,
3891 .fh = NFS_FH(inode),
3892 };
3893 struct nfs4_lookupp_res res = {
3894 .server = server,
3895 .fattr = fattr,
3896 .label = label,
3897 .fh = fhandle,
3898 };
3899 struct rpc_message msg = {
3900 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUPP],
3901 .rpc_argp = &args,
3902 .rpc_resp = &res,
3903 };
3904
3905 args.bitmask = nfs4_bitmask(server, label);
3906
3907 nfs_fattr_init(fattr);
3908
3909 dprintk("NFS call lookupp ino=0x%lx\n", inode->i_ino);
3910 status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
3911 &res.seq_res, 0);
3912 dprintk("NFS reply lookupp: %d\n", status);
3913 return status;
3914}
3915
3916static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
3917 struct nfs_fattr *fattr, struct nfs4_label *label)
3918{
3919 struct nfs4_exception exception = { };
3920 int err;
3921 do {
3922 err = _nfs4_proc_lookupp(inode, fhandle, fattr, label);
3923 trace_nfs4_lookupp(inode, err);
3924 err = nfs4_handle_exception(NFS_SERVER(inode), err,
3925 &exception);
3926 } while (exception.retry);
3927 return err;
3928}
3929
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
3931{
Trond Myklebust76b32992007-08-10 17:45:11 -04003932 struct nfs_server *server = NFS_SERVER(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003933 struct nfs4_accessargs args = {
3934 .fh = NFS_FH(inode),
Trond Myklebusta4980e72012-01-30 15:43:56 -05003935 .bitmask = server->cache_consistency_bitmask,
Anna Schumaker1750d922017-07-26 12:00:21 -04003936 .access = entry->mask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 };
Trond Myklebust76b32992007-08-10 17:45:11 -04003938 struct nfs4_accessres res = {
3939 .server = server,
Trond Myklebust76b32992007-08-10 17:45:11 -04003940 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003941 struct rpc_message msg = {
3942 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
3943 .rpc_argp = &args,
3944 .rpc_resp = &res,
3945 .rpc_cred = entry->cred,
3946 };
David Quigleyaa9c2662013-05-22 12:50:44 -04003947 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948
Trond Myklebustc407d412010-04-16 16:22:48 -04003949 res.fattr = nfs_alloc_fattr();
3950 if (res.fattr == NULL)
3951 return -ENOMEM;
3952
Bryan Schumaker7c513052011-03-24 17:12:24 +00003953 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 if (!status) {
Weston Andros Adamson6168f622012-09-10 14:00:46 -04003955 nfs_access_set_mask(entry, res.access);
Trond Myklebustc407d412010-04-16 16:22:48 -04003956 nfs_refresh_inode(inode, res.fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003957 }
Trond Myklebustc407d412010-04-16 16:22:48 -04003958 nfs_free_fattr(res.fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003959 return status;
3960}
3961
3962static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
3963{
3964 struct nfs4_exception exception = { };
3965 int err;
3966 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04003967 err = _nfs4_proc_access(inode, entry);
3968 trace_nfs4_access(inode, err);
3969 err = nfs4_handle_exception(NFS_SERVER(inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003970 &exception);
3971 } while (exception.retry);
3972 return err;
3973}
3974
3975/*
3976 * TODO: For the time being, we don't try to get any attributes
3977 * along with any of the zero-copy operations READ, READDIR,
3978 * READLINK, WRITE.
3979 *
3980 * In the case of the first three, we want to put the GETATTR
3981 * after the read-type operation -- this is because it is hard
3982 * to predict the length of a GETATTR response in v4, and thus
3983 * align the READ data correctly. This means that the GETATTR
3984 * may end up partially falling into the page cache, and we should
3985 * shift it into the 'tail' of the xdr_buf before processing.
3986 * To do this efficiently, we need to know the total length
3987 * of data received, which doesn't seem to be available outside
3988 * of the RPC layer.
3989 *
3990 * In the case of WRITE, we also want to put the GETATTR after
3991 * the operation -- in this case because we want to make sure
Trond Myklebust140150d2012-06-05 15:20:25 -04003992 * we get the post-operation mtime and size.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 *
3994 * Both of these changes to the XDR layer would in fact be quite
3995 * minor, but I decided to leave them for a subsequent patch.
3996 */
3997static int _nfs4_proc_readlink(struct inode *inode, struct page *page,
3998 unsigned int pgbase, unsigned int pglen)
3999{
4000 struct nfs4_readlink args = {
4001 .fh = NFS_FH(inode),
4002 .pgbase = pgbase,
4003 .pglen = pglen,
4004 .pages = &page,
4005 };
Benny Halevyf50c7002009-04-01 09:21:55 -04004006 struct nfs4_readlink_res res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007 struct rpc_message msg = {
4008 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK],
4009 .rpc_argp = &args,
Benny Halevyf50c7002009-04-01 09:21:55 -04004010 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004011 };
4012
Bryan Schumaker7c513052011-03-24 17:12:24 +00004013 return nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004014}
4015
4016static int nfs4_proc_readlink(struct inode *inode, struct page *page,
4017 unsigned int pgbase, unsigned int pglen)
4018{
4019 struct nfs4_exception exception = { };
4020 int err;
4021 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04004022 err = _nfs4_proc_readlink(inode, page, pgbase, pglen);
4023 trace_nfs4_readlink(inode, err);
4024 err = nfs4_handle_exception(NFS_SERVER(inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025 &exception);
4026 } while (exception.retry);
4027 return err;
4028}
4029
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030/*
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004031 * This is just for mknod. open(O_CREAT) will always do ->open_context().
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033static int
4034nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004035 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036{
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004037 struct nfs_server *server = NFS_SERVER(dir);
David Quigleyaa9c2662013-05-22 12:50:44 -04004038 struct nfs4_label l, *ilabel = NULL;
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004039 struct nfs_open_context *ctx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 struct nfs4_state *state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004041 int status = 0;
4042
NeilBrown532d4de2016-10-13 15:26:47 +11004043 ctx = alloc_nfs_open_context(dentry, FMODE_READ, NULL);
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004044 if (IS_ERR(ctx))
4045 return PTR_ERR(ctx);
4046
David Quigleyaa9c2662013-05-22 12:50:44 -04004047 ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
4048
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004049 if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
4050 sattr->ia_mode &= ~current_umask();
Kinglong Meec5c3fb52015-08-26 21:11:39 +08004051 state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 if (IS_ERR(state)) {
4053 status = PTR_ERR(state);
Trond Myklebustc0204fd2010-09-17 10:56:51 -04004054 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004055 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056out:
David Quigleyaa9c2662013-05-22 12:50:44 -04004057 nfs4_label_release_security(ilabel);
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004058 put_nfs_open_context(ctx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004059 return status;
4060}
4061
Al Virobeffb8f2016-07-20 16:34:42 -04004062static int _nfs4_proc_remove(struct inode *dir, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004063{
Trond Myklebust16e42952005-10-27 22:12:44 -04004064 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04004065 struct nfs_removeargs args = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 .fh = NFS_FH(dir),
Linus Torvalds26fe5752012-05-10 13:14:12 -07004067 .name = *name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 };
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04004069 struct nfs_removeres res = {
Trond Myklebust16e42952005-10-27 22:12:44 -04004070 .server = server,
Trond Myklebust16e42952005-10-27 22:12:44 -04004071 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 struct rpc_message msg = {
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04004073 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
4074 .rpc_argp = &args,
4075 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 };
Trond Myklebustd3129ef2017-01-11 22:07:28 -05004077 unsigned long timestamp = jiffies;
Trond Myklebust778d2812012-04-27 13:48:19 -04004078 int status;
Trond Myklebustd3468902010-04-16 16:22:50 -04004079
Bryan Schumaker7c513052011-03-24 17:12:24 +00004080 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
Trond Myklebust778d2812012-04-27 13:48:19 -04004081 if (status == 0)
Trond Myklebustd3129ef2017-01-11 22:07:28 -05004082 update_changeattr(dir, &res.cinfo, timestamp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004083 return status;
4084}
4085
Al Virobeffb8f2016-07-20 16:34:42 -04004086static int nfs4_proc_remove(struct inode *dir, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004087{
4088 struct nfs4_exception exception = { };
4089 int err;
4090 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004091 err = _nfs4_proc_remove(dir, name);
4092 trace_nfs4_remove(dir, name, err);
4093 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 &exception);
4095 } while (exception.retry);
4096 return err;
4097}
4098
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004099static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004100{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004101 struct nfs_server *server = NFS_SERVER(dir);
4102 struct nfs_removeargs *args = msg->rpc_argp;
4103 struct nfs_removeres *res = msg->rpc_resp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004105 res->server = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004106 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
Chuck Levera9c92d62013-08-09 12:48:18 -04004107 nfs4_init_sequence(&args->seq_args, &res->seq_res, 1);
David Quigleyaa9c2662013-05-22 12:50:44 -04004108
4109 nfs_fattr_init(res->dir_attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110}
4111
Bryan Schumaker34e137c2012-03-19 14:54:41 -04004112static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
4113{
Anna Schumaker42e1cca2017-01-09 15:48:22 -05004114 nfs4_setup_sequence(NFS_SB(data->dentry->d_sb)->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04004115 &data->args.seq_args,
4116 &data->res.seq_res,
4117 task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118}
4119
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004120static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121{
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004122 struct nfs_unlinkdata *data = task->tk_calldata;
4123 struct nfs_removeres *res = &data->res;
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004124
Trond Myklebust14516c32010-07-31 14:29:06 -04004125 if (!nfs4_sequence_done(task, &res->seq_res))
4126 return 0;
NeilBrown8478eaa2014-09-18 16:09:27 +10004127 if (nfs4_async_handle_error(task, res->server, NULL,
4128 &data->timeout) == -EAGAIN)
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004129 return 0;
Trond Myklebustc40d52f2017-01-11 12:36:11 -05004130 if (task->tk_status == 0)
Trond Myklebustd3129ef2017-01-11 22:07:28 -05004131 update_changeattr(dir, &res->cinfo, res->dir_attr->time_start);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004132 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004133}
4134
Jeff Laytond3d41522010-09-17 17:31:57 -04004135static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
4136{
4137 struct nfs_server *server = NFS_SERVER(dir);
4138 struct nfs_renameargs *arg = msg->rpc_argp;
4139 struct nfs_renameres *res = msg->rpc_resp;
4140
4141 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
Jeff Laytond3d41522010-09-17 17:31:57 -04004142 res->server = server;
Chuck Levera9c92d62013-08-09 12:48:18 -04004143 nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1);
Jeff Laytond3d41522010-09-17 17:31:57 -04004144}
4145
Bryan Schumakerc6bfa1a2012-03-19 14:54:42 -04004146static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
4147{
Anna Schumaker42e1cca2017-01-09 15:48:22 -05004148 nfs4_setup_sequence(NFS_SERVER(data->old_dir)->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04004149 &data->args.seq_args,
4150 &data->res.seq_res,
4151 task);
Jeff Laytond3d41522010-09-17 17:31:57 -04004152}
4153
4154static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
4155 struct inode *new_dir)
4156{
Trond Myklebustfbc6f7c2013-08-12 17:08:26 -04004157 struct nfs_renamedata *data = task->tk_calldata;
4158 struct nfs_renameres *res = &data->res;
Jeff Laytond3d41522010-09-17 17:31:57 -04004159
4160 if (!nfs4_sequence_done(task, &res->seq_res))
4161 return 0;
NeilBrown8478eaa2014-09-18 16:09:27 +10004162 if (nfs4_async_handle_error(task, res->server, NULL, &data->timeout) == -EAGAIN)
Jeff Laytond3d41522010-09-17 17:31:57 -04004163 return 0;
4164
Trond Myklebustc733c492017-01-11 12:32:26 -05004165 if (task->tk_status == 0) {
Trond Myklebustd3129ef2017-01-11 22:07:28 -05004166 update_changeattr(old_dir, &res->old_cinfo, res->old_fattr->time_start);
Trond Myklebustc733c492017-01-11 12:32:26 -05004167 if (new_dir != old_dir)
Trond Myklebustd3129ef2017-01-11 22:07:28 -05004168 update_changeattr(new_dir, &res->new_cinfo, res->new_fattr->time_start);
Trond Myklebustc733c492017-01-11 12:32:26 -05004169 }
Jeff Laytond3d41522010-09-17 17:31:57 -04004170 return 1;
4171}
4172
Al Virobeffb8f2016-07-20 16:34:42 -04004173static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174{
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004175 struct nfs_server *server = NFS_SERVER(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 struct nfs4_link_arg arg = {
4177 .fh = NFS_FH(inode),
4178 .dir_fh = NFS_FH(dir),
4179 .name = name,
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004180 .bitmask = server->attr_bitmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 };
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004182 struct nfs4_link_res res = {
4183 .server = server,
David Quigley1775fd32013-05-22 12:50:42 -04004184 .label = NULL,
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004185 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 struct rpc_message msg = {
4187 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
4188 .rpc_argp = &arg,
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004189 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 };
Trond Myklebust136f2622010-04-16 16:22:49 -04004191 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192
Trond Myklebust136f2622010-04-16 16:22:49 -04004193 res.fattr = nfs_alloc_fattr();
Trond Myklebust778d2812012-04-27 13:48:19 -04004194 if (res.fattr == NULL)
Trond Myklebust136f2622010-04-16 16:22:49 -04004195 goto out;
4196
David Quigley14c43f72013-05-22 12:50:43 -04004197 res.label = nfs4_label_alloc(server, GFP_KERNEL);
4198 if (IS_ERR(res.label)) {
4199 status = PTR_ERR(res.label);
4200 goto out;
4201 }
David Quigleyaa9c2662013-05-22 12:50:44 -04004202 arg.bitmask = nfs4_bitmask(server, res.label);
David Quigley14c43f72013-05-22 12:50:43 -04004203
Bryan Schumaker7c513052011-03-24 17:12:24 +00004204 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004205 if (!status) {
Trond Myklebustd3129ef2017-01-11 22:07:28 -05004206 update_changeattr(dir, &res.cinfo, res.fattr->time_start);
David Quigleyaa9c2662013-05-22 12:50:44 -04004207 status = nfs_post_op_update_inode(inode, res.fattr);
4208 if (!status)
4209 nfs_setsecurity(inode, res.fattr, res.label);
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004210 }
David Quigley14c43f72013-05-22 12:50:43 -04004211
4212
4213 nfs4_label_free(res.label);
4214
Trond Myklebust136f2622010-04-16 16:22:49 -04004215out:
Trond Myklebust136f2622010-04-16 16:22:49 -04004216 nfs_free_fattr(res.fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 return status;
4218}
4219
Al Virobeffb8f2016-07-20 16:34:42 -04004220static int nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004221{
4222 struct nfs4_exception exception = { };
4223 int err;
4224 do {
4225 err = nfs4_handle_exception(NFS_SERVER(inode),
4226 _nfs4_proc_link(inode, dir, name),
4227 &exception);
4228 } while (exception.retry);
4229 return err;
4230}
4231
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004232struct nfs4_createdata {
4233 struct rpc_message msg;
4234 struct nfs4_create_arg arg;
4235 struct nfs4_create_res res;
4236 struct nfs_fh fh;
4237 struct nfs_fattr fattr;
David Quigley1775fd32013-05-22 12:50:42 -04004238 struct nfs4_label *label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004239};
4240
4241static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
Al Virobeffb8f2016-07-20 16:34:42 -04004242 const struct qstr *name, struct iattr *sattr, u32 ftype)
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004243{
4244 struct nfs4_createdata *data;
4245
4246 data = kzalloc(sizeof(*data), GFP_KERNEL);
4247 if (data != NULL) {
4248 struct nfs_server *server = NFS_SERVER(dir);
4249
David Quigley14c43f72013-05-22 12:50:43 -04004250 data->label = nfs4_label_alloc(server, GFP_KERNEL);
4251 if (IS_ERR(data->label))
4252 goto out_free;
4253
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004254 data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
4255 data->msg.rpc_argp = &data->arg;
4256 data->msg.rpc_resp = &data->res;
4257 data->arg.dir_fh = NFS_FH(dir);
4258 data->arg.server = server;
4259 data->arg.name = name;
4260 data->arg.attrs = sattr;
4261 data->arg.ftype = ftype;
David Quigleyaa9c2662013-05-22 12:50:44 -04004262 data->arg.bitmask = nfs4_bitmask(server, data->label);
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004263 data->arg.umask = current_umask();
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004264 data->res.server = server;
4265 data->res.fh = &data->fh;
4266 data->res.fattr = &data->fattr;
David Quigley1775fd32013-05-22 12:50:42 -04004267 data->res.label = data->label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004268 nfs_fattr_init(data->res.fattr);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004269 }
4270 return data;
David Quigley14c43f72013-05-22 12:50:43 -04004271out_free:
4272 kfree(data);
4273 return NULL;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004274}
4275
4276static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
4277{
Bryan Schumaker7c513052011-03-24 17:12:24 +00004278 int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
Bryan Schumakere73b83f2011-03-24 17:12:23 +00004279 &data->arg.seq_args, &data->res.seq_res, 1);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004280 if (status == 0) {
Trond Myklebustd3129ef2017-01-11 22:07:28 -05004281 update_changeattr(dir, &data->res.dir_cinfo,
4282 data->res.fattr->time_start);
David Quigley1775fd32013-05-22 12:50:42 -04004283 status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004284 }
4285 return status;
4286}
4287
4288static void nfs4_free_createdata(struct nfs4_createdata *data)
4289{
David Quigley14c43f72013-05-22 12:50:43 -04004290 nfs4_label_free(data->label);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004291 kfree(data);
4292}
4293
Chuck Lever4f390c12006-08-22 20:06:22 -04004294static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
David Quigley1775fd32013-05-22 12:50:42 -04004295 struct page *page, unsigned int len, struct iattr *sattr,
4296 struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297{
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004298 struct nfs4_createdata *data;
4299 int status = -ENAMETOOLONG;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300
Chuck Lever94a6d752006-08-22 20:06:23 -04004301 if (len > NFS4_MAXPATHLEN)
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004302 goto out;
Chuck Lever4f390c12006-08-22 20:06:22 -04004303
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004304 status = -ENOMEM;
4305 data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4LNK);
4306 if (data == NULL)
4307 goto out;
4308
4309 data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
4310 data->arg.u.symlink.pages = &page;
4311 data->arg.u.symlink.len = len;
David Quigley1775fd32013-05-22 12:50:42 -04004312 data->arg.label = label;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004314 status = nfs4_do_create(dir, dentry, data);
4315
4316 nfs4_free_createdata(data);
4317out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 return status;
4319}
4320
Chuck Lever4f390c12006-08-22 20:06:22 -04004321static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
Chuck Lever94a6d752006-08-22 20:06:23 -04004322 struct page *page, unsigned int len, struct iattr *sattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323{
4324 struct nfs4_exception exception = { };
David Quigleyaa9c2662013-05-22 12:50:44 -04004325 struct nfs4_label l, *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 int err;
David Quigleyaa9c2662013-05-22 12:50:44 -04004327
4328 label = nfs4_label_init_security(dir, dentry, sattr, &l);
4329
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004331 err = _nfs4_proc_symlink(dir, dentry, page, len, sattr, label);
4332 trace_nfs4_symlink(dir, &dentry->d_name, err);
4333 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004334 &exception);
4335 } while (exception.retry);
David Quigleyaa9c2662013-05-22 12:50:44 -04004336
4337 nfs4_label_release_security(label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 return err;
4339}
4340
4341static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
David Quigley1775fd32013-05-22 12:50:42 -04004342 struct iattr *sattr, struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343{
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004344 struct nfs4_createdata *data;
4345 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004347 data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR);
4348 if (data == NULL)
4349 goto out;
4350
David Quigley1775fd32013-05-22 12:50:42 -04004351 data->arg.label = label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004352 status = nfs4_do_create(dir, dentry, data);
4353
4354 nfs4_free_createdata(data);
4355out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004356 return status;
4357}
4358
4359static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
4360 struct iattr *sattr)
4361{
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004362 struct nfs_server *server = NFS_SERVER(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 struct nfs4_exception exception = { };
David Quigleyaa9c2662013-05-22 12:50:44 -04004364 struct nfs4_label l, *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365 int err;
Aneesh Kumar K.Va8a5da92010-12-09 11:35:14 +00004366
David Quigleyaa9c2662013-05-22 12:50:44 -04004367 label = nfs4_label_init_security(dir, dentry, sattr, &l);
4368
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004369 if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
4370 sattr->ia_mode &= ~current_umask();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004371 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004372 err = _nfs4_proc_mkdir(dir, dentry, sattr, label);
4373 trace_nfs4_mkdir(dir, &dentry->d_name, err);
4374 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004375 &exception);
4376 } while (exception.retry);
David Quigleyaa9c2662013-05-22 12:50:44 -04004377 nfs4_label_release_security(label);
4378
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 return err;
4380}
4381
4382static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04004383 u64 cookie, struct page **pages, unsigned int count, bool plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384{
David Howells2b0143b2015-03-17 22:25:59 +00004385 struct inode *dir = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004386 struct nfs4_readdir_arg args = {
4387 .fh = NFS_FH(dir),
Bryan Schumaker56e4ebf2010-10-20 15:44:37 -04004388 .pages = pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 .pgbase = 0,
4390 .count = count,
David Howells2b0143b2015-03-17 22:25:59 +00004391 .bitmask = NFS_SERVER(d_inode(dentry))->attr_bitmask,
Bryan Schumaker82f2e542010-10-21 16:33:18 -04004392 .plus = plus,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004393 };
4394 struct nfs4_readdir_res res;
4395 struct rpc_message msg = {
4396 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
4397 .rpc_argp = &args,
4398 .rpc_resp = &res,
4399 .rpc_cred = cred,
4400 };
4401 int status;
4402
Al Viro6de14722013-09-16 10:53:17 -04004403 dprintk("%s: dentry = %pd2, cookie = %Lu\n", __func__,
4404 dentry,
Trond Myklebusteadf4592005-06-22 17:16:39 +00004405 (unsigned long long)cookie);
Trond Myklebustc3f52af2012-09-03 14:56:02 -04004406 nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 res.pgbase = args.pgbase;
Bryan Schumaker7c513052011-03-24 17:12:24 +00004408 status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
Trond Myklebustac396122010-11-15 20:26:22 -05004409 if (status >= 0) {
Trond Myklebustc3f52af2012-09-03 14:56:02 -04004410 memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE);
Trond Myklebustac396122010-11-15 20:26:22 -05004411 status += args.pgbase;
4412 }
Trond Myklebustc4812992007-09-28 17:11:45 -04004413
4414 nfs_invalidate_atime(dir);
4415
Harvey Harrison3110ff82008-05-02 13:42:44 -07004416 dprintk("%s: returns %d\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 return status;
4418}
4419
4420static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04004421 u64 cookie, struct page **pages, unsigned int count, bool plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422{
4423 struct nfs4_exception exception = { };
4424 int err;
4425 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04004426 err = _nfs4_proc_readdir(dentry, cred, cookie,
4427 pages, count, plus);
David Howells2b0143b2015-03-17 22:25:59 +00004428 trace_nfs4_readdir(d_inode(dentry), err);
4429 err = nfs4_handle_exception(NFS_SERVER(d_inode(dentry)), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 &exception);
4431 } while (exception.retry);
4432 return err;
4433}
4434
4435static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
David Quigleyaa9c2662013-05-22 12:50:44 -04004436 struct iattr *sattr, struct nfs4_label *label, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437{
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004438 struct nfs4_createdata *data;
4439 int mode = sattr->ia_mode;
4440 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004441
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004442 data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK);
4443 if (data == NULL)
4444 goto out;
4445
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 if (S_ISFIFO(mode))
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004447 data->arg.ftype = NF4FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 else if (S_ISBLK(mode)) {
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004449 data->arg.ftype = NF4BLK;
4450 data->arg.u.device.specdata1 = MAJOR(rdev);
4451 data->arg.u.device.specdata2 = MINOR(rdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452 }
4453 else if (S_ISCHR(mode)) {
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004454 data->arg.ftype = NF4CHR;
4455 data->arg.u.device.specdata1 = MAJOR(rdev);
4456 data->arg.u.device.specdata2 = MINOR(rdev);
Trond Myklebust4ea8fed2012-10-15 15:47:41 -04004457 } else if (!S_ISSOCK(mode)) {
4458 status = -EINVAL;
4459 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 }
David Quigley1775fd32013-05-22 12:50:42 -04004461
David Quigleyaa9c2662013-05-22 12:50:44 -04004462 data->arg.label = label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004463 status = nfs4_do_create(dir, dentry, data);
Trond Myklebust4ea8fed2012-10-15 15:47:41 -04004464out_free:
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004465 nfs4_free_createdata(data);
4466out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004467 return status;
4468}
4469
4470static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
4471 struct iattr *sattr, dev_t rdev)
4472{
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004473 struct nfs_server *server = NFS_SERVER(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 struct nfs4_exception exception = { };
David Quigleyaa9c2662013-05-22 12:50:44 -04004475 struct nfs4_label l, *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476 int err;
Aneesh Kumar K.Va8a5da92010-12-09 11:35:14 +00004477
David Quigleyaa9c2662013-05-22 12:50:44 -04004478 label = nfs4_label_init_security(dir, dentry, sattr, &l);
4479
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004480 if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
4481 sattr->ia_mode &= ~current_umask();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004483 err = _nfs4_proc_mknod(dir, dentry, sattr, label, rdev);
4484 trace_nfs4_mknod(dir, &dentry->d_name, err);
4485 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 &exception);
4487 } while (exception.retry);
David Quigleyaa9c2662013-05-22 12:50:44 -04004488
4489 nfs4_label_release_security(label);
4490
Linus Torvalds1da177e2005-04-16 15:20:36 -07004491 return err;
4492}
4493
4494static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
4495 struct nfs_fsstat *fsstat)
4496{
4497 struct nfs4_statfs_arg args = {
4498 .fh = fhandle,
4499 .bitmask = server->attr_bitmask,
4500 };
Benny Halevy24ad1482009-04-01 09:21:56 -04004501 struct nfs4_statfs_res res = {
4502 .fsstat = fsstat,
4503 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 struct rpc_message msg = {
4505 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS],
4506 .rpc_argp = &args,
Benny Halevy24ad1482009-04-01 09:21:56 -04004507 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004508 };
4509
Trond Myklebust0e574af2005-10-27 22:12:38 -04004510 nfs_fattr_init(fsstat->fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00004511 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004512}
4513
4514static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
4515{
4516 struct nfs4_exception exception = { };
4517 int err;
4518 do {
4519 err = nfs4_handle_exception(server,
4520 _nfs4_proc_statfs(server, fhandle, fsstat),
4521 &exception);
4522 } while (exception.retry);
4523 return err;
4524}
4525
4526static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
4527 struct nfs_fsinfo *fsinfo)
4528{
4529 struct nfs4_fsinfo_arg args = {
4530 .fh = fhandle,
4531 .bitmask = server->attr_bitmask,
4532 };
Benny Halevy3dda5e42009-04-01 09:21:57 -04004533 struct nfs4_fsinfo_res res = {
4534 .fsinfo = fsinfo,
4535 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 struct rpc_message msg = {
4537 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO],
4538 .rpc_argp = &args,
Benny Halevy3dda5e42009-04-01 09:21:57 -04004539 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004540 };
4541
Bryan Schumaker7c513052011-03-24 17:12:24 +00004542 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004543}
4544
4545static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
4546{
4547 struct nfs4_exception exception = { };
Chuck Lever83ca7f52013-03-16 15:55:53 -04004548 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004549 int err;
4550
4551 do {
Chuck Lever83ca7f52013-03-16 15:55:53 -04004552 err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
Trond Myklebustb5f875a2013-08-13 13:01:39 -04004553 trace_nfs4_fsinfo(server, fhandle, fsinfo->fattr, err);
Chuck Lever83ca7f52013-03-16 15:55:53 -04004554 if (err == 0) {
Trond Myklebustfb10fb62016-08-05 19:13:08 -04004555 nfs4_set_lease_period(server->nfs_client,
4556 fsinfo->lease_time * HZ,
4557 now);
Chuck Lever83ca7f52013-03-16 15:55:53 -04004558 break;
4559 }
4560 err = nfs4_handle_exception(server, err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004561 } while (exception.retry);
4562 return err;
4563}
4564
4565static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
4566{
Bryan Schumakere38eb652012-06-20 15:53:40 -04004567 int error;
4568
Trond Myklebust0e574af2005-10-27 22:12:38 -04004569 nfs_fattr_init(fsinfo->fattr);
Bryan Schumakere38eb652012-06-20 15:53:40 -04004570 error = nfs4_do_fsinfo(server, fhandle, fsinfo);
Peng Taodc182542012-08-24 00:27:49 +08004571 if (error == 0) {
4572 /* block layout checks this! */
4573 server->pnfs_blksize = fsinfo->blksize;
Jeff Laytonca440c32016-09-15 14:40:49 -04004574 set_pnfs_layoutdriver(server, fhandle, fsinfo);
Peng Taodc182542012-08-24 00:27:49 +08004575 }
Bryan Schumakere38eb652012-06-20 15:53:40 -04004576
4577 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004578}
4579
4580static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
4581 struct nfs_pathconf *pathconf)
4582{
4583 struct nfs4_pathconf_arg args = {
4584 .fh = fhandle,
4585 .bitmask = server->attr_bitmask,
4586 };
Benny Halevyd45b2982009-04-01 09:21:58 -04004587 struct nfs4_pathconf_res res = {
4588 .pathconf = pathconf,
4589 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 struct rpc_message msg = {
4591 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF],
4592 .rpc_argp = &args,
Benny Halevyd45b2982009-04-01 09:21:58 -04004593 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 };
4595
4596 /* None of the pathconf attributes are mandatory to implement */
4597 if ((args.bitmask[0] & nfs4_pathconf_bitmap[0]) == 0) {
4598 memset(pathconf, 0, sizeof(*pathconf));
4599 return 0;
4600 }
4601
Trond Myklebust0e574af2005-10-27 22:12:38 -04004602 nfs_fattr_init(pathconf->fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00004603 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604}
4605
4606static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
4607 struct nfs_pathconf *pathconf)
4608{
4609 struct nfs4_exception exception = { };
4610 int err;
4611
4612 do {
4613 err = nfs4_handle_exception(server,
4614 _nfs4_proc_pathconf(server, fhandle, pathconf),
4615 &exception);
4616 } while (exception.retry);
4617 return err;
4618}
4619
Trond Myklebust5521abf2013-03-16 20:54:34 -04004620int nfs4_set_rw_stateid(nfs4_stateid *stateid,
Trond Myklebust9b206142013-03-17 15:52:00 -04004621 const struct nfs_open_context *ctx,
4622 const struct nfs_lock_context *l_ctx,
4623 fmode_t fmode)
4624{
NeilBrown17393472016-10-13 15:26:47 +11004625 return nfs4_select_rw_stateid(ctx->state, fmode, l_ctx, stateid, NULL);
Trond Myklebust9b206142013-03-17 15:52:00 -04004626}
4627EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid);
4628
Trond Myklebust5521abf2013-03-16 20:54:34 -04004629static bool nfs4_stateid_is_current(nfs4_stateid *stateid,
4630 const struct nfs_open_context *ctx,
4631 const struct nfs_lock_context *l_ctx,
4632 fmode_t fmode)
4633{
4634 nfs4_stateid current_stateid;
4635
Trond Myklebuste1253be2014-03-05 08:44:23 -05004636 /* If the current stateid represents a lost lock, then exit */
4637 if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode) == -EIO)
4638 return true;
Trond Myklebust5521abf2013-03-16 20:54:34 -04004639 return nfs4_stateid_match(stateid, &current_stateid);
4640}
4641
4642static bool nfs4_error_stateid_expired(int err)
4643{
4644 switch (err) {
4645 case -NFS4ERR_DELEG_REVOKED:
4646 case -NFS4ERR_ADMIN_REVOKED:
4647 case -NFS4ERR_BAD_STATEID:
4648 case -NFS4ERR_STALE_STATEID:
4649 case -NFS4ERR_OLD_STATEID:
4650 case -NFS4ERR_OPENMODE:
4651 case -NFS4ERR_EXPIRED:
4652 return true;
4653 }
4654 return false;
4655}
4656
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004657static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004658{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004659 struct nfs_server *server = NFS_SERVER(hdr->inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004660
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004661 trace_nfs4_read(hdr, task->tk_status);
Trond Myklebust9c278692016-09-22 13:39:11 -04004662 if (task->tk_status < 0) {
4663 struct nfs4_exception exception = {
4664 .inode = hdr->inode,
4665 .state = hdr->args.context->state,
4666 .stateid = &hdr->args.stateid,
4667 };
4668 task->tk_status = nfs4_async_handle_exception(task,
4669 server, task->tk_status, &exception);
4670 if (exception.retry) {
4671 rpc_restart_call_prepare(task);
4672 return -EAGAIN;
4673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004674 }
Trond Myklebust8850df92007-09-28 17:20:07 -04004675
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 if (task->tk_status > 0)
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004677 renew_lease(server, hdr->timestamp);
Trond Myklebustec06c092006-03-20 13:44:27 -05004678 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679}
4680
Trond Myklebust5521abf2013-03-16 20:54:34 -04004681static bool nfs4_read_stateid_changed(struct rpc_task *task,
Anna Schumaker3c6b8992014-05-06 09:12:24 -04004682 struct nfs_pgio_args *args)
Trond Myklebust5521abf2013-03-16 20:54:34 -04004683{
4684
4685 if (!nfs4_error_stateid_expired(task->tk_status) ||
4686 nfs4_stateid_is_current(&args->stateid,
4687 args->context,
4688 args->lock_context,
4689 FMODE_READ))
4690 return false;
4691 rpc_restart_call_prepare(task);
4692 return true;
4693}
4694
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004695static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
Andy Adamsoncbdabc72011-03-01 01:34:20 +00004696{
4697
4698 dprintk("--> %s\n", __func__);
4699
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004700 if (!nfs4_sequence_done(task, &hdr->res.seq_res))
Andy Adamsoncbdabc72011-03-01 01:34:20 +00004701 return -EAGAIN;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004702 if (nfs4_read_stateid_changed(task, &hdr->args))
Trond Myklebust5521abf2013-03-16 20:54:34 -04004703 return -EAGAIN;
Trond Myklebustbfc505d2016-09-15 18:26:05 -04004704 if (task->tk_status > 0)
4705 nfs_invalidate_atime(hdr->inode);
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004706 return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) :
4707 nfs4_read_done_cb(task, hdr);
Andy Adamsoncbdabc72011-03-01 01:34:20 +00004708}
4709
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004710static void nfs4_proc_read_setup(struct nfs_pgio_header *hdr,
4711 struct rpc_message *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004713 hdr->timestamp = jiffies;
Trond Myklebustca857cc2016-06-28 13:54:09 -04004714 if (!hdr->pgio_done_cb)
4715 hdr->pgio_done_cb = nfs4_read_done_cb;
Trond Myklebustbdc7f022007-07-14 15:40:00 -04004716 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004717 nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718}
4719
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004720static int nfs4_proc_pgio_rpc_prepare(struct rpc_task *task,
4721 struct nfs_pgio_header *hdr)
Bryan Schumakerea7c3302012-03-19 14:54:40 -04004722{
Anna Schumaker42e1cca2017-01-09 15:48:22 -05004723 if (nfs4_setup_sequence(NFS_SERVER(hdr->inode)->nfs_client,
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004724 &hdr->args.seq_args,
4725 &hdr->res.seq_res,
Trond Myklebust9b206142013-03-17 15:52:00 -04004726 task))
NeilBrownef1820f2013-09-04 17:04:49 +10004727 return 0;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004728 if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
4729 hdr->args.lock_context,
Benjamin Coddingtonfbe77c32017-04-19 10:11:35 -04004730 hdr->rw_mode) == -EIO)
NeilBrownef1820f2013-09-04 17:04:49 +10004731 return -EIO;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004732 if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags)))
NeilBrownef1820f2013-09-04 17:04:49 +10004733 return -EIO;
4734 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735}
4736
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004737static int nfs4_write_done_cb(struct rpc_task *task,
4738 struct nfs_pgio_header *hdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004739{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004740 struct inode *inode = hdr->inode;
NeilBrown8478eaa2014-09-18 16:09:27 +10004741
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004742 trace_nfs4_write(hdr, task->tk_status);
Trond Myklebust9c278692016-09-22 13:39:11 -04004743 if (task->tk_status < 0) {
4744 struct nfs4_exception exception = {
4745 .inode = hdr->inode,
4746 .state = hdr->args.context->state,
4747 .stateid = &hdr->args.stateid,
4748 };
4749 task->tk_status = nfs4_async_handle_exception(task,
4750 NFS_SERVER(inode), task->tk_status,
4751 &exception);
4752 if (exception.retry) {
4753 rpc_restart_call_prepare(task);
4754 return -EAGAIN;
4755 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 }
Trond Myklebust4f9838c2005-10-27 22:12:44 -04004757 if (task->tk_status >= 0) {
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004758 renew_lease(NFS_SERVER(inode), hdr->timestamp);
Trond Myklebusta08a8cd2015-02-26 17:36:09 -05004759 nfs_writeback_update_inode(hdr);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04004760 }
Trond Myklebust788e7a82006-03-20 13:44:27 -05004761 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762}
4763
Trond Myklebust5521abf2013-03-16 20:54:34 -04004764static bool nfs4_write_stateid_changed(struct rpc_task *task,
Anna Schumaker3c6b8992014-05-06 09:12:24 -04004765 struct nfs_pgio_args *args)
Trond Myklebust5521abf2013-03-16 20:54:34 -04004766{
4767
4768 if (!nfs4_error_stateid_expired(task->tk_status) ||
4769 nfs4_stateid_is_current(&args->stateid,
4770 args->context,
4771 args->lock_context,
4772 FMODE_WRITE))
4773 return false;
4774 rpc_restart_call_prepare(task);
4775 return true;
4776}
4777
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004778static int nfs4_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
Fred Isamanb029bc92011-03-03 15:13:42 +00004779{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004780 if (!nfs4_sequence_done(task, &hdr->res.seq_res))
Fred Isamanb029bc92011-03-03 15:13:42 +00004781 return -EAGAIN;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004782 if (nfs4_write_stateid_changed(task, &hdr->args))
Trond Myklebust5521abf2013-03-16 20:54:34 -04004783 return -EAGAIN;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004784 return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) :
4785 nfs4_write_done_cb(task, hdr);
Fred Isamanb029bc92011-03-03 15:13:42 +00004786}
4787
Trond Myklebust5a37f852012-04-28 14:55:16 -04004788static
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004789bool nfs4_write_need_cache_consistency_data(struct nfs_pgio_header *hdr)
Fred Isamana69aef12011-03-03 15:13:47 +00004790{
Trond Myklebust5a37f852012-04-28 14:55:16 -04004791 /* Don't request attributes for pNFS or O_DIRECT writes */
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004792 if (hdr->ds_clp != NULL || hdr->dreq != NULL)
Trond Myklebust5a37f852012-04-28 14:55:16 -04004793 return false;
4794 /* Otherwise, request attributes if and only if we don't hold
4795 * a delegation
4796 */
Bryan Schumaker011e2a72012-06-20 15:53:43 -04004797 return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0;
Fred Isamana69aef12011-03-03 15:13:47 +00004798}
Fred Isamana69aef12011-03-03 15:13:47 +00004799
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004800static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr,
4801 struct rpc_message *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004802{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004803 struct nfs_server *server = NFS_SERVER(hdr->inode);
Trond Myklebustbdc7f022007-07-14 15:40:00 -04004804
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004805 if (!nfs4_write_need_cache_consistency_data(hdr)) {
4806 hdr->args.bitmask = NULL;
4807 hdr->res.fattr = NULL;
Fred Isaman7ffd1062011-03-03 15:13:46 +00004808 } else
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004809 hdr->args.bitmask = server->cache_consistency_bitmask;
Trond Myklebust5a37f852012-04-28 14:55:16 -04004810
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004811 if (!hdr->pgio_done_cb)
4812 hdr->pgio_done_cb = nfs4_write_done_cb;
4813 hdr->res.server = server;
4814 hdr->timestamp = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004815
Trond Myklebustbdc7f022007-07-14 15:40:00 -04004816 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04004817 nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818}
4819
Fred Isaman0b7c0152012-04-20 14:47:39 -04004820static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
4821{
Anna Schumaker42e1cca2017-01-09 15:48:22 -05004822 nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04004823 &data->args.seq_args,
4824 &data->res.seq_res,
4825 task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004826}
4827
Fred Isaman0b7c0152012-04-20 14:47:39 -04004828static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004830 struct inode *inode = data->inode;
Trond Myklebust14516c32010-07-31 14:29:06 -04004831
Trond Myklebustcc668ab2013-08-14 15:31:28 -04004832 trace_nfs4_commit(data, task->tk_status);
NeilBrown8478eaa2014-09-18 16:09:27 +10004833 if (nfs4_async_handle_error(task, NFS_SERVER(inode),
4834 NULL, NULL) == -EAGAIN) {
Trond Myklebustd00c5d42011-10-19 12:17:29 -07004835 rpc_restart_call_prepare(task);
Trond Myklebust788e7a82006-03-20 13:44:27 -05004836 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837 }
Trond Myklebust788e7a82006-03-20 13:44:27 -05004838 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839}
4840
Fred Isaman0b7c0152012-04-20 14:47:39 -04004841static int nfs4_commit_done(struct rpc_task *task, struct nfs_commit_data *data)
Fred Isaman5f452432011-03-23 13:27:46 +00004842{
4843 if (!nfs4_sequence_done(task, &data->res.seq_res))
4844 return -EAGAIN;
Fred Isaman0b7c0152012-04-20 14:47:39 -04004845 return data->commit_done_cb(task, data);
Fred Isaman5f452432011-03-23 13:27:46 +00004846}
4847
Fred Isaman0b7c0152012-04-20 14:47:39 -04004848static void nfs4_proc_commit_setup(struct nfs_commit_data *data, struct rpc_message *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849{
Trond Myklebust788e7a82006-03-20 13:44:27 -05004850 struct nfs_server *server = NFS_SERVER(data->inode);
Fred Isaman988b6dc2011-03-23 13:27:52 +00004851
Fred Isaman0b7c0152012-04-20 14:47:39 -04004852 if (data->commit_done_cb == NULL)
4853 data->commit_done_cb = nfs4_commit_done_cb;
Trond Myklebust4f9838c2005-10-27 22:12:44 -04004854 data->res.server = server;
Trond Myklebustbdc7f022007-07-14 15:40:00 -04004855 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
Chuck Levera9c92d62013-08-09 12:48:18 -04004856 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857}
4858
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004859struct nfs4_renewdata {
4860 struct nfs_client *client;
4861 unsigned long timestamp;
4862};
4863
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864/*
4865 * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special
4866 * standalone procedure for queueing an asynchronous RENEW.
4867 */
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004868static void nfs4_renew_release(void *calldata)
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08004869{
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004870 struct nfs4_renewdata *data = calldata;
4871 struct nfs_client *clp = data->client;
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08004872
Elena Reshetova212bf412017-10-20 12:53:38 +03004873 if (refcount_read(&clp->cl_count) > 1)
Alexandros Batsakis0851de062010-02-05 03:45:06 -08004874 nfs4_schedule_state_renewal(clp);
4875 nfs_put_client(clp);
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004876 kfree(data);
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08004877}
4878
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004879static void nfs4_renew_done(struct rpc_task *task, void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004880{
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004881 struct nfs4_renewdata *data = calldata;
4882 struct nfs_client *clp = data->client;
4883 unsigned long timestamp = data->timestamp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004884
Trond Myklebustc6d01c62013-08-09 11:51:26 -04004885 trace_nfs4_renew_async(clp, task->tk_status);
Chuck Leverf8aba1e2013-10-17 14:13:53 -04004886 switch (task->tk_status) {
4887 case 0:
4888 break;
4889 case -NFS4ERR_LEASE_MOVED:
4890 nfs4_schedule_lease_moved_recovery(clp);
4891 break;
4892 default:
Trond Myklebust95baa252009-05-26 14:51:00 -04004893 /* Unless we're shutting down, schedule state recovery! */
Trond Myklebust042b60b2011-08-24 15:07:37 -04004894 if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0)
4895 return;
4896 if (task->tk_status != NFS4ERR_CB_PATH_DOWN) {
Trond Myklebust0400a6b2011-03-09 16:00:53 -05004897 nfs4_schedule_lease_recovery(clp);
Trond Myklebust042b60b2011-08-24 15:07:37 -04004898 return;
4899 }
4900 nfs4_schedule_path_down_recovery(clp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004901 }
Trond Myklebust452e9352010-07-31 14:29:06 -04004902 do_renew_lease(clp, timestamp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903}
4904
Trond Myklebust963d8fe2006-01-03 09:55:04 +01004905static const struct rpc_call_ops nfs4_renew_ops = {
4906 .rpc_call_done = nfs4_renew_done,
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08004907 .rpc_release = nfs4_renew_release,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01004908};
4909
Trond Myklebust2f60ea62011-08-24 15:07:37 -04004910static int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004911{
4912 struct rpc_message msg = {
4913 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
4914 .rpc_argp = clp,
Trond Myklebustb4454fe2006-01-03 09:55:25 +01004915 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004916 };
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004917 struct nfs4_renewdata *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918
Trond Myklebust2f60ea62011-08-24 15:07:37 -04004919 if (renew_flags == 0)
4920 return 0;
Elena Reshetova212bf412017-10-20 12:53:38 +03004921 if (!refcount_inc_not_zero(&clp->cl_count))
Alexandros Batsakis0851de062010-02-05 03:45:06 -08004922 return -EIO;
Trond Myklebustb569ad32011-08-24 15:07:35 -04004923 data = kmalloc(sizeof(*data), GFP_NOFS);
Dave Wysochanski5c737cb2017-04-27 10:45:15 -04004924 if (data == NULL) {
4925 nfs_put_client(clp);
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004926 return -ENOMEM;
Dave Wysochanski5c737cb2017-04-27 10:45:15 -04004927 }
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004928 data->client = clp;
4929 data->timestamp = jiffies;
Trond Myklebustbc7a05c2013-04-08 17:50:28 -04004930 return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT,
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004931 &nfs4_renew_ops, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004932}
4933
Trond Myklebust8534d4e2011-08-24 15:07:37 -04004934static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004935{
4936 struct rpc_message msg = {
4937 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
4938 .rpc_argp = clp,
Trond Myklebustb4454fe2006-01-03 09:55:25 +01004939 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004940 };
4941 unsigned long now = jiffies;
4942 int status;
4943
Trond Myklebustbc7a05c2013-04-08 17:50:28 -04004944 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 if (status < 0)
4946 return status;
Trond Myklebust452e9352010-07-31 14:29:06 -04004947 do_renew_lease(clp, now);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948 return 0;
4949}
4950
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004951static inline int nfs4_server_supports_acls(struct nfs_server *server)
4952{
Malahal Naineni7dd7d952014-01-23 08:54:55 -06004953 return server->caps & NFS_CAP_ACLS;
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004954}
4955
Trond Myklebust21f498c2012-08-24 10:59:25 -04004956/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
4957 * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004958 * the stack.
4959 */
Trond Myklebust21f498c2012-08-24 10:59:25 -04004960#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004961
Neil Hormane9e3d722011-03-04 19:26:03 -05004962static int buf_to_pages_noslab(const void *buf, size_t buflen,
Andreas Gruenbacher8fbcf232015-11-03 18:25:34 +01004963 struct page **pages)
Neil Hormane9e3d722011-03-04 19:26:03 -05004964{
4965 struct page *newpage, **spages;
4966 int rc = 0;
4967 size_t len;
4968 spages = pages;
4969
4970 do {
Trond Myklebust21f498c2012-08-24 10:59:25 -04004971 len = min_t(size_t, PAGE_SIZE, buflen);
Neil Hormane9e3d722011-03-04 19:26:03 -05004972 newpage = alloc_page(GFP_KERNEL);
4973
4974 if (newpage == NULL)
4975 goto unwind;
4976 memcpy(page_address(newpage), buf, len);
Anna Schumakerd9b67e12017-01-11 15:04:25 -05004977 buf += len;
4978 buflen -= len;
Neil Hormane9e3d722011-03-04 19:26:03 -05004979 *pages++ = newpage;
4980 rc++;
4981 } while (buflen != 0);
4982
4983 return rc;
4984
4985unwind:
4986 for(; rc > 0; rc--)
4987 __free_page(spages[rc-1]);
4988 return -ENOMEM;
4989}
4990
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004991struct nfs4_cached_acl {
4992 int cached;
4993 size_t len;
Andrew Morton3e9d4152005-06-22 17:16:28 +00004994 char data[0];
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004995};
4996
4997static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl)
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004998{
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004999 struct nfs_inode *nfsi = NFS_I(inode);
5000
5001 spin_lock(&inode->i_lock);
5002 kfree(nfsi->nfs4_acl);
5003 nfsi->nfs4_acl = acl;
5004 spin_unlock(&inode->i_lock);
5005}
5006
5007static void nfs4_zap_acl_attr(struct inode *inode)
5008{
5009 nfs4_set_cached_acl(inode, NULL);
5010}
5011
5012static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen)
5013{
5014 struct nfs_inode *nfsi = NFS_I(inode);
5015 struct nfs4_cached_acl *acl;
5016 int ret = -ENOENT;
5017
5018 spin_lock(&inode->i_lock);
5019 acl = nfsi->nfs4_acl;
5020 if (acl == NULL)
5021 goto out;
5022 if (buf == NULL) /* user is just asking for length */
5023 goto out_len;
5024 if (acl->cached == 0)
5025 goto out;
5026 ret = -ERANGE; /* see getxattr(2) man page */
5027 if (acl->len > buflen)
5028 goto out;
5029 memcpy(buf, acl->data, acl->len);
5030out_len:
5031 ret = acl->len;
5032out:
5033 spin_unlock(&inode->i_lock);
5034 return ret;
5035}
5036
Sachin Prabhu5794d212012-04-17 14:36:40 +01005037static void nfs4_write_cached_acl(struct inode *inode, struct page **pages, size_t pgbase, size_t acl_len)
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005038{
5039 struct nfs4_cached_acl *acl;
Trond Myklebustb291f1b2012-08-14 18:30:41 -04005040 size_t buflen = sizeof(*acl) + acl_len;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005041
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005042 if (buflen <= PAGE_SIZE) {
Trond Myklebustb291f1b2012-08-14 18:30:41 -04005043 acl = kmalloc(buflen, GFP_KERNEL);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005044 if (acl == NULL)
5045 goto out;
5046 acl->cached = 1;
Sachin Prabhu5794d212012-04-17 14:36:40 +01005047 _copy_from_pages(acl->data, pages, pgbase, acl_len);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005048 } else {
5049 acl = kmalloc(sizeof(*acl), GFP_KERNEL);
5050 if (acl == NULL)
5051 goto out;
5052 acl->cached = 0;
5053 }
5054 acl->len = acl_len;
5055out:
5056 nfs4_set_cached_acl(inode, acl);
5057}
5058
Andy Adamsonbf118a32011-12-07 11:55:27 -05005059/*
5060 * The getxattr API returns the required buffer length when called with a
5061 * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating
5062 * the required buf. On a NULL buf, we send a page of data to the server
5063 * guessing that the ACL request can be serviced by a page. If so, we cache
5064 * up to the page of ACL data, and the 2nd call to getxattr is serviced by
5065 * the cache. If not so, we throw away the page, and cache the required
5066 * length. The next getxattr call will then produce another round trip to
5067 * the server, this time with the input buf of the required size.
5068 */
Trond Myklebust16b42892006-08-24 12:27:15 -04005069static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005070{
Weston Andros Adamsoned92d8c2017-02-23 14:54:21 -05005071 struct page *pages[NFS4ACL_MAXPAGES + 1] = {NULL, };
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005072 struct nfs_getaclargs args = {
5073 .fh = NFS_FH(inode),
5074 .acl_pages = pages,
5075 .acl_len = buflen,
5076 };
Benny Halevy663c79b2009-04-01 09:21:59 -04005077 struct nfs_getaclres res = {
5078 .acl_len = buflen,
5079 };
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005080 struct rpc_message msg = {
5081 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],
5082 .rpc_argp = &args,
Benny Halevy663c79b2009-04-01 09:21:59 -04005083 .rpc_resp = &res,
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005084 };
Weston Andros Adamsoned92d8c2017-02-23 14:54:21 -05005085 unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
Trond Myklebust21f498c2012-08-24 10:59:25 -04005086 int ret = -ENOMEM, i;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005087
Trond Myklebust21f498c2012-08-24 10:59:25 -04005088 if (npages > ARRAY_SIZE(pages))
5089 return -ERANGE;
Sachin Prabhu5a006892012-04-17 14:35:39 +01005090
Andy Adamsonbf118a32011-12-07 11:55:27 -05005091 for (i = 0; i < npages; i++) {
5092 pages[i] = alloc_page(GFP_KERNEL);
5093 if (!pages[i])
5094 goto out_free;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005095 }
Sachin Prabhu5a006892012-04-17 14:35:39 +01005096
5097 /* for decoding across pages */
5098 res.acl_scratch = alloc_page(GFP_KERNEL);
5099 if (!res.acl_scratch)
5100 goto out_free;
5101
Andy Adamsonbf118a32011-12-07 11:55:27 -05005102 args.acl_len = npages * PAGE_SIZE;
Sachin Prabhu5a006892012-04-17 14:35:39 +01005103
Peng Taode040be2012-01-10 22:42:47 +08005104 dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n",
Andy Adamsonbf118a32011-12-07 11:55:27 -05005105 __func__, buf, buflen, npages, args.acl_len);
5106 ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
5107 &msg, &args.seq_args, &res.seq_res, 0);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005108 if (ret)
5109 goto out_free;
Andy Adamsonbf118a32011-12-07 11:55:27 -05005110
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005111 /* Handle the case where the passed-in buffer is too short */
5112 if (res.acl_flags & NFS4_ACL_TRUNC) {
5113 /* Did the user only issue a request for the acl length? */
5114 if (buf == NULL)
5115 goto out_ok;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005116 ret = -ERANGE;
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005117 goto out_free;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005118 }
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005119 nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len);
Sven Wegener7d3e91a2012-12-08 15:30:18 +01005120 if (buf) {
5121 if (res.acl_len > buflen) {
5122 ret = -ERANGE;
5123 goto out_free;
5124 }
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005125 _copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len);
Sven Wegener7d3e91a2012-12-08 15:30:18 +01005126 }
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005127out_ok:
5128 ret = res.acl_len;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005129out_free:
Andy Adamsonbf118a32011-12-07 11:55:27 -05005130 for (i = 0; i < npages; i++)
5131 if (pages[i])
5132 __free_page(pages[i]);
Trond Myklebust331818f2012-02-03 18:30:53 -05005133 if (res.acl_scratch)
5134 __free_page(res.acl_scratch);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005135 return ret;
5136}
5137
Trond Myklebust16b42892006-08-24 12:27:15 -04005138static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
5139{
5140 struct nfs4_exception exception = { };
5141 ssize_t ret;
5142 do {
5143 ret = __nfs4_get_acl_uncached(inode, buf, buflen);
Trond Myklebustc1578b72013-08-12 16:58:42 -04005144 trace_nfs4_get_acl(inode, ret);
Trond Myklebust16b42892006-08-24 12:27:15 -04005145 if (ret >= 0)
5146 break;
5147 ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
5148 } while (exception.retry);
5149 return ret;
5150}
5151
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005152static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
5153{
5154 struct nfs_server *server = NFS_SERVER(inode);
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005155 int ret;
5156
5157 if (!nfs4_server_supports_acls(server))
5158 return -EOPNOTSUPP;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005159 ret = nfs_revalidate_inode(server, inode);
5160 if (ret < 0)
5161 return ret;
Aneesh Kumar K.V08a22b32010-12-01 10:42:16 +00005162 if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
5163 nfs_zap_acl_cache(inode);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005164 ret = nfs4_read_cached_acl(inode, buf, buflen);
5165 if (ret != -ENOENT)
Andy Adamsonbf118a32011-12-07 11:55:27 -05005166 /* -ENOENT is returned if there is no ACL or if there is an ACL
5167 * but no cached acl data, just the acl length */
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005168 return ret;
5169 return nfs4_get_acl_uncached(inode, buf, buflen);
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005170}
5171
Trond Myklebust16b42892006-08-24 12:27:15 -04005172static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005173{
5174 struct nfs_server *server = NFS_SERVER(inode);
5175 struct page *pages[NFS4ACL_MAXPAGES];
5176 struct nfs_setaclargs arg = {
5177 .fh = NFS_FH(inode),
5178 .acl_pages = pages,
5179 .acl_len = buflen,
5180 };
Benny Halevy73c403a2009-04-01 09:22:01 -04005181 struct nfs_setaclres res;
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005182 struct rpc_message msg = {
5183 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL],
5184 .rpc_argp = &arg,
Benny Halevy73c403a2009-04-01 09:22:01 -04005185 .rpc_resp = &res,
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005186 };
Trond Myklebust21f498c2012-08-24 10:59:25 -04005187 unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
Neil Hormane9e3d722011-03-04 19:26:03 -05005188 int ret, i;
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005189
5190 if (!nfs4_server_supports_acls(server))
5191 return -EOPNOTSUPP;
Trond Myklebust21f498c2012-08-24 10:59:25 -04005192 if (npages > ARRAY_SIZE(pages))
5193 return -ERANGE;
Andreas Gruenbacher8fbcf232015-11-03 18:25:34 +01005194 i = buf_to_pages_noslab(buf, buflen, arg.acl_pages);
Neil Hormane9e3d722011-03-04 19:26:03 -05005195 if (i < 0)
5196 return i;
Bryan Schumaker57ec14c2012-06-20 15:53:44 -04005197 nfs4_inode_return_delegation(inode);
Bryan Schumaker7c513052011-03-24 17:12:24 +00005198 ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Neil Hormane9e3d722011-03-04 19:26:03 -05005199
5200 /*
5201 * Free each page after tx, so the only ref left is
5202 * held by the network stack
5203 */
5204 for (; i > 0; i--)
5205 put_page(pages[i-1]);
5206
Aneesh Kumar K.V08a22b32010-12-01 10:42:16 +00005207 /*
5208 * Acl update can result in inode attribute update.
5209 * so mark the attribute cache invalid.
5210 */
5211 spin_lock(&inode->i_lock);
5212 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
5213 spin_unlock(&inode->i_lock);
Trond Myklebustf41f7412008-06-11 17:39:04 -04005214 nfs_access_zap_cache(inode);
5215 nfs_zap_acl_cache(inode);
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005216 return ret;
5217}
5218
Trond Myklebust16b42892006-08-24 12:27:15 -04005219static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
5220{
5221 struct nfs4_exception exception = { };
5222 int err;
5223 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04005224 err = __nfs4_proc_set_acl(inode, buf, buflen);
5225 trace_nfs4_set_acl(inode, err);
5226 err = nfs4_handle_exception(NFS_SERVER(inode), err,
Trond Myklebust16b42892006-08-24 12:27:15 -04005227 &exception);
5228 } while (exception.retry);
5229 return err;
5230}
5231
David Quigleyaa9c2662013-05-22 12:50:44 -04005232#ifdef CONFIG_NFS_V4_SECURITY_LABEL
5233static int _nfs4_get_security_label(struct inode *inode, void *buf,
5234 size_t buflen)
5235{
5236 struct nfs_server *server = NFS_SERVER(inode);
5237 struct nfs_fattr fattr;
5238 struct nfs4_label label = {0, 0, buflen, buf};
5239
5240 u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
Trond Myklebustfcb63a92013-11-01 12:42:25 -04005241 struct nfs4_getattr_arg arg = {
David Quigleyaa9c2662013-05-22 12:50:44 -04005242 .fh = NFS_FH(inode),
5243 .bitmask = bitmask,
5244 };
5245 struct nfs4_getattr_res res = {
5246 .fattr = &fattr,
5247 .label = &label,
5248 .server = server,
5249 };
5250 struct rpc_message msg = {
5251 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
Trond Myklebustfcb63a92013-11-01 12:42:25 -04005252 .rpc_argp = &arg,
David Quigleyaa9c2662013-05-22 12:50:44 -04005253 .rpc_resp = &res,
5254 };
5255 int ret;
5256
5257 nfs_fattr_init(&fattr);
5258
Trond Myklebustfcb63a92013-11-01 12:42:25 -04005259 ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 0);
David Quigleyaa9c2662013-05-22 12:50:44 -04005260 if (ret)
5261 return ret;
5262 if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))
5263 return -ENOENT;
5264 if (buflen < label.len)
5265 return -ERANGE;
5266 return 0;
5267}
5268
5269static int nfs4_get_security_label(struct inode *inode, void *buf,
5270 size_t buflen)
5271{
5272 struct nfs4_exception exception = { };
5273 int err;
5274
5275 if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
5276 return -EOPNOTSUPP;
5277
5278 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04005279 err = _nfs4_get_security_label(inode, buf, buflen);
5280 trace_nfs4_get_security_label(inode, err);
5281 err = nfs4_handle_exception(NFS_SERVER(inode), err,
David Quigleyaa9c2662013-05-22 12:50:44 -04005282 &exception);
5283 } while (exception.retry);
5284 return err;
5285}
5286
5287static int _nfs4_do_set_security_label(struct inode *inode,
5288 struct nfs4_label *ilabel,
5289 struct nfs_fattr *fattr,
5290 struct nfs4_label *olabel)
5291{
5292
5293 struct iattr sattr = {0};
5294 struct nfs_server *server = NFS_SERVER(inode);
5295 const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
Jeff Layton12207f62013-11-01 10:49:32 -04005296 struct nfs_setattrargs arg = {
Anna Schumakerd9b67e12017-01-11 15:04:25 -05005297 .fh = NFS_FH(inode),
5298 .iap = &sattr,
David Quigleyaa9c2662013-05-22 12:50:44 -04005299 .server = server,
5300 .bitmask = bitmask,
5301 .label = ilabel,
5302 };
5303 struct nfs_setattrres res = {
5304 .fattr = fattr,
5305 .label = olabel,
5306 .server = server,
5307 };
5308 struct rpc_message msg = {
Anna Schumakerd9b67e12017-01-11 15:04:25 -05005309 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
5310 .rpc_argp = &arg,
5311 .rpc_resp = &res,
David Quigleyaa9c2662013-05-22 12:50:44 -04005312 };
5313 int status;
5314
Jeff Layton12207f62013-11-01 10:49:32 -04005315 nfs4_stateid_copy(&arg.stateid, &zero_stateid);
David Quigleyaa9c2662013-05-22 12:50:44 -04005316
Jeff Layton12207f62013-11-01 10:49:32 -04005317 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
David Quigleyaa9c2662013-05-22 12:50:44 -04005318 if (status)
5319 dprintk("%s failed: %d\n", __func__, status);
5320
5321 return status;
5322}
5323
5324static int nfs4_do_set_security_label(struct inode *inode,
5325 struct nfs4_label *ilabel,
5326 struct nfs_fattr *fattr,
5327 struct nfs4_label *olabel)
5328{
5329 struct nfs4_exception exception = { };
5330 int err;
5331
5332 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04005333 err = _nfs4_do_set_security_label(inode, ilabel,
5334 fattr, olabel);
5335 trace_nfs4_set_security_label(inode, err);
5336 err = nfs4_handle_exception(NFS_SERVER(inode), err,
David Quigleyaa9c2662013-05-22 12:50:44 -04005337 &exception);
5338 } while (exception.retry);
5339 return err;
5340}
5341
5342static int
Al Viro59301222016-05-27 10:19:30 -04005343nfs4_set_security_label(struct inode *inode, const void *buf, size_t buflen)
David Quigleyaa9c2662013-05-22 12:50:44 -04005344{
5345 struct nfs4_label ilabel, *olabel = NULL;
5346 struct nfs_fattr fattr;
5347 struct rpc_cred *cred;
David Quigleyaa9c2662013-05-22 12:50:44 -04005348 int status;
5349
5350 if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
5351 return -EOPNOTSUPP;
5352
5353 nfs_fattr_init(&fattr);
5354
5355 ilabel.pi = 0;
5356 ilabel.lfs = 0;
5357 ilabel.label = (char *)buf;
5358 ilabel.len = buflen;
5359
5360 cred = rpc_lookup_cred();
5361 if (IS_ERR(cred))
5362 return PTR_ERR(cred);
5363
5364 olabel = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
5365 if (IS_ERR(olabel)) {
5366 status = -PTR_ERR(olabel);
5367 goto out;
5368 }
5369
5370 status = nfs4_do_set_security_label(inode, &ilabel, &fattr, olabel);
5371 if (status == 0)
5372 nfs_setsecurity(inode, &fattr, olabel);
5373
5374 nfs4_label_free(olabel);
5375out:
5376 put_rpccred(cred);
5377 return status;
5378}
5379#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
5380
5381
Chuck Leverf0920752012-05-21 22:45:41 -04005382static void nfs4_init_boot_verifier(const struct nfs_client *clp,
5383 nfs4_verifier *bootverf)
Chuck Levercd937102012-03-02 17:14:31 -05005384{
5385 __be32 verf[2];
5386
Chuck Lever2c820d92012-05-21 22:45:33 -04005387 if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
5388 /* An impossible timestamp guarantees this value
5389 * will never match a generated boot time. */
Deepa Dinamani2f86e092016-10-01 16:46:26 -07005390 verf[0] = cpu_to_be32(U32_MAX);
5391 verf[1] = cpu_to_be32(U32_MAX);
Chuck Lever2c820d92012-05-21 22:45:33 -04005392 } else {
Chuck Leverf0920752012-05-21 22:45:41 -04005393 struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
Deepa Dinamani2f86e092016-10-01 16:46:26 -07005394 u64 ns = ktime_to_ns(nn->boot_time);
5395
5396 verf[0] = cpu_to_be32(ns >> 32);
5397 verf[1] = cpu_to_be32(ns);
Chuck Lever2c820d92012-05-21 22:45:33 -04005398 }
Chuck Levercd937102012-03-02 17:14:31 -05005399 memcpy(bootverf->data, verf, sizeof(bootverf->data));
5400}
5401
Jeff Laytona3192682015-06-09 19:43:59 -04005402static int
5403nfs4_init_nonuniform_client_string(struct nfs_client *clp)
Chuck Levere984a552012-09-14 17:24:21 -04005404{
Jeff Laytona3192682015-06-09 19:43:59 -04005405 size_t len;
5406 char *str;
Chuck Levere984a552012-09-14 17:24:21 -04005407
Trond Myklebustceb3a162015-01-03 15:16:04 -05005408 if (clp->cl_owner_id != NULL)
Jeff Laytona3192682015-06-09 19:43:59 -04005409 return 0;
Kinglong Mee4a3e5772015-08-31 10:53:43 +08005410
Jeff Laytona3192682015-06-09 19:43:59 -04005411 rcu_read_lock();
Kinglong Mee4a703162015-08-31 10:53:33 +08005412 len = 14 + strlen(clp->cl_ipaddr) + 1 +
Jeff Laytona3192682015-06-09 19:43:59 -04005413 strlen(rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)) +
5414 1 +
5415 strlen(rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO)) +
5416 1;
5417 rcu_read_unlock();
5418
5419 if (len > NFS4_OPAQUE_LIMIT + 1)
5420 return -EINVAL;
5421
5422 /*
5423 * Since this string is allocated at mount time, and held until the
5424 * nfs_client is destroyed, we can use GFP_KERNEL here w/o worrying
5425 * about a memory-reclaim deadlock.
5426 */
5427 str = kmalloc(len, GFP_KERNEL);
5428 if (!str)
5429 return -ENOMEM;
Trond Myklebustceb3a162015-01-03 15:16:04 -05005430
Chuck Levere984a552012-09-14 17:24:21 -04005431 rcu_read_lock();
Trond Myklebustf2dd4362015-10-08 11:33:17 -04005432 scnprintf(str, len, "Linux NFSv4.0 %s/%s %s",
Jeff Laytona3192682015-06-09 19:43:59 -04005433 clp->cl_ipaddr,
5434 rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR),
5435 rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO));
Chuck Levere984a552012-09-14 17:24:21 -04005436 rcu_read_unlock();
Jeff Laytona3192682015-06-09 19:43:59 -04005437
Jeff Laytona3192682015-06-09 19:43:59 -04005438 clp->cl_owner_id = str;
5439 return 0;
Chuck Levere984a552012-09-14 17:24:21 -04005440}
5441
Jeff Layton873e3852015-06-09 19:44:00 -04005442static int
5443nfs4_init_uniquifier_client_string(struct nfs_client *clp)
Chuck Levere984a552012-09-14 17:24:21 -04005444{
Jeff Layton873e3852015-06-09 19:44:00 -04005445 size_t len;
5446 char *str;
5447
5448 len = 10 + 10 + 1 + 10 + 1 +
5449 strlen(nfs4_client_id_uniquifier) + 1 +
5450 strlen(clp->cl_rpcclient->cl_nodename) + 1;
5451
5452 if (len > NFS4_OPAQUE_LIMIT + 1)
5453 return -EINVAL;
5454
5455 /*
5456 * Since this string is allocated at mount time, and held until the
5457 * nfs_client is destroyed, we can use GFP_KERNEL here w/o worrying
5458 * about a memory-reclaim deadlock.
5459 */
5460 str = kmalloc(len, GFP_KERNEL);
5461 if (!str)
5462 return -ENOMEM;
5463
Trond Myklebustf2dd4362015-10-08 11:33:17 -04005464 scnprintf(str, len, "Linux NFSv%u.%u %s/%s",
Jeff Layton873e3852015-06-09 19:44:00 -04005465 clp->rpc_ops->version, clp->cl_minorversion,
5466 nfs4_client_id_uniquifier,
5467 clp->cl_rpcclient->cl_nodename);
Jeff Layton873e3852015-06-09 19:44:00 -04005468 clp->cl_owner_id = str;
5469 return 0;
5470}
5471
5472static int
5473nfs4_init_uniform_client_string(struct nfs_client *clp)
5474{
Jeff Layton873e3852015-06-09 19:44:00 -04005475 size_t len;
5476 char *str;
Trond Myklebustceb3a162015-01-03 15:16:04 -05005477
5478 if (clp->cl_owner_id != NULL)
Jeff Layton873e3852015-06-09 19:44:00 -04005479 return 0;
Chuck Lever6f2ea7f2012-09-14 17:24:41 -04005480
5481 if (nfs4_client_id_uniquifier[0] != '\0')
Jeff Layton873e3852015-06-09 19:44:00 -04005482 return nfs4_init_uniquifier_client_string(clp);
5483
5484 len = 10 + 10 + 1 + 10 + 1 +
5485 strlen(clp->cl_rpcclient->cl_nodename) + 1;
5486
5487 if (len > NFS4_OPAQUE_LIMIT + 1)
5488 return -EINVAL;
5489
5490 /*
5491 * Since this string is allocated at mount time, and held until the
5492 * nfs_client is destroyed, we can use GFP_KERNEL here w/o worrying
5493 * about a memory-reclaim deadlock.
5494 */
5495 str = kmalloc(len, GFP_KERNEL);
5496 if (!str)
5497 return -ENOMEM;
5498
Trond Myklebustf2dd4362015-10-08 11:33:17 -04005499 scnprintf(str, len, "Linux NFSv%u.%u %s",
Jeff Layton873e3852015-06-09 19:44:00 -04005500 clp->rpc_ops->version, clp->cl_minorversion,
5501 clp->cl_rpcclient->cl_nodename);
Jeff Layton873e3852015-06-09 19:44:00 -04005502 clp->cl_owner_id = str;
5503 return 0;
Chuck Levere984a552012-09-14 17:24:21 -04005504}
5505
Chuck Lever706cb8d2014-03-12 12:51:47 -04005506/*
5507 * nfs4_callback_up_net() starts only "tcp" and "tcp6" callback
5508 * services. Advertise one based on the address family of the
5509 * clientaddr.
5510 */
5511static unsigned int
5512nfs4_init_callback_netid(const struct nfs_client *clp, char *buf, size_t len)
5513{
5514 if (strchr(clp->cl_ipaddr, ':') != NULL)
5515 return scnprintf(buf, len, "tcp6");
5516 else
5517 return scnprintf(buf, len, "tcp");
5518}
5519
Jeff Laytonf11b2a12014-06-21 20:52:17 -04005520static void nfs4_setclientid_done(struct rpc_task *task, void *calldata)
5521{
5522 struct nfs4_setclientid *sc = calldata;
5523
5524 if (task->tk_status == 0)
5525 sc->sc_cred = get_rpccred(task->tk_rqstp->rq_cred);
5526}
5527
5528static const struct rpc_call_ops nfs4_setclientid_ops = {
5529 .rpc_call_done = nfs4_setclientid_done,
5530};
5531
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04005532/**
5533 * nfs4_proc_setclientid - Negotiate client ID
5534 * @clp: state data structure
5535 * @program: RPC program for NFSv4 callback service
5536 * @port: IP port number for NFS4 callback service
5537 * @cred: RPC credential to use for this call
5538 * @res: where to place the result
5539 *
5540 * Returns zero, a negative errno, or a negative NFS4ERR status code.
5541 */
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04005542int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
5543 unsigned short port, struct rpc_cred *cred,
5544 struct nfs4_setclientid_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545{
5546 nfs4_verifier sc_verifier;
5547 struct nfs4_setclientid setclientid = {
5548 .sc_verifier = &sc_verifier,
5549 .sc_prog = program,
Jeff Layton3a6bb732015-06-09 19:43:57 -04005550 .sc_clnt = clp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005551 };
5552 struct rpc_message msg = {
5553 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
5554 .rpc_argp = &setclientid,
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04005555 .rpc_resp = res,
Trond Myklebust286d7d62006-01-03 09:55:26 +01005556 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005557 };
Jeff Laytonf11b2a12014-06-21 20:52:17 -04005558 struct rpc_task *task;
5559 struct rpc_task_setup task_setup_data = {
5560 .rpc_client = clp->cl_rpcclient,
5561 .rpc_message = &msg,
5562 .callback_ops = &nfs4_setclientid_ops,
5563 .callback_data = &setclientid,
5564 .flags = RPC_TASK_TIMEOUT,
5565 };
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04005566 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005567
Chuck Leverde734832012-07-11 16:30:50 -04005568 /* nfs_client_id4 */
Chuck Leverf0920752012-05-21 22:45:41 -04005569 nfs4_init_boot_verifier(clp, &sc_verifier);
Jeff Layton873e3852015-06-09 19:44:00 -04005570
5571 if (test_bit(NFS_CS_MIGRATION, &clp->cl_flags))
5572 status = nfs4_init_uniform_client_string(clp);
5573 else
Jeff Laytona3192682015-06-09 19:43:59 -04005574 status = nfs4_init_nonuniform_client_string(clp);
Jeff Layton873e3852015-06-09 19:44:00 -04005575
5576 if (status)
5577 goto out;
Jeff Layton3a6bb732015-06-09 19:43:57 -04005578
Chuck Leverde734832012-07-11 16:30:50 -04005579 /* cb_client4 */
Chuck Lever706cb8d2014-03-12 12:51:47 -04005580 setclientid.sc_netid_len =
5581 nfs4_init_callback_netid(clp,
5582 setclientid.sc_netid,
5583 sizeof(setclientid.sc_netid));
Chuck Leverde734832012-07-11 16:30:50 -04005584 setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
Chuck Leverd4d3c502007-12-10 14:57:09 -05005585 sizeof(setclientid.sc_uaddr), "%s.%u.%u",
Linus Torvalds1da177e2005-04-16 15:20:36 -07005586 clp->cl_ipaddr, port >> 8, port & 255);
5587
Jeff Layton3a6bb732015-06-09 19:43:57 -04005588 dprintk("NFS call setclientid auth=%s, '%s'\n",
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04005589 clp->cl_rpcclient->cl_auth->au_ops->au_name,
Jeff Layton3a6bb732015-06-09 19:43:57 -04005590 clp->cl_owner_id);
Jeff Laytonf11b2a12014-06-21 20:52:17 -04005591 task = rpc_run_task(&task_setup_data);
5592 if (IS_ERR(task)) {
5593 status = PTR_ERR(task);
5594 goto out;
5595 }
5596 status = task->tk_status;
5597 if (setclientid.sc_cred) {
5598 clp->cl_acceptor = rpcauth_stringify_acceptor(setclientid.sc_cred);
5599 put_rpccred(setclientid.sc_cred);
5600 }
5601 rpc_put_task(task);
5602out:
Trond Myklebustc6d01c62013-08-09 11:51:26 -04005603 trace_nfs4_setclientid(clp, status);
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04005604 dprintk("NFS reply setclientid: %d\n", status);
5605 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005606}
5607
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04005608/**
5609 * nfs4_proc_setclientid_confirm - Confirm client ID
5610 * @clp: state data structure
5611 * @res: result of a previous SETCLIENTID
5612 * @cred: RPC credential to use for this call
5613 *
5614 * Returns zero, a negative errno, or a negative NFS4ERR status code.
5615 */
Trond Myklebustfd954ae2011-04-24 14:28:18 -04005616int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04005617 struct nfs4_setclientid_res *arg,
5618 struct rpc_cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005619{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005620 struct rpc_message msg = {
5621 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04005622 .rpc_argp = arg,
Trond Myklebust286d7d62006-01-03 09:55:26 +01005623 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005624 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005625 int status;
5626
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04005627 dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n",
5628 clp->cl_rpcclient->cl_auth->au_ops->au_name,
5629 clp->cl_clientid);
Trond Myklebust1bd714f2011-04-24 14:29:33 -04005630 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04005631 trace_nfs4_setclientid_confirm(clp, status);
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04005632 dprintk("NFS reply setclientid_confirm: %d\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005633 return status;
5634}
5635
Trond Myklebustfe650402006-01-03 09:55:18 +01005636struct nfs4_delegreturndata {
5637 struct nfs4_delegreturnargs args;
Trond Myklebustfa178f22006-01-03 09:55:38 +01005638 struct nfs4_delegreturnres res;
Trond Myklebustfe650402006-01-03 09:55:18 +01005639 struct nfs_fh fh;
5640 nfs4_stateid stateid;
Trond Myklebust26e976a2006-01-03 09:55:21 +01005641 unsigned long timestamp;
Trond Myklebust586f1c32016-11-15 15:03:33 -05005642 struct {
5643 struct nfs4_layoutreturn_args arg;
5644 struct nfs4_layoutreturn_res res;
Trond Myklebust4d796d72016-09-23 11:38:08 -04005645 struct nfs4_xdr_opaque_data ld_private;
Trond Myklebust586f1c32016-11-15 15:03:33 -05005646 u32 roc_barrier;
5647 bool roc;
5648 } lr;
Trond Myklebustfa178f22006-01-03 09:55:38 +01005649 struct nfs_fattr fattr;
Trond Myklebustfe650402006-01-03 09:55:18 +01005650 int rpc_status;
Peng Tao039b7562014-07-03 13:05:02 +08005651 struct inode *inode;
Trond Myklebustfe650402006-01-03 09:55:18 +01005652};
5653
Trond Myklebustfe650402006-01-03 09:55:18 +01005654static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
5655{
5656 struct nfs4_delegreturndata *data = calldata;
Andy Adamson938e1012009-04-01 09:22:28 -04005657
Trond Myklebust14516c32010-07-31 14:29:06 -04005658 if (!nfs4_sequence_done(task, &data->res.seq_res))
5659 return;
Andy Adamson938e1012009-04-01 09:22:28 -04005660
Trond Myklebustca8acf82013-08-13 10:36:56 -04005661 trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status);
Trond Myklebust586f1c32016-11-15 15:03:33 -05005662
5663 /* Handle Layoutreturn errors */
5664 if (data->args.lr_args && task->tk_status != 0) {
5665 switch(data->res.lr_ret) {
5666 default:
5667 data->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT;
5668 break;
5669 case 0:
5670 data->args.lr_args = NULL;
5671 data->res.lr_res = NULL;
5672 break;
5673 case -NFS4ERR_ADMIN_REVOKED:
5674 case -NFS4ERR_DELEG_REVOKED:
5675 case -NFS4ERR_EXPIRED:
5676 case -NFS4ERR_BAD_STATEID:
5677 case -NFS4ERR_OLD_STATEID:
5678 case -NFS4ERR_UNKNOWN_LAYOUTTYPE:
5679 case -NFS4ERR_WRONG_CRED:
5680 data->args.lr_args = NULL;
5681 data->res.lr_res = NULL;
5682 data->res.lr_ret = 0;
5683 rpc_restart_call_prepare(task);
5684 return;
5685 }
5686 }
5687
Ricardo Labiaga79708862009-12-07 09:23:21 -05005688 switch (task->tk_status) {
Ricardo Labiaga79708862009-12-07 09:23:21 -05005689 case 0:
Trond Myklebustfa178f22006-01-03 09:55:38 +01005690 renew_lease(data->res.server, data->timestamp);
Trond Myklebust23ea44c2016-11-10 16:06:28 -05005691 break;
Trond Myklebustc97cf602013-11-19 16:34:14 -05005692 case -NFS4ERR_ADMIN_REVOKED:
5693 case -NFS4ERR_DELEG_REVOKED:
Trond Myklebust26d36302016-09-22 13:39:05 -04005694 case -NFS4ERR_EXPIRED:
5695 nfs4_free_revoked_stateid(data->res.server,
5696 data->args.stateid,
5697 task->tk_msg.rpc_cred);
Trond Myklebustc97cf602013-11-19 16:34:14 -05005698 case -NFS4ERR_BAD_STATEID:
5699 case -NFS4ERR_OLD_STATEID:
5700 case -NFS4ERR_STALE_STATEID:
Trond Myklebustc97cf602013-11-19 16:34:14 -05005701 task->tk_status = 0;
5702 break;
Trond Myklebust8ac2b4222016-12-19 10:23:10 -05005703 case -NFS4ERR_ACCESS:
5704 if (data->args.bitmask) {
5705 data->args.bitmask = NULL;
5706 data->res.fattr = NULL;
5707 task->tk_status = 0;
5708 rpc_restart_call_prepare(task);
5709 return;
5710 }
Ricardo Labiaga79708862009-12-07 09:23:21 -05005711 default:
NeilBrown8478eaa2014-09-18 16:09:27 +10005712 if (nfs4_async_handle_error(task, data->res.server,
5713 NULL, NULL) == -EAGAIN) {
Trond Myklebustd00c5d42011-10-19 12:17:29 -07005714 rpc_restart_call_prepare(task);
Ricardo Labiaga79708862009-12-07 09:23:21 -05005715 return;
5716 }
5717 }
5718 data->rpc_status = task->tk_status;
Trond Myklebustfe650402006-01-03 09:55:18 +01005719}
5720
5721static void nfs4_delegreturn_release(void *calldata)
5722{
Peng Tao039b7562014-07-03 13:05:02 +08005723 struct nfs4_delegreturndata *data = calldata;
Trond Myklebustea7c38f2015-02-05 15:13:24 -05005724 struct inode *inode = data->inode;
Peng Tao039b7562014-07-03 13:05:02 +08005725
Trond Myklebustea7c38f2015-02-05 15:13:24 -05005726 if (inode) {
Trond Myklebust586f1c32016-11-15 15:03:33 -05005727 if (data->lr.roc)
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05005728 pnfs_roc_release(&data->lr.arg, &data->lr.res,
5729 data->res.lr_ret);
Trond Myklebust0bc2c9b2016-12-16 19:48:09 -05005730 nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
Trond Myklebustea7c38f2015-02-05 15:13:24 -05005731 nfs_iput_and_deactive(inode);
5732 }
Trond Myklebustfe650402006-01-03 09:55:18 +01005733 kfree(calldata);
5734}
5735
Andy Adamson938e1012009-04-01 09:22:28 -04005736static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
5737{
5738 struct nfs4_delegreturndata *d_data;
5739
5740 d_data = (struct nfs4_delegreturndata *)data;
5741
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05005742 if (!d_data->lr.roc && nfs4_wait_on_layoutreturn(d_data->inode, task))
Peng Tao500d7012015-09-22 11:35:22 +08005743 return;
5744
Anna Schumaker42e1cca2017-01-09 15:48:22 -05005745 nfs4_setup_sequence(d_data->res.server->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04005746 &d_data->args.seq_args,
5747 &d_data->res.seq_res,
5748 task);
Andy Adamson938e1012009-04-01 09:22:28 -04005749}
Andy Adamson938e1012009-04-01 09:22:28 -04005750
Jesper Juhlc8d149f2006-03-20 13:44:07 -05005751static const struct rpc_call_ops nfs4_delegreturn_ops = {
Andy Adamson938e1012009-04-01 09:22:28 -04005752 .rpc_call_prepare = nfs4_delegreturn_prepare,
Trond Myklebustfe650402006-01-03 09:55:18 +01005753 .rpc_call_done = nfs4_delegreturn_done,
5754 .rpc_release = nfs4_delegreturn_release,
5755};
5756
Trond Myklebuste6f81072008-01-24 18:14:34 -05005757static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync)
Trond Myklebustfe650402006-01-03 09:55:18 +01005758{
5759 struct nfs4_delegreturndata *data;
Trond Myklebustfa178f22006-01-03 09:55:38 +01005760 struct nfs_server *server = NFS_SERVER(inode);
Trond Myklebustfe650402006-01-03 09:55:18 +01005761 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04005762 struct rpc_message msg = {
5763 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN],
5764 .rpc_cred = cred,
5765 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04005766 struct rpc_task_setup task_setup_data = {
5767 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04005768 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04005769 .callback_ops = &nfs4_delegreturn_ops,
5770 .flags = RPC_TASK_ASYNC,
5771 };
Trond Myklebuste6f81072008-01-24 18:14:34 -05005772 int status = 0;
Trond Myklebustfe650402006-01-03 09:55:18 +01005773
Trond Myklebust8535b2b2010-05-13 12:51:01 -04005774 data = kzalloc(sizeof(*data), GFP_NOFS);
Trond Myklebustfe650402006-01-03 09:55:18 +01005775 if (data == NULL)
5776 return -ENOMEM;
Chuck Levera9c92d62013-08-09 12:48:18 -04005777 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
Andrew Elble99ade3c2015-12-02 09:39:51 -05005778
5779 nfs4_state_protect(server->nfs_client,
5780 NFS_SP4_MACH_CRED_CLEANUP,
5781 &task_setup_data.rpc_client, &msg);
5782
Trond Myklebustfe650402006-01-03 09:55:18 +01005783 data->args.fhandle = &data->fh;
5784 data->args.stateid = &data->stateid;
Trond Myklebust9e907fe2012-04-27 13:48:17 -04005785 data->args.bitmask = server->cache_consistency_bitmask;
Trond Myklebustfe650402006-01-03 09:55:18 +01005786 nfs_copy_fh(&data->fh, NFS_FH(inode));
Trond Myklebustf597c532012-03-04 18:13:56 -05005787 nfs4_stateid_copy(&data->stateid, stateid);
Trond Myklebustfa178f22006-01-03 09:55:38 +01005788 data->res.fattr = &data->fattr;
5789 data->res.server = server;
Trond Myklebust586f1c32016-11-15 15:03:33 -05005790 data->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT;
Trond Myklebust4d796d72016-09-23 11:38:08 -04005791 data->lr.arg.ld_private = &data->lr.ld_private;
Trond Myklebust5138fde2007-07-14 15:40:01 -04005792 nfs_fattr_init(data->res.fattr);
Trond Myklebust26e976a2006-01-03 09:55:21 +01005793 data->timestamp = jiffies;
Trond Myklebustfe650402006-01-03 09:55:18 +01005794 data->rpc_status = 0;
Trond Myklebust53e6fc82016-11-19 08:48:47 -05005795 data->lr.roc = pnfs_roc(inode, &data->lr.arg, &data->lr.res, cred);
Trond Myklebustea7c38f2015-02-05 15:13:24 -05005796 data->inode = nfs_igrab_and_active(inode);
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05005797 if (data->inode) {
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05005798 if (data->lr.roc) {
5799 data->args.lr_args = &data->lr.arg;
5800 data->res.lr_res = &data->lr.res;
5801 }
Trond Myklebust53e6fc82016-11-19 08:48:47 -05005802 } else if (data->lr.roc) {
5803 pnfs_roc_release(&data->lr.arg, &data->lr.res, 0);
5804 data->lr.roc = false;
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05005805 }
Trond Myklebustfe650402006-01-03 09:55:18 +01005806
Trond Myklebustc970aa82007-07-14 15:39:59 -04005807 task_setup_data.callback_data = data;
Trond Myklebust1174dd12010-12-21 10:52:24 -05005808 msg.rpc_argp = &data->args;
5809 msg.rpc_resp = &data->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04005810 task = rpc_run_task(&task_setup_data);
Trond Myklebust7a1218a2006-03-20 18:11:10 -05005811 if (IS_ERR(task))
Trond Myklebustfe650402006-01-03 09:55:18 +01005812 return PTR_ERR(task);
Trond Myklebuste6f81072008-01-24 18:14:34 -05005813 if (!issync)
5814 goto out;
Anna Schumaker820bf852017-01-11 15:01:43 -05005815 status = rpc_wait_for_completion_task(task);
Trond Myklebuste6f81072008-01-24 18:14:34 -05005816 if (status != 0)
5817 goto out;
5818 status = data->rpc_status;
Trond Myklebuste6f81072008-01-24 18:14:34 -05005819out:
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05005820 rpc_put_task(task);
Trond Myklebustfe650402006-01-03 09:55:18 +01005821 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822}
5823
Trond Myklebuste6f81072008-01-24 18:14:34 -05005824int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005825{
5826 struct nfs_server *server = NFS_SERVER(inode);
5827 struct nfs4_exception exception = { };
5828 int err;
5829 do {
Trond Myklebuste6f81072008-01-24 18:14:34 -05005830 err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
Olga Kornievskaia48c95792015-11-24 13:29:41 -05005831 trace_nfs4_delegreturn(inode, stateid, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005832 switch (err) {
5833 case -NFS4ERR_STALE_STATEID:
5834 case -NFS4ERR_EXPIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005835 case 0:
5836 return 0;
5837 }
5838 err = nfs4_handle_exception(server, err, &exception);
5839 } while (exception.retry);
5840 return err;
5841}
5842
Linus Torvalds1da177e2005-04-16 15:20:36 -07005843static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
5844{
5845 struct inode *inode = state->inode;
5846 struct nfs_server *server = NFS_SERVER(inode);
David Howells7539bba2006-08-22 20:06:09 -04005847 struct nfs_client *clp = server->nfs_client;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005848 struct nfs_lockt_args arg = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005849 .fh = NFS_FH(inode),
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005850 .fl = request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005851 };
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005852 struct nfs_lockt_res res = {
5853 .denied = request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005854 };
5855 struct rpc_message msg = {
5856 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT],
Anna Schumakerd9b67e12017-01-11 15:04:25 -05005857 .rpc_argp = &arg,
5858 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005859 .rpc_cred = state->owner->so_cred,
5860 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005861 struct nfs4_lock_state *lsp;
5862 int status;
5863
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005864 arg.lock_owner.clientid = clp->cl_clientid;
Trond Myklebust8d0a8a92005-06-22 17:16:32 +00005865 status = nfs4_set_lock_state(state, request);
5866 if (status != 0)
5867 goto out;
5868 lsp = request->fl_u.nfs4_fl.owner;
Trond Myklebust48c22eb2012-01-17 22:04:25 -05005869 arg.lock_owner.id = lsp->ls_seqid.owner_id;
Trond Myklebustd035c362010-12-21 10:45:27 -05005870 arg.lock_owner.s_dev = server->s_dev;
Bryan Schumaker7c513052011-03-24 17:12:24 +00005871 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005872 switch (status) {
5873 case 0:
5874 request->fl_type = F_UNLCK;
5875 break;
5876 case -NFS4ERR_DENIED:
5877 status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 }
J. Bruce Fields70cc6482007-02-22 18:48:53 -05005879 request->fl_ops->fl_release_private(request);
Trond Myklebusta6f951d2013-10-01 14:24:58 -04005880 request->fl_ops = NULL;
Trond Myklebust8d0a8a92005-06-22 17:16:32 +00005881out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 return status;
5883}
5884
5885static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
5886{
5887 struct nfs4_exception exception = { };
5888 int err;
5889
5890 do {
Trond Myklebustd1b748a2013-08-12 16:35:20 -04005891 err = _nfs4_proc_getlk(state, cmd, request);
5892 trace_nfs4_get_lock(request, state, cmd, err);
5893 err = nfs4_handle_exception(NFS_SERVER(state->inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005894 &exception);
5895 } while (exception.retry);
5896 return err;
5897}
5898
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005899struct nfs4_unlockdata {
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005900 struct nfs_locku_args arg;
5901 struct nfs_locku_res res;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005902 struct nfs4_lock_state *lsp;
5903 struct nfs_open_context *ctx;
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04005904 struct nfs_lock_context *l_ctx;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005905 struct file_lock fl;
Trond Myklebust516285eb2015-09-20 16:15:24 -04005906 struct nfs_server *server;
Trond Myklebust26e976a2006-01-03 09:55:21 +01005907 unsigned long timestamp;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005908};
5909
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005910static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
5911 struct nfs_open_context *ctx,
5912 struct nfs4_lock_state *lsp,
5913 struct nfs_seqid *seqid)
5914{
5915 struct nfs4_unlockdata *p;
5916 struct inode *inode = lsp->ls_state->inode;
5917
Trond Myklebust8535b2b2010-05-13 12:51:01 -04005918 p = kzalloc(sizeof(*p), GFP_NOFS);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005919 if (p == NULL)
5920 return NULL;
5921 p->arg.fh = NFS_FH(inode);
5922 p->arg.fl = &p->fl;
5923 p->arg.seqid = seqid;
Trond Myklebustc1d51932008-04-07 13:20:54 -04005924 p->res.seqid = seqid;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005925 p->lsp = lsp;
Elena Reshetova194bc1f2017-10-20 12:53:36 +03005926 refcount_inc(&lsp->ls_count);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005927 /* Ensure we don't close file until we're done freeing locks! */
5928 p->ctx = get_nfs_open_context(ctx);
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04005929 p->l_ctx = nfs_get_lock_context(ctx);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005930 memcpy(&p->fl, fl, sizeof(p->fl));
5931 p->server = NFS_SERVER(inode);
5932 return p;
5933}
5934
Trond Myklebust06f814a2006-01-03 09:55:07 +01005935static void nfs4_locku_release_calldata(void *data)
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005936{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005937 struct nfs4_unlockdata *calldata = data;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005938 nfs_free_seqid(calldata->arg.seqid);
Trond Myklebust06f814a2006-01-03 09:55:07 +01005939 nfs4_put_lock_state(calldata->lsp);
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04005940 nfs_put_lock_context(calldata->l_ctx);
Trond Myklebust06f814a2006-01-03 09:55:07 +01005941 put_nfs_open_context(calldata->ctx);
5942 kfree(calldata);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005943}
5944
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005945static void nfs4_locku_done(struct rpc_task *task, void *data)
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005946{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005947 struct nfs4_unlockdata *calldata = data;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005948
Trond Myklebust14516c32010-07-31 14:29:06 -04005949 if (!nfs4_sequence_done(task, &calldata->res.seq_res))
5950 return;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005951 switch (task->tk_status) {
5952 case 0:
Trond Myklebust26e976a2006-01-03 09:55:21 +01005953 renew_lease(calldata->server, calldata->timestamp);
Jeff Layton75575dd2016-09-17 18:17:32 -04005954 locks_lock_inode_wait(calldata->lsp->ls_state->inode, &calldata->fl);
Trond Myklebustc69899a2015-01-24 16:03:52 -05005955 if (nfs4_update_lock_stateid(calldata->lsp,
5956 &calldata->res.stateid))
5957 break;
Trond Myklebust26d36302016-09-22 13:39:05 -04005958 case -NFS4ERR_ADMIN_REVOKED:
5959 case -NFS4ERR_EXPIRED:
5960 nfs4_free_revoked_stateid(calldata->server,
5961 &calldata->arg.stateid,
5962 task->tk_msg.rpc_cred);
Trond Myklebust9e33bed2008-12-23 15:21:46 -05005963 case -NFS4ERR_BAD_STATEID:
5964 case -NFS4ERR_OLD_STATEID:
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005965 case -NFS4ERR_STALE_STATEID:
Trond Myklebust425c1d42015-01-24 14:57:53 -05005966 if (!nfs4_stateid_match(&calldata->arg.stateid,
5967 &calldata->lsp->ls_stateid))
5968 rpc_restart_call_prepare(task);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005969 break;
5970 default:
NeilBrown8478eaa2014-09-18 16:09:27 +10005971 if (nfs4_async_handle_error(task, calldata->server,
5972 NULL, NULL) == -EAGAIN)
Trond Myklebustd00c5d42011-10-19 12:17:29 -07005973 rpc_restart_call_prepare(task);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005974 }
Trond Myklebust2b1bc302012-10-29 18:53:23 -04005975 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005976}
5977
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01005978static void nfs4_locku_prepare(struct rpc_task *task, void *data)
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005979{
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01005980 struct nfs4_unlockdata *calldata = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005981
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04005982 if (test_bit(NFS_CONTEXT_UNLOCK, &calldata->l_ctx->open_context->flags) &&
5983 nfs_async_iocounter_wait(task, calldata->l_ctx))
5984 return;
5985
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005986 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05005987 goto out_wait;
Trond Myklebust425c1d42015-01-24 14:57:53 -05005988 nfs4_stateid_copy(&calldata->arg.stateid, &calldata->lsp->ls_stateid);
Trond Myklebust795a88c2012-09-10 13:26:49 -04005989 if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005990 /* Note: exit _without_ running nfs4_locku_done */
Trond Myklebustc8da19b2013-02-11 19:01:21 -05005991 goto out_no_action;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005992 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01005993 calldata->timestamp = jiffies;
Anna Schumaker42e1cca2017-01-09 15:48:22 -05005994 if (nfs4_setup_sequence(calldata->server->nfs_client,
Andy Adamsona8936932009-04-01 09:22:23 -04005995 &calldata->arg.seq_args,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04005996 &calldata->res.seq_res,
5997 task) != 0)
5998 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05005999 return;
6000out_no_action:
6001 task->tk_action = NULL;
6002out_wait:
6003 nfs4_sequence_done(task, &calldata->res.seq_res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006004}
6005
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006006static const struct rpc_call_ops nfs4_locku_ops = {
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01006007 .rpc_call_prepare = nfs4_locku_prepare,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006008 .rpc_call_done = nfs4_locku_done,
Trond Myklebust06f814a2006-01-03 09:55:07 +01006009 .rpc_release = nfs4_locku_release_calldata,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006010};
6011
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006012static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
6013 struct nfs_open_context *ctx,
6014 struct nfs4_lock_state *lsp,
6015 struct nfs_seqid *seqid)
6016{
6017 struct nfs4_unlockdata *data;
Trond Myklebust5138fde2007-07-14 15:40:01 -04006018 struct rpc_message msg = {
6019 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU],
6020 .rpc_cred = ctx->cred,
6021 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04006022 struct rpc_task_setup task_setup_data = {
6023 .rpc_client = NFS_CLIENT(lsp->ls_state->inode),
Trond Myklebust5138fde2007-07-14 15:40:01 -04006024 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006025 .callback_ops = &nfs4_locku_ops,
Trond Myklebust101070c2008-02-19 20:04:23 -05006026 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006027 .flags = RPC_TASK_ASYNC,
6028 };
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006029
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04006030 nfs4_state_protect(NFS_SERVER(lsp->ls_state->inode)->nfs_client,
6031 NFS_SP4_MACH_CRED_CLEANUP, &task_setup_data.rpc_client, &msg);
6032
Frank Filz137d6ac2007-07-09 15:32:29 -07006033 /* Ensure this is an unlock - when canceling a lock, the
6034 * canceled lock is passed in, and it won't be an unlock.
6035 */
6036 fl->fl_type = F_UNLCK;
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04006037 if (fl->fl_flags & FL_CLOSE)
6038 set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);
Frank Filz137d6ac2007-07-09 15:32:29 -07006039
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006040 data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
6041 if (data == NULL) {
6042 nfs_free_seqid(seqid);
6043 return ERR_PTR(-ENOMEM);
6044 }
6045
Chuck Levera9c92d62013-08-09 12:48:18 -04006046 nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
Trond Myklebust1174dd12010-12-21 10:52:24 -05006047 msg.rpc_argp = &data->arg;
6048 msg.rpc_resp = &data->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04006049 task_setup_data.callback_data = data;
6050 return rpc_run_task(&task_setup_data);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006051}
6052
Linus Torvalds1da177e2005-04-16 15:20:36 -07006053static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
6054{
Trond Myklebust65b62a22013-02-07 10:54:07 -05006055 struct inode *inode = state->inode;
6056 struct nfs4_state_owner *sp = state->owner;
6057 struct nfs_inode *nfsi = NFS_I(inode);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006058 struct nfs_seqid *seqid;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006059 struct nfs4_lock_state *lsp;
Trond Myklebust06f814a2006-01-03 09:55:07 +01006060 struct rpc_task *task;
Trond Myklebustb4019c02015-01-24 14:19:19 -05006061 struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
Trond Myklebust06f814a2006-01-03 09:55:07 +01006062 int status = 0;
Trond Myklebust536ff0f2008-04-04 15:08:02 -04006063 unsigned char fl_flags = request->fl_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006064
Trond Myklebust9b073572006-06-29 16:38:34 -04006065 status = nfs4_set_lock_state(state, request);
6066 /* Unlock _before_ we do the RPC call */
6067 request->fl_flags |= FL_EXISTS;
Trond Myklebust65b62a22013-02-07 10:54:07 -05006068 /* Exclude nfs_delegation_claim_locks() */
6069 mutex_lock(&sp->so_delegreturn_mutex);
6070 /* Exclude nfs4_reclaim_open_stateid() - note nesting! */
Trond Myklebust19e03c52008-12-23 15:21:44 -05006071 down_read(&nfsi->rwsem);
Jeff Layton75575dd2016-09-17 18:17:32 -04006072 if (locks_lock_inode_wait(inode, request) == -ENOENT) {
Trond Myklebust19e03c52008-12-23 15:21:44 -05006073 up_read(&nfsi->rwsem);
Trond Myklebust65b62a22013-02-07 10:54:07 -05006074 mutex_unlock(&sp->so_delegreturn_mutex);
Trond Myklebust9b073572006-06-29 16:38:34 -04006075 goto out;
Trond Myklebust19e03c52008-12-23 15:21:44 -05006076 }
6077 up_read(&nfsi->rwsem);
Trond Myklebust65b62a22013-02-07 10:54:07 -05006078 mutex_unlock(&sp->so_delegreturn_mutex);
Trond Myklebust9b073572006-06-29 16:38:34 -04006079 if (status != 0)
6080 goto out;
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05006081 /* Is this a delegated lock? */
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006082 lsp = request->fl_u.nfs4_fl.owner;
Trond Myklebustc5a2a152013-04-30 12:43:42 -04006083 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) == 0)
6084 goto out;
Trond Myklebustb4019c02015-01-24 14:19:19 -05006085 alloc_seqid = NFS_SERVER(inode)->nfs_client->cl_mvops->alloc_seqid;
6086 seqid = alloc_seqid(&lsp->ls_seqid, GFP_KERNEL);
Trond Myklebust9b073572006-06-29 16:38:34 -04006087 status = -ENOMEM;
Trond Myklebustbadc76d2015-01-23 18:48:00 -05006088 if (IS_ERR(seqid))
Trond Myklebust9b073572006-06-29 16:38:34 -04006089 goto out;
Trond Myklebustcd3758e2007-08-10 17:44:32 -04006090 task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006091 status = PTR_ERR(task);
6092 if (IS_ERR(task))
Trond Myklebust9b073572006-06-29 16:38:34 -04006093 goto out;
Anna Schumaker820bf852017-01-11 15:01:43 -05006094 status = rpc_wait_for_completion_task(task);
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05006095 rpc_put_task(task);
Trond Myklebust9b073572006-06-29 16:38:34 -04006096out:
Trond Myklebust536ff0f2008-04-04 15:08:02 -04006097 request->fl_flags = fl_flags;
Trond Myklebustd1b748a2013-08-12 16:35:20 -04006098 trace_nfs4_unlock(request, state, F_SETLK, status);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006099 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006100}
6101
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006102struct nfs4_lockdata {
6103 struct nfs_lock_args arg;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006104 struct nfs_lock_res res;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006105 struct nfs4_lock_state *lsp;
6106 struct nfs_open_context *ctx;
6107 struct file_lock fl;
Trond Myklebust26e976a2006-01-03 09:55:21 +01006108 unsigned long timestamp;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006109 int rpc_status;
6110 int cancelled;
Andy Adamson66179ef2009-04-01 09:22:22 -04006111 struct nfs_server *server;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006112};
6113
6114static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006115 struct nfs_open_context *ctx, struct nfs4_lock_state *lsp,
6116 gfp_t gfp_mask)
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006117{
6118 struct nfs4_lockdata *p;
6119 struct inode *inode = lsp->ls_state->inode;
6120 struct nfs_server *server = NFS_SERVER(inode);
Trond Myklebustb4019c02015-01-24 14:19:19 -05006121 struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006122
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006123 p = kzalloc(sizeof(*p), gfp_mask);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006124 if (p == NULL)
6125 return NULL;
6126
6127 p->arg.fh = NFS_FH(inode);
6128 p->arg.fl = &p->fl;
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006129 p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask);
Trond Myklebustbadc76d2015-01-23 18:48:00 -05006130 if (IS_ERR(p->arg.open_seqid))
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006131 goto out_free;
Trond Myklebustb4019c02015-01-24 14:19:19 -05006132 alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
6133 p->arg.lock_seqid = alloc_seqid(&lsp->ls_seqid, gfp_mask);
Trond Myklebustbadc76d2015-01-23 18:48:00 -05006134 if (IS_ERR(p->arg.lock_seqid))
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006135 goto out_free_seqid;
David Howells7539bba2006-08-22 20:06:09 -04006136 p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
Trond Myklebust48c22eb2012-01-17 22:04:25 -05006137 p->arg.lock_owner.id = lsp->ls_seqid.owner_id;
Trond Myklebustd035c362010-12-21 10:45:27 -05006138 p->arg.lock_owner.s_dev = server->s_dev;
Trond Myklebustc1d51932008-04-07 13:20:54 -04006139 p->res.lock_seqid = p->arg.lock_seqid;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006140 p->lsp = lsp;
Andy Adamson66179ef2009-04-01 09:22:22 -04006141 p->server = server;
Elena Reshetova194bc1f2017-10-20 12:53:36 +03006142 refcount_inc(&lsp->ls_count);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006143 p->ctx = get_nfs_open_context(ctx);
6144 memcpy(&p->fl, fl, sizeof(p->fl));
6145 return p;
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006146out_free_seqid:
6147 nfs_free_seqid(p->arg.open_seqid);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006148out_free:
6149 kfree(p);
6150 return NULL;
6151}
6152
6153static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
6154{
6155 struct nfs4_lockdata *data = calldata;
6156 struct nfs4_state *state = data->lsp->ls_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006157
Harvey Harrison3110ff82008-05-02 13:42:44 -07006158 dprintk("%s: begin!\n", __func__);
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006159 if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05006160 goto out_wait;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006161 /* Do we need to do an open_to_lock_owner? */
Trond Myklebust6b447532015-01-24 18:38:15 -05006162 if (!test_bit(NFS_LOCK_INITIALIZED, &data->lsp->ls_flags)) {
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006163 if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
Trond Myklebust2240a9e2012-10-29 18:37:40 -04006164 goto out_release_lock_seqid;
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006165 }
Trond Myklebust425c1d42015-01-24 14:57:53 -05006166 nfs4_stateid_copy(&data->arg.open_stateid,
6167 &state->open_stateid);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006168 data->arg.new_lock_owner = 1;
Trond Myklebustc1d51932008-04-07 13:20:54 -04006169 data->res.open_seqid = data->arg.open_seqid;
Trond Myklebust425c1d42015-01-24 14:57:53 -05006170 } else {
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006171 data->arg.new_lock_owner = 0;
Trond Myklebust425c1d42015-01-24 14:57:53 -05006172 nfs4_stateid_copy(&data->arg.lock_stateid,
6173 &data->lsp->ls_stateid);
6174 }
Trond Myklebust5d422302013-03-14 16:57:48 -04006175 if (!nfs4_valid_open_stateid(state)) {
6176 data->rpc_status = -EBADF;
6177 task->tk_action = NULL;
6178 goto out_release_open_seqid;
6179 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01006180 data->timestamp = jiffies;
Anna Schumaker42e1cca2017-01-09 15:48:22 -05006181 if (nfs4_setup_sequence(data->server->nfs_client,
Trond Myklebust035168ab2010-06-16 09:52:26 -04006182 &data->arg.seq_args,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04006183 &data->res.seq_res,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04006184 task) == 0)
Andy Adamson66179ef2009-04-01 09:22:22 -04006185 return;
Trond Myklebust5d422302013-03-14 16:57:48 -04006186out_release_open_seqid:
Trond Myklebust2240a9e2012-10-29 18:37:40 -04006187 nfs_release_seqid(data->arg.open_seqid);
6188out_release_lock_seqid:
6189 nfs_release_seqid(data->arg.lock_seqid);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05006190out_wait:
6191 nfs4_sequence_done(task, &data->res.seq_res);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006192 dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08006193}
6194
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006195static void nfs4_lock_done(struct rpc_task *task, void *calldata)
6196{
6197 struct nfs4_lockdata *data = calldata;
Trond Myklebust39071e62015-01-24 15:07:56 -05006198 struct nfs4_lock_state *lsp = data->lsp;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006199
Harvey Harrison3110ff82008-05-02 13:42:44 -07006200 dprintk("%s: begin!\n", __func__);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006201
Trond Myklebust14516c32010-07-31 14:29:06 -04006202 if (!nfs4_sequence_done(task, &data->res.seq_res))
6203 return;
Andy Adamson66179ef2009-04-01 09:22:22 -04006204
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006205 data->rpc_status = task->tk_status;
Trond Myklebust425c1d42015-01-24 14:57:53 -05006206 switch (task->tk_status) {
6207 case 0:
David Howells2b0143b2015-03-17 22:25:59 +00006208 renew_lease(NFS_SERVER(d_inode(data->ctx->dentry)),
Trond Myklebust39071e62015-01-24 15:07:56 -05006209 data->timestamp);
Trond Myklebustc69899a2015-01-24 16:03:52 -05006210 if (data->arg.new_lock) {
6211 data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
Jeff Layton75575dd2016-09-17 18:17:32 -04006212 if (locks_lock_inode_wait(lsp->ls_state->inode, &data->fl) < 0) {
Trond Myklebustc69899a2015-01-24 16:03:52 -05006213 rpc_restart_call_prepare(task);
6214 break;
6215 }
6216 }
Trond Myklebust39071e62015-01-24 15:07:56 -05006217 if (data->arg.new_lock_owner != 0) {
6218 nfs_confirm_seqid(&lsp->ls_seqid, 0);
6219 nfs4_stateid_copy(&lsp->ls_stateid, &data->res.stateid);
6220 set_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
6221 } else if (!nfs4_update_lock_stateid(lsp, &data->res.stateid))
6222 rpc_restart_call_prepare(task);
Trond Myklebust425c1d42015-01-24 14:57:53 -05006223 break;
6224 case -NFS4ERR_BAD_STATEID:
6225 case -NFS4ERR_OLD_STATEID:
6226 case -NFS4ERR_STALE_STATEID:
6227 case -NFS4ERR_EXPIRED:
6228 if (data->arg.new_lock_owner != 0) {
6229 if (!nfs4_stateid_match(&data->arg.open_stateid,
6230 &lsp->ls_state->open_stateid))
6231 rpc_restart_call_prepare(task);
6232 } else if (!nfs4_stateid_match(&data->arg.lock_stateid,
6233 &lsp->ls_stateid))
6234 rpc_restart_call_prepare(task);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006235 }
Harvey Harrison3110ff82008-05-02 13:42:44 -07006236 dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006237}
6238
6239static void nfs4_lock_release(void *calldata)
6240{
6241 struct nfs4_lockdata *data = calldata;
6242
Harvey Harrison3110ff82008-05-02 13:42:44 -07006243 dprintk("%s: begin!\n", __func__);
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006244 nfs_free_seqid(data->arg.open_seqid);
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04006245 if (data->cancelled) {
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006246 struct rpc_task *task;
6247 task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
6248 data->arg.lock_seqid);
6249 if (!IS_ERR(task))
Trond Myklebustbf294b42011-02-21 11:05:41 -08006250 rpc_put_task_async(task);
Harvey Harrison3110ff82008-05-02 13:42:44 -07006251 dprintk("%s: cancelling lock!\n", __func__);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006252 } else
6253 nfs_free_seqid(data->arg.lock_seqid);
6254 nfs4_put_lock_state(data->lsp);
6255 put_nfs_open_context(data->ctx);
6256 kfree(data);
Harvey Harrison3110ff82008-05-02 13:42:44 -07006257 dprintk("%s: done!\n", __func__);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006258}
6259
6260static const struct rpc_call_ops nfs4_lock_ops = {
6261 .rpc_call_prepare = nfs4_lock_prepare,
6262 .rpc_call_done = nfs4_lock_done,
6263 .rpc_release = nfs4_lock_release,
6264};
6265
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006266static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
6267{
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006268 switch (error) {
6269 case -NFS4ERR_ADMIN_REVOKED:
Trond Myklebustd7f3e4b2016-09-22 13:39:09 -04006270 case -NFS4ERR_EXPIRED:
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006271 case -NFS4ERR_BAD_STATEID:
Trond Myklebustecac7992011-03-09 16:00:56 -05006272 lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006273 if (new_lock_owner != 0 ||
Trond Myklebust795a88c2012-09-10 13:26:49 -04006274 test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0)
Trond Myklebustecac7992011-03-09 16:00:56 -05006275 nfs4_schedule_stateid_recovery(server, lsp->ls_state);
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -05006276 break;
6277 case -NFS4ERR_STALE_STATEID:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -05006278 lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
Trond Myklebustecac7992011-03-09 16:00:56 -05006279 nfs4_schedule_lease_recovery(server->nfs_client);
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006280 };
6281}
6282
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08006283static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type)
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006284{
6285 struct nfs4_lockdata *data;
6286 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04006287 struct rpc_message msg = {
6288 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK],
6289 .rpc_cred = state->owner->so_cred,
6290 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04006291 struct rpc_task_setup task_setup_data = {
6292 .rpc_client = NFS_CLIENT(state->inode),
Trond Myklebust5138fde2007-07-14 15:40:01 -04006293 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006294 .callback_ops = &nfs4_lock_ops,
Trond Myklebust101070c2008-02-19 20:04:23 -05006295 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006296 .flags = RPC_TASK_ASYNC,
6297 };
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006298 int ret;
6299
Harvey Harrison3110ff82008-05-02 13:42:44 -07006300 dprintk("%s: begin!\n", __func__);
Trond Myklebustcd3758e2007-08-10 17:44:32 -04006301 data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006302 fl->fl_u.nfs4_fl.owner,
6303 recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006304 if (data == NULL)
6305 return -ENOMEM;
6306 if (IS_SETLKW(cmd))
6307 data->arg.block = 1;
Chuck Levera9c92d62013-08-09 12:48:18 -04006308 nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
Trond Myklebust1174dd12010-12-21 10:52:24 -05006309 msg.rpc_argp = &data->arg;
6310 msg.rpc_resp = &data->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04006311 task_setup_data.callback_data = data;
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006312 if (recovery_type > NFS_LOCK_NEW) {
6313 if (recovery_type == NFS_LOCK_RECLAIM)
6314 data->arg.reclaim = NFS_LOCK_RECLAIM;
6315 nfs4_set_sequence_privileged(&data->arg.seq_args);
Trond Myklebustc69899a2015-01-24 16:03:52 -05006316 } else
6317 data->arg.new_lock = 1;
Trond Myklebustc970aa82007-07-14 15:39:59 -04006318 task = rpc_run_task(&task_setup_data);
Trond Myklebust7a1218a2006-03-20 18:11:10 -05006319 if (IS_ERR(task))
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006320 return PTR_ERR(task);
Anna Schumaker820bf852017-01-11 15:01:43 -05006321 ret = rpc_wait_for_completion_task(task);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006322 if (ret == 0) {
6323 ret = data->rpc_status;
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006324 if (ret)
6325 nfs4_handle_setlk_error(data->server, data->lsp,
6326 data->arg.new_lock_owner, ret);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006327 } else
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04006328 data->cancelled = true;
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05006329 rpc_put_task(task);
Harvey Harrison3110ff82008-05-02 13:42:44 -07006330 dprintk("%s: done, ret = %d!\n", __func__, ret);
Olga Kornievskaia48c95792015-11-24 13:29:41 -05006331 trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006332 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006333}
6334
6335static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
6336{
Trond Myklebust202b50d2005-06-22 17:16:29 +00006337 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust05ffe242012-04-18 12:20:10 -04006338 struct nfs4_exception exception = {
6339 .inode = state->inode,
6340 };
Trond Myklebust202b50d2005-06-22 17:16:29 +00006341 int err;
6342
6343 do {
Trond Myklebust42a2d132006-06-29 16:38:36 -04006344 /* Cache the lock if possible... */
6345 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
6346 return 0;
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08006347 err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
Trond Myklebust168667c2010-10-19 19:47:49 -04006348 if (err != -NFS4ERR_DELAY)
Trond Myklebust202b50d2005-06-22 17:16:29 +00006349 break;
6350 nfs4_handle_exception(server, err, &exception);
6351 } while (exception.retry);
6352 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006353}
6354
6355static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request)
6356{
Trond Myklebust202b50d2005-06-22 17:16:29 +00006357 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust05ffe242012-04-18 12:20:10 -04006358 struct nfs4_exception exception = {
6359 .inode = state->inode,
6360 };
Trond Myklebust202b50d2005-06-22 17:16:29 +00006361 int err;
6362
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05006363 err = nfs4_set_lock_state(state, request);
6364 if (err != 0)
6365 return err;
Trond Myklebustf6de7a32013-09-04 10:08:54 -04006366 if (!recover_lost_locks) {
NeilBrownef1820f2013-09-04 17:04:49 +10006367 set_bit(NFS_LOCK_LOST, &request->fl_u.nfs4_fl.owner->ls_flags);
6368 return 0;
6369 }
Trond Myklebust202b50d2005-06-22 17:16:29 +00006370 do {
Trond Myklebust42a2d132006-06-29 16:38:36 -04006371 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
6372 return 0;
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08006373 err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05006374 switch (err) {
6375 default:
6376 goto out;
6377 case -NFS4ERR_GRACE:
6378 case -NFS4ERR_DELAY:
6379 nfs4_handle_exception(server, err, &exception);
6380 err = 0;
6381 }
Trond Myklebust202b50d2005-06-22 17:16:29 +00006382 } while (exception.retry);
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05006383out:
Trond Myklebust202b50d2005-06-22 17:16:29 +00006384 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006385}
6386
Bryan Schumakerf062eb62011-06-02 14:59:10 -04006387#if defined(CONFIG_NFS_V4_1)
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05006388static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
6389{
Trond Myklebustc5896fc2016-09-22 13:39:03 -04006390 struct nfs4_lock_state *lsp;
6391 int status;
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05006392
Trond Myklebustc5896fc2016-09-22 13:39:03 -04006393 status = nfs4_set_lock_state(state, request);
6394 if (status != 0)
6395 return status;
6396 lsp = request->fl_u.nfs4_fl.owner;
6397 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) ||
6398 test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
6399 return 0;
Anna Schumaker81b68de2017-01-11 16:41:34 -05006400 return nfs4_lock_expired(state, request);
Bryan Schumakerf062eb62011-06-02 14:59:10 -04006401}
6402#endif
6403
Linus Torvalds1da177e2005-04-16 15:20:36 -07006404static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
6405{
Trond Myklebust19e03c52008-12-23 15:21:44 -05006406 struct nfs_inode *nfsi = NFS_I(state->inode);
Chuck Lever11476e92016-04-11 16:20:22 -04006407 struct nfs4_state_owner *sp = state->owner;
Trond Myklebust01c3b862006-06-29 16:38:39 -04006408 unsigned char fl_flags = request->fl_flags;
Jeff Layton1ea67db2016-09-17 18:17:37 -04006409 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006410
Trond Myklebust01c3b862006-06-29 16:38:39 -04006411 request->fl_flags |= FL_ACCESS;
Jeff Layton75575dd2016-09-17 18:17:32 -04006412 status = locks_lock_inode_wait(state->inode, request);
Trond Myklebust01c3b862006-06-29 16:38:39 -04006413 if (status < 0)
6414 goto out;
Chuck Lever11476e92016-04-11 16:20:22 -04006415 mutex_lock(&sp->so_delegreturn_mutex);
Trond Myklebust19e03c52008-12-23 15:21:44 -05006416 down_read(&nfsi->rwsem);
Trond Myklebust01c3b862006-06-29 16:38:39 -04006417 if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
Trond Myklebust01c3b862006-06-29 16:38:39 -04006418 /* Yes: cache locks! */
Trond Myklebust01c3b862006-06-29 16:38:39 -04006419 /* ...but avoid races with delegation recall... */
Trond Myklebust19e03c52008-12-23 15:21:44 -05006420 request->fl_flags = fl_flags & ~FL_SLEEP;
Jeff Layton75575dd2016-09-17 18:17:32 -04006421 status = locks_lock_inode_wait(state->inode, request);
Trond Myklebustc69899a2015-01-24 16:03:52 -05006422 up_read(&nfsi->rwsem);
Chuck Lever11476e92016-04-11 16:20:22 -04006423 mutex_unlock(&sp->so_delegreturn_mutex);
Trond Myklebustc69899a2015-01-24 16:03:52 -05006424 goto out;
Trond Myklebust01c3b862006-06-29 16:38:39 -04006425 }
Trond Myklebust9a99af42013-02-04 20:17:49 -05006426 up_read(&nfsi->rwsem);
Chuck Lever11476e92016-04-11 16:20:22 -04006427 mutex_unlock(&sp->so_delegreturn_mutex);
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08006428 status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
Trond Myklebust01c3b862006-06-29 16:38:39 -04006429out:
6430 request->fl_flags = fl_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006431 return status;
6432}
6433
6434static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
6435{
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -05006436 struct nfs4_exception exception = {
6437 .state = state,
Trond Myklebust05ffe242012-04-18 12:20:10 -04006438 .inode = state->inode,
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -05006439 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006440 int err;
6441
6442 do {
Trond Myklebust965b5d62009-06-17 13:22:59 -07006443 err = _nfs4_proc_setlk(state, cmd, request);
6444 if (err == -NFS4ERR_DENIED)
6445 err = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006446 err = nfs4_handle_exception(NFS_SERVER(state->inode),
Trond Myklebust965b5d62009-06-17 13:22:59 -07006447 err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006448 } while (exception.retry);
6449 return err;
6450}
6451
Jeff Laytond2f3a7f2016-09-17 18:17:38 -04006452#define NFS4_LOCK_MINTIMEOUT (1 * HZ)
6453#define NFS4_LOCK_MAXTIMEOUT (30 * HZ)
6454
6455static int
Jeff Laytona1d617d82016-09-17 18:17:39 -04006456nfs4_retry_setlk_simple(struct nfs4_state *state, int cmd,
6457 struct file_lock *request)
Jeff Laytond2f3a7f2016-09-17 18:17:38 -04006458{
6459 int status = -ERESTARTSYS;
6460 unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
6461
6462 while(!signalled()) {
6463 status = nfs4_proc_setlk(state, cmd, request);
6464 if ((status != -EAGAIN) || IS_SETLK(cmd))
6465 break;
6466 freezable_schedule_timeout_interruptible(timeout);
6467 timeout *= 2;
6468 timeout = min_t(unsigned long, NFS4_LOCK_MAXTIMEOUT, timeout);
6469 status = -ERESTARTSYS;
6470 }
6471 return status;
6472}
6473
Jeff Laytona1d617d82016-09-17 18:17:39 -04006474#ifdef CONFIG_NFS_V4_1
6475struct nfs4_lock_waiter {
6476 struct task_struct *task;
6477 struct inode *inode;
6478 struct nfs_lowner *owner;
6479 bool notified;
6480};
6481
6482static int
Ingo Molnarac6424b2017-06-20 12:06:13 +02006483nfs4_wake_lock_waiter(wait_queue_entry_t *wait, unsigned int mode, int flags, void *key)
Jeff Laytona1d617d82016-09-17 18:17:39 -04006484{
6485 int ret;
6486 struct cb_notify_lock_args *cbnl = key;
6487 struct nfs4_lock_waiter *waiter = wait->private;
6488 struct nfs_lowner *lowner = &cbnl->cbnl_owner,
6489 *wowner = waiter->owner;
6490
6491 /* Only wake if the callback was for the same owner */
6492 if (lowner->clientid != wowner->clientid ||
6493 lowner->id != wowner->id ||
6494 lowner->s_dev != wowner->s_dev)
6495 return 0;
6496
6497 /* Make sure it's for the right inode */
6498 if (nfs_compare_fh(NFS_FH(waiter->inode), &cbnl->cbnl_fh))
6499 return 0;
6500
6501 waiter->notified = true;
6502
6503 /* override "private" so we can use default_wake_function */
6504 wait->private = waiter->task;
6505 ret = autoremove_wake_function(wait, mode, flags, key);
6506 wait->private = waiter;
6507 return ret;
6508}
6509
6510static int
6511nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
6512{
6513 int status = -ERESTARTSYS;
6514 unsigned long flags;
6515 struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner;
6516 struct nfs_server *server = NFS_SERVER(state->inode);
6517 struct nfs_client *clp = server->nfs_client;
6518 wait_queue_head_t *q = &clp->cl_lock_waitq;
6519 struct nfs_lowner owner = { .clientid = clp->cl_clientid,
6520 .id = lsp->ls_seqid.owner_id,
6521 .s_dev = server->s_dev };
6522 struct nfs4_lock_waiter waiter = { .task = current,
6523 .inode = state->inode,
6524 .owner = &owner,
6525 .notified = false };
Ingo Molnarac6424b2017-06-20 12:06:13 +02006526 wait_queue_entry_t wait;
Jeff Laytona1d617d82016-09-17 18:17:39 -04006527
6528 /* Don't bother with waitqueue if we don't expect a callback */
6529 if (!test_bit(NFS_STATE_MAY_NOTIFY_LOCK, &state->flags))
6530 return nfs4_retry_setlk_simple(state, cmd, request);
6531
6532 init_wait(&wait);
6533 wait.private = &waiter;
6534 wait.func = nfs4_wake_lock_waiter;
6535 add_wait_queue(q, &wait);
6536
6537 while(!signalled()) {
6538 status = nfs4_proc_setlk(state, cmd, request);
6539 if ((status != -EAGAIN) || IS_SETLK(cmd))
6540 break;
6541
6542 status = -ERESTARTSYS;
6543 spin_lock_irqsave(&q->lock, flags);
6544 if (waiter.notified) {
6545 spin_unlock_irqrestore(&q->lock, flags);
6546 continue;
6547 }
6548 set_current_state(TASK_INTERRUPTIBLE);
6549 spin_unlock_irqrestore(&q->lock, flags);
6550
Benjamin Coddingtonb7dbcc02017-07-28 12:33:54 -04006551 freezable_schedule_timeout(NFS4_LOCK_MAXTIMEOUT);
Jeff Laytona1d617d82016-09-17 18:17:39 -04006552 }
6553
6554 finish_wait(q, &wait);
6555 return status;
6556}
6557#else /* !CONFIG_NFS_V4_1 */
6558static inline int
6559nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
6560{
6561 return nfs4_retry_setlk_simple(state, cmd, request);
6562}
6563#endif
6564
Linus Torvalds1da177e2005-04-16 15:20:36 -07006565static int
6566nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
6567{
6568 struct nfs_open_context *ctx;
6569 struct nfs4_state *state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006570 int status;
6571
6572 /* verify open state */
Trond Myklebustcd3758e2007-08-10 17:44:32 -04006573 ctx = nfs_file_open_context(filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006574 state = ctx->state;
6575
Trond Myklebustd9531262009-07-21 19:22:38 -04006576 if (IS_GETLK(cmd)) {
6577 if (state != NULL)
6578 return nfs4_proc_getlk(state, F_GETLK, request);
6579 return 0;
6580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006581
6582 if (!(IS_SETLK(cmd) || IS_SETLKW(cmd)))
6583 return -EINVAL;
6584
Trond Myklebustd9531262009-07-21 19:22:38 -04006585 if (request->fl_type == F_UNLCK) {
6586 if (state != NULL)
6587 return nfs4_proc_unlck(state, cmd, request);
6588 return 0;
6589 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07006590
Trond Myklebustd9531262009-07-21 19:22:38 -04006591 if (state == NULL)
6592 return -ENOLCK;
Jeff Layton1ea67db2016-09-17 18:17:37 -04006593
6594 if ((request->fl_flags & FL_POSIX) &&
6595 !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags))
6596 return -ENOLCK;
6597
Jeff Layton1ea67db2016-09-17 18:17:37 -04006598 status = nfs4_set_lock_state(state, request);
6599 if (status != 0)
6600 return status;
6601
Jeff Laytond2f3a7f2016-09-17 18:17:38 -04006602 return nfs4_retry_setlk(state, cmd, request);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006603}
6604
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04006605int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid)
Trond Myklebust888e6942005-11-04 15:38:11 -05006606{
6607 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust888e6942005-11-04 15:38:11 -05006608 int err;
6609
6610 err = nfs4_set_lock_state(state, fl);
6611 if (err != 0)
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04006612 return err;
Trond Myklebust4a706fa2013-04-01 14:47:22 -04006613 err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04006614 return nfs4_handle_delegation_recall_error(server, state, stateid, err);
Trond Myklebust888e6942005-11-04 15:38:11 -05006615}
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00006616
Trond Myklebustcf470c32012-03-07 13:49:12 -05006617struct nfs_release_lockowner_data {
6618 struct nfs4_lock_state *lsp;
Trond Myklebust5ae67c42012-03-19 16:17:18 -04006619 struct nfs_server *server;
Trond Myklebustcf470c32012-03-07 13:49:12 -05006620 struct nfs_release_lockowner_args args;
Trond Myklebustb7e63a12014-02-26 11:19:14 -08006621 struct nfs_release_lockowner_res res;
Chuck Lever60ea6812013-10-17 14:13:47 -04006622 unsigned long timestamp;
Trond Myklebustcf470c32012-03-07 13:49:12 -05006623};
6624
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04006625static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata)
6626{
6627 struct nfs_release_lockowner_data *data = calldata;
Kinglong Mee5b53dc82014-08-04 16:18:16 +08006628 struct nfs_server *server = data->server;
Anna Schumaker7981c8a2017-01-10 11:39:53 -05006629 nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
6630 &data->res.seq_res, task);
Kinglong Mee5b53dc82014-08-04 16:18:16 +08006631 data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
Chuck Lever60ea6812013-10-17 14:13:47 -04006632 data->timestamp = jiffies;
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04006633}
6634
6635static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
6636{
6637 struct nfs_release_lockowner_data *data = calldata;
Chuck Lever60ea6812013-10-17 14:13:47 -04006638 struct nfs_server *server = data->server;
6639
Trond Myklebustb7e63a12014-02-26 11:19:14 -08006640 nfs40_sequence_done(task, &data->res.seq_res);
Chuck Lever60ea6812013-10-17 14:13:47 -04006641
6642 switch (task->tk_status) {
6643 case 0:
6644 renew_lease(server, data->timestamp);
6645 break;
6646 case -NFS4ERR_STALE_CLIENTID:
6647 case -NFS4ERR_EXPIRED:
Kinglong Mee5b53dc82014-08-04 16:18:16 +08006648 nfs4_schedule_lease_recovery(server->nfs_client);
6649 break;
Chuck Lever60ea6812013-10-17 14:13:47 -04006650 case -NFS4ERR_LEASE_MOVED:
6651 case -NFS4ERR_DELAY:
NeilBrown8478eaa2014-09-18 16:09:27 +10006652 if (nfs4_async_handle_error(task, server,
6653 NULL, NULL) == -EAGAIN)
Chuck Lever60ea6812013-10-17 14:13:47 -04006654 rpc_restart_call_prepare(task);
6655 }
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04006656}
6657
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04006658static void nfs4_release_lockowner_release(void *calldata)
6659{
Trond Myklebustcf470c32012-03-07 13:49:12 -05006660 struct nfs_release_lockowner_data *data = calldata;
Trond Myklebust5ae67c42012-03-19 16:17:18 -04006661 nfs4_free_lock_state(data->server, data->lsp);
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04006662 kfree(calldata);
6663}
6664
Trond Myklebust17280172012-03-11 13:11:00 -04006665static const struct rpc_call_ops nfs4_release_lockowner_ops = {
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04006666 .rpc_call_prepare = nfs4_release_lockowner_prepare,
6667 .rpc_call_done = nfs4_release_lockowner_done,
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04006668 .rpc_release = nfs4_release_lockowner_release,
6669};
6670
Jeff Laytonf1cdae82014-05-01 06:28:47 -04006671static void
6672nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04006673{
Trond Myklebustcf470c32012-03-07 13:49:12 -05006674 struct nfs_release_lockowner_data *data;
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04006675 struct rpc_message msg = {
6676 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
6677 };
6678
6679 if (server->nfs_client->cl_mvops->minor_version != 0)
Jeff Laytonf1cdae82014-05-01 06:28:47 -04006680 return;
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04006681
Trond Myklebustcf470c32012-03-07 13:49:12 -05006682 data = kmalloc(sizeof(*data), GFP_NOFS);
6683 if (!data)
Jeff Laytonf1cdae82014-05-01 06:28:47 -04006684 return;
Trond Myklebustcf470c32012-03-07 13:49:12 -05006685 data->lsp = lsp;
Trond Myklebust5ae67c42012-03-19 16:17:18 -04006686 data->server = server;
Trond Myklebustcf470c32012-03-07 13:49:12 -05006687 data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
6688 data->args.lock_owner.id = lsp->ls_seqid.owner_id;
6689 data->args.lock_owner.s_dev = server->s_dev;
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04006690
Trond Myklebustcf470c32012-03-07 13:49:12 -05006691 msg.rpc_argp = &data->args;
Trond Myklebustb7e63a12014-02-26 11:19:14 -08006692 msg.rpc_resp = &data->res;
6693 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
Trond Myklebustcf470c32012-03-07 13:49:12 -05006694 rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04006695}
6696
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00006697#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
6698
Andreas Gruenbacherd9a82a02015-10-04 19:18:51 +02006699static int nfs4_xattr_set_nfs4_acl(const struct xattr_handler *handler,
Al Viro59301222016-05-27 10:19:30 -04006700 struct dentry *unused, struct inode *inode,
6701 const char *key, const void *buf,
6702 size_t buflen, int flags)
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00006703{
Al Viro59301222016-05-27 10:19:30 -04006704 return nfs4_proc_set_acl(inode, buf, buflen);
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00006705}
6706
Andreas Gruenbacherd9a82a02015-10-04 19:18:51 +02006707static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler,
Al Virob2968212016-04-10 20:48:24 -04006708 struct dentry *unused, struct inode *inode,
6709 const char *key, void *buf, size_t buflen)
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00006710{
Al Virob2968212016-04-10 20:48:24 -04006711 return nfs4_proc_get_acl(inode, buf, buflen);
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00006712}
6713
Andreas Gruenbacher764a5c62015-12-02 14:44:43 +01006714static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry)
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00006715{
Andreas Gruenbacher764a5c62015-12-02 14:44:43 +01006716 return nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry)));
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00006717}
6718
David Quigleyc9bccef2013-05-22 12:50:45 -04006719#ifdef CONFIG_NFS_V4_SECURITY_LABEL
David Quigleyc9bccef2013-05-22 12:50:45 -04006720
Andreas Gruenbacherd9a82a02015-10-04 19:18:51 +02006721static int nfs4_xattr_set_nfs4_label(const struct xattr_handler *handler,
Al Viro59301222016-05-27 10:19:30 -04006722 struct dentry *unused, struct inode *inode,
6723 const char *key, const void *buf,
6724 size_t buflen, int flags)
David Quigleyc9bccef2013-05-22 12:50:45 -04006725{
6726 if (security_ismaclabel(key))
Al Viro59301222016-05-27 10:19:30 -04006727 return nfs4_set_security_label(inode, buf, buflen);
David Quigleyc9bccef2013-05-22 12:50:45 -04006728
6729 return -EOPNOTSUPP;
6730}
6731
Andreas Gruenbacherd9a82a02015-10-04 19:18:51 +02006732static int nfs4_xattr_get_nfs4_label(const struct xattr_handler *handler,
Al Virob2968212016-04-10 20:48:24 -04006733 struct dentry *unused, struct inode *inode,
6734 const char *key, void *buf, size_t buflen)
David Quigleyc9bccef2013-05-22 12:50:45 -04006735{
6736 if (security_ismaclabel(key))
Al Virob2968212016-04-10 20:48:24 -04006737 return nfs4_get_security_label(inode, buf, buflen);
David Quigleyc9bccef2013-05-22 12:50:45 -04006738 return -EOPNOTSUPP;
6739}
6740
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01006741static ssize_t
6742nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
David Quigleyc9bccef2013-05-22 12:50:45 -04006743{
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01006744 int len = 0;
David Quigleyc9bccef2013-05-22 12:50:45 -04006745
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01006746 if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
6747 len = security_inode_listsecurity(inode, list, list_len);
6748 if (list_len && len > list_len)
6749 return -ERANGE;
David Quigleyc9bccef2013-05-22 12:50:45 -04006750 }
6751 return len;
6752}
6753
6754static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
6755 .prefix = XATTR_SECURITY_PREFIX,
David Quigleyc9bccef2013-05-22 12:50:45 -04006756 .get = nfs4_xattr_get_nfs4_label,
6757 .set = nfs4_xattr_set_nfs4_label,
6758};
David Quigleyc9bccef2013-05-22 12:50:45 -04006759
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01006760#else
6761
6762static ssize_t
6763nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
6764{
6765 return 0;
6766}
6767
6768#endif
David Quigleyc9bccef2013-05-22 12:50:45 -04006769
Andy Adamson533eb462011-06-13 18:25:56 -04006770/*
6771 * nfs_fhget will use either the mounted_on_fileid or the fileid
6772 */
Trond Myklebust69aaaae2009-03-11 14:10:28 -04006773static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
6774{
Andy Adamson533eb462011-06-13 18:25:56 -04006775 if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) ||
6776 (fattr->valid & NFS_ATTR_FATTR_FILEID)) &&
6777 (fattr->valid & NFS_ATTR_FATTR_FSID) &&
Chuck Lever81934dd2012-03-01 17:01:57 -05006778 (fattr->valid & NFS_ATTR_FATTR_V4_LOCATIONS)))
Trond Myklebust69aaaae2009-03-11 14:10:28 -04006779 return;
6780
6781 fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
Chuck Lever81934dd2012-03-01 17:01:57 -05006782 NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_V4_REFERRAL;
Trond Myklebust69aaaae2009-03-11 14:10:28 -04006783 fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
6784 fattr->nlink = 2;
6785}
6786
Bryan Schumakerf05d1472012-04-27 13:27:41 -04006787static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
6788 const struct qstr *name,
6789 struct nfs4_fs_locations *fs_locations,
6790 struct page *page)
Trond Myklebust683b57b2006-06-09 09:34:22 -04006791{
6792 struct nfs_server *server = NFS_SERVER(dir);
David Quigleya09df2c2013-05-22 12:50:41 -04006793 u32 bitmask[3] = {
Manoj Naik361e6242006-06-09 09:34:24 -04006794 [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
Trond Myklebust683b57b2006-06-09 09:34:22 -04006795 };
6796 struct nfs4_fs_locations_arg args = {
6797 .dir_fh = NFS_FH(dir),
Trond Myklebustc228fd32007-01-13 02:28:11 -05006798 .name = name,
Trond Myklebust683b57b2006-06-09 09:34:22 -04006799 .page = page,
6800 .bitmask = bitmask,
6801 };
Benny Halevy22958462009-04-01 09:22:02 -04006802 struct nfs4_fs_locations_res res = {
6803 .fs_locations = fs_locations,
6804 };
Trond Myklebust683b57b2006-06-09 09:34:22 -04006805 struct rpc_message msg = {
6806 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
6807 .rpc_argp = &args,
Benny Halevy22958462009-04-01 09:22:02 -04006808 .rpc_resp = &res,
Trond Myklebust683b57b2006-06-09 09:34:22 -04006809 };
6810 int status;
6811
Harvey Harrison3110ff82008-05-02 13:42:44 -07006812 dprintk("%s: start\n", __func__);
Andy Adamson533eb462011-06-13 18:25:56 -04006813
6814 /* Ask for the fileid of the absent filesystem if mounted_on_fileid
6815 * is not supported */
6816 if (NFS_SERVER(dir)->attr_bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
6817 bitmask[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
6818 else
6819 bitmask[0] |= FATTR4_WORD0_FILEID;
6820
Trond Myklebustc228fd32007-01-13 02:28:11 -05006821 nfs_fattr_init(&fs_locations->fattr);
Trond Myklebust683b57b2006-06-09 09:34:22 -04006822 fs_locations->server = server;
Manoj Naik830b8e32006-06-09 09:34:25 -04006823 fs_locations->nlocations = 0;
Bryan Schumakerf05d1472012-04-27 13:27:41 -04006824 status = nfs4_call_sync(client, server, &msg, &args.seq_args, &res.seq_res, 0);
Harvey Harrison3110ff82008-05-02 13:42:44 -07006825 dprintk("%s: returned status = %d\n", __func__, status);
Trond Myklebust683b57b2006-06-09 09:34:22 -04006826 return status;
6827}
6828
Bryan Schumakerf05d1472012-04-27 13:27:41 -04006829int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
6830 const struct qstr *name,
6831 struct nfs4_fs_locations *fs_locations,
6832 struct page *page)
Bryan Schumakerdb0a9592012-04-27 13:27:39 -04006833{
6834 struct nfs4_exception exception = { };
6835 int err;
6836 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04006837 err = _nfs4_proc_fs_locations(client, dir, name,
6838 fs_locations, page);
6839 trace_nfs4_get_fs_locations(dir, name, err);
6840 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Bryan Schumakerdb0a9592012-04-27 13:27:39 -04006841 &exception);
6842 } while (exception.retry);
6843 return err;
6844}
6845
Chuck Leverb03d7352013-10-17 14:12:50 -04006846/*
6847 * This operation also signals the server that this client is
6848 * performing migration recovery. The server can stop returning
6849 * NFS4ERR_LEASE_MOVED to this client. A RENEW operation is
6850 * appended to this compound to identify the client ID which is
6851 * performing recovery.
6852 */
6853static int _nfs40_proc_get_locations(struct inode *inode,
6854 struct nfs4_fs_locations *locations,
6855 struct page *page, struct rpc_cred *cred)
6856{
6857 struct nfs_server *server = NFS_SERVER(inode);
6858 struct rpc_clnt *clnt = server->client;
6859 u32 bitmask[2] = {
6860 [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
6861 };
6862 struct nfs4_fs_locations_arg args = {
6863 .clientid = server->nfs_client->cl_clientid,
6864 .fh = NFS_FH(inode),
6865 .page = page,
6866 .bitmask = bitmask,
6867 .migration = 1, /* skip LOOKUP */
6868 .renew = 1, /* append RENEW */
6869 };
6870 struct nfs4_fs_locations_res res = {
6871 .fs_locations = locations,
6872 .migration = 1,
6873 .renew = 1,
6874 };
6875 struct rpc_message msg = {
6876 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
6877 .rpc_argp = &args,
6878 .rpc_resp = &res,
6879 .rpc_cred = cred,
6880 };
6881 unsigned long now = jiffies;
6882 int status;
6883
6884 nfs_fattr_init(&locations->fattr);
6885 locations->server = server;
6886 locations->nlocations = 0;
6887
6888 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
6889 nfs4_set_sequence_privileged(&args.seq_args);
6890 status = nfs4_call_sync_sequence(clnt, server, &msg,
6891 &args.seq_args, &res.seq_res);
6892 if (status)
6893 return status;
6894
6895 renew_lease(server, now);
6896 return 0;
6897}
6898
6899#ifdef CONFIG_NFS_V4_1
6900
6901/*
6902 * This operation also signals the server that this client is
6903 * performing migration recovery. The server can stop asserting
6904 * SEQ4_STATUS_LEASE_MOVED for this client. The client ID
6905 * performing this operation is identified in the SEQUENCE
6906 * operation in this compound.
6907 *
6908 * When the client supports GETATTR(fs_locations_info), it can
6909 * be plumbed in here.
6910 */
6911static int _nfs41_proc_get_locations(struct inode *inode,
6912 struct nfs4_fs_locations *locations,
6913 struct page *page, struct rpc_cred *cred)
6914{
6915 struct nfs_server *server = NFS_SERVER(inode);
6916 struct rpc_clnt *clnt = server->client;
6917 u32 bitmask[2] = {
6918 [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
6919 };
6920 struct nfs4_fs_locations_arg args = {
6921 .fh = NFS_FH(inode),
6922 .page = page,
6923 .bitmask = bitmask,
6924 .migration = 1, /* skip LOOKUP */
6925 };
6926 struct nfs4_fs_locations_res res = {
6927 .fs_locations = locations,
6928 .migration = 1,
6929 };
6930 struct rpc_message msg = {
6931 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
6932 .rpc_argp = &args,
6933 .rpc_resp = &res,
6934 .rpc_cred = cred,
6935 };
6936 int status;
6937
6938 nfs_fattr_init(&locations->fattr);
6939 locations->server = server;
6940 locations->nlocations = 0;
6941
6942 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
6943 nfs4_set_sequence_privileged(&args.seq_args);
6944 status = nfs4_call_sync_sequence(clnt, server, &msg,
6945 &args.seq_args, &res.seq_res);
6946 if (status == NFS4_OK &&
6947 res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED)
6948 status = -NFS4ERR_LEASE_MOVED;
6949 return status;
6950}
6951
6952#endif /* CONFIG_NFS_V4_1 */
6953
6954/**
6955 * nfs4_proc_get_locations - discover locations for a migrated FSID
6956 * @inode: inode on FSID that is migrating
6957 * @locations: result of query
6958 * @page: buffer
6959 * @cred: credential to use for this operation
6960 *
6961 * Returns NFS4_OK on success, a negative NFS4ERR status code if the
6962 * operation failed, or a negative errno if a local error occurred.
6963 *
6964 * On success, "locations" is filled in, but if the server has
6965 * no locations information, NFS_ATTR_FATTR_V4_LOCATIONS is not
6966 * asserted.
6967 *
6968 * -NFS4ERR_LEASE_MOVED is returned if the server still has leases
6969 * from this client that require migration recovery.
6970 */
6971int nfs4_proc_get_locations(struct inode *inode,
6972 struct nfs4_fs_locations *locations,
6973 struct page *page, struct rpc_cred *cred)
6974{
6975 struct nfs_server *server = NFS_SERVER(inode);
6976 struct nfs_client *clp = server->nfs_client;
6977 const struct nfs4_mig_recovery_ops *ops =
6978 clp->cl_mvops->mig_recovery_ops;
6979 struct nfs4_exception exception = { };
6980 int status;
6981
6982 dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
6983 (unsigned long long)server->fsid.major,
6984 (unsigned long long)server->fsid.minor,
6985 clp->cl_hostname);
6986 nfs_display_fhandle(NFS_FH(inode), __func__);
6987
6988 do {
6989 status = ops->get_locations(inode, locations, page, cred);
6990 if (status != -NFS4ERR_DELAY)
6991 break;
6992 nfs4_handle_exception(server, status, &exception);
6993 } while (exception.retry);
6994 return status;
6995}
6996
Chuck Lever44c99932013-10-17 14:13:30 -04006997/*
6998 * This operation also signals the server that this client is
6999 * performing "lease moved" recovery. The server can stop
7000 * returning NFS4ERR_LEASE_MOVED to this client. A RENEW operation
7001 * is appended to this compound to identify the client ID which is
7002 * performing recovery.
7003 */
7004static int _nfs40_proc_fsid_present(struct inode *inode, struct rpc_cred *cred)
7005{
7006 struct nfs_server *server = NFS_SERVER(inode);
7007 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
7008 struct rpc_clnt *clnt = server->client;
7009 struct nfs4_fsid_present_arg args = {
7010 .fh = NFS_FH(inode),
7011 .clientid = clp->cl_clientid,
7012 .renew = 1, /* append RENEW */
7013 };
7014 struct nfs4_fsid_present_res res = {
7015 .renew = 1,
7016 };
7017 struct rpc_message msg = {
7018 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSID_PRESENT],
7019 .rpc_argp = &args,
7020 .rpc_resp = &res,
7021 .rpc_cred = cred,
7022 };
7023 unsigned long now = jiffies;
7024 int status;
7025
7026 res.fh = nfs_alloc_fhandle();
7027 if (res.fh == NULL)
7028 return -ENOMEM;
7029
7030 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
7031 nfs4_set_sequence_privileged(&args.seq_args);
7032 status = nfs4_call_sync_sequence(clnt, server, &msg,
7033 &args.seq_args, &res.seq_res);
7034 nfs_free_fhandle(res.fh);
7035 if (status)
7036 return status;
7037
7038 do_renew_lease(clp, now);
7039 return 0;
7040}
7041
7042#ifdef CONFIG_NFS_V4_1
7043
7044/*
7045 * This operation also signals the server that this client is
7046 * performing "lease moved" recovery. The server can stop asserting
7047 * SEQ4_STATUS_LEASE_MOVED for this client. The client ID performing
7048 * this operation is identified in the SEQUENCE operation in this
7049 * compound.
7050 */
7051static int _nfs41_proc_fsid_present(struct inode *inode, struct rpc_cred *cred)
7052{
7053 struct nfs_server *server = NFS_SERVER(inode);
7054 struct rpc_clnt *clnt = server->client;
7055 struct nfs4_fsid_present_arg args = {
7056 .fh = NFS_FH(inode),
7057 };
7058 struct nfs4_fsid_present_res res = {
7059 };
7060 struct rpc_message msg = {
7061 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSID_PRESENT],
7062 .rpc_argp = &args,
7063 .rpc_resp = &res,
7064 .rpc_cred = cred,
7065 };
7066 int status;
7067
7068 res.fh = nfs_alloc_fhandle();
7069 if (res.fh == NULL)
7070 return -ENOMEM;
7071
7072 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
7073 nfs4_set_sequence_privileged(&args.seq_args);
7074 status = nfs4_call_sync_sequence(clnt, server, &msg,
7075 &args.seq_args, &res.seq_res);
7076 nfs_free_fhandle(res.fh);
7077 if (status == NFS4_OK &&
7078 res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED)
7079 status = -NFS4ERR_LEASE_MOVED;
7080 return status;
7081}
7082
7083#endif /* CONFIG_NFS_V4_1 */
7084
7085/**
7086 * nfs4_proc_fsid_present - Is this FSID present or absent on server?
7087 * @inode: inode on FSID to check
7088 * @cred: credential to use for this operation
7089 *
7090 * Server indicates whether the FSID is present, moved, or not
7091 * recognized. This operation is necessary to clear a LEASE_MOVED
7092 * condition for this client ID.
7093 *
7094 * Returns NFS4_OK if the FSID is present on this server,
7095 * -NFS4ERR_MOVED if the FSID is no longer present, a negative
7096 * NFS4ERR code if some error occurred on the server, or a
7097 * negative errno if a local failure occurred.
7098 */
7099int nfs4_proc_fsid_present(struct inode *inode, struct rpc_cred *cred)
7100{
7101 struct nfs_server *server = NFS_SERVER(inode);
7102 struct nfs_client *clp = server->nfs_client;
7103 const struct nfs4_mig_recovery_ops *ops =
7104 clp->cl_mvops->mig_recovery_ops;
7105 struct nfs4_exception exception = { };
7106 int status;
7107
7108 dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
7109 (unsigned long long)server->fsid.major,
7110 (unsigned long long)server->fsid.minor,
7111 clp->cl_hostname);
7112 nfs_display_fhandle(NFS_FH(inode), __func__);
7113
7114 do {
7115 status = ops->fsid_present(inode, cred);
7116 if (status != -NFS4ERR_DELAY)
7117 break;
7118 nfs4_handle_exception(server, status, &exception);
7119 } while (exception.retry);
7120 return status;
7121}
7122
Andy Adamson5ec16a82013-08-08 10:57:55 -04007123/**
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007124 * If 'use_integrity' is true and the state managment nfs_client
7125 * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient
7126 * and the machine credential as per RFC3530bis and RFC5661 Security
7127 * Considerations sections. Otherwise, just use the user cred with the
7128 * filesystem's rpc_client.
Andy Adamson5ec16a82013-08-08 10:57:55 -04007129 */
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007130static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors, bool use_integrity)
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007131{
7132 int status;
7133 struct nfs4_secinfo_arg args = {
7134 .dir_fh = NFS_FH(dir),
7135 .name = name,
7136 };
7137 struct nfs4_secinfo_res res = {
7138 .flavors = flavors,
7139 };
7140 struct rpc_message msg = {
7141 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO],
7142 .rpc_argp = &args,
7143 .rpc_resp = &res,
7144 };
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007145 struct rpc_clnt *clnt = NFS_SERVER(dir)->client;
Weston Andros Adamson7cb852d2013-09-10 18:44:31 -04007146 struct rpc_cred *cred = NULL;
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007147
7148 if (use_integrity) {
7149 clnt = NFS_SERVER(dir)->nfs_client->cl_rpcclient;
Weston Andros Adamson7cb852d2013-09-10 18:44:31 -04007150 cred = nfs4_get_clid_cred(NFS_SERVER(dir)->nfs_client);
7151 msg.rpc_cred = cred;
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007152 }
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007153
7154 dprintk("NFS call secinfo %s\n", name->name);
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04007155
7156 nfs4_state_protect(NFS_SERVER(dir)->nfs_client,
7157 NFS_SP4_MACH_CRED_SECINFO, &clnt, &msg);
7158
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007159 status = nfs4_call_sync(clnt, NFS_SERVER(dir), &msg, &args.seq_args,
7160 &res.seq_res, 0);
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007161 dprintk("NFS reply secinfo: %d\n", status);
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007162
Weston Andros Adamson7cb852d2013-09-10 18:44:31 -04007163 if (cred)
7164 put_rpccred(cred);
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007165
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007166 return status;
7167}
7168
Bryan Schumaker72de53e2012-04-27 13:27:40 -04007169int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
7170 struct nfs4_secinfo_flavors *flavors)
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007171{
7172 struct nfs4_exception exception = { };
7173 int err;
7174 do {
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007175 err = -NFS4ERR_WRONGSEC;
7176
7177 /* try to use integrity protection with machine cred */
7178 if (_nfs4_is_integrity_protected(NFS_SERVER(dir)->nfs_client))
7179 err = _nfs4_proc_secinfo(dir, name, flavors, true);
7180
7181 /*
7182 * if unable to use integrity protection, or SECINFO with
7183 * integrity protection returns NFS4ERR_WRONGSEC (which is
7184 * disallowed by spec, but exists in deployed servers) use
7185 * the current filesystem's rpc_client and the user cred.
7186 */
7187 if (err == -NFS4ERR_WRONGSEC)
7188 err = _nfs4_proc_secinfo(dir, name, flavors, false);
7189
Trond Myklebust078ea3d2013-08-12 16:45:55 -04007190 trace_nfs4_secinfo(dir, name, err);
7191 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007192 &exception);
7193 } while (exception.retry);
7194 return err;
7195}
7196
Andy Adamson557134a2009-04-01 09:21:53 -04007197#ifdef CONFIG_NFS_V4_1
Benny Halevy99fe60d2009-04-01 09:22:29 -04007198/*
Andy Adamson357f54d2010-12-14 10:11:57 -05007199 * Check the exchange flags returned by the server for invalid flags, having
7200 * both PNFS and NON_PNFS flags set, and not having one of NON_PNFS, PNFS, or
7201 * DS flags set.
7202 */
7203static int nfs4_check_cl_exchange_flags(u32 flags)
7204{
7205 if (flags & ~EXCHGID4_FLAG_MASK_R)
7206 goto out_inval;
7207 if ((flags & EXCHGID4_FLAG_USE_PNFS_MDS) &&
7208 (flags & EXCHGID4_FLAG_USE_NON_PNFS))
7209 goto out_inval;
7210 if (!(flags & (EXCHGID4_FLAG_MASK_PNFS)))
7211 goto out_inval;
7212 return NFS_OK;
7213out_inval:
7214 return -NFS4ERR_INVAL;
7215}
7216
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04007217static bool
Chuck Lever79d4e1f2012-05-21 22:44:31 -04007218nfs41_same_server_scope(struct nfs41_server_scope *a,
7219 struct nfs41_server_scope *b)
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04007220{
Anna Schumaker49ad0142017-01-11 16:51:59 -05007221 if (a->server_scope_sz != b->server_scope_sz)
7222 return false;
7223 return memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0;
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04007224}
7225
Andy Adamson02a95de2016-02-05 16:08:37 -05007226static void
7227nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
7228{
7229}
7230
7231static const struct rpc_call_ops nfs4_bind_one_conn_to_session_ops = {
7232 .rpc_call_done = &nfs4_bind_one_conn_to_session_done,
7233};
7234
Andy Adamson357f54d2010-12-14 10:11:57 -05007235/*
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05007236 * nfs4_proc_bind_one_conn_to_session()
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007237 *
7238 * The 4.1 client currently uses the same TCP connection for the
7239 * fore and backchannel.
7240 */
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05007241static
7242int nfs4_proc_bind_one_conn_to_session(struct rpc_clnt *clnt,
7243 struct rpc_xprt *xprt,
7244 struct nfs_client *clp,
7245 struct rpc_cred *cred)
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007246{
7247 int status;
Trond Myklebust71a097c2015-02-18 09:27:18 -08007248 struct nfs41_bind_conn_to_session_args args = {
7249 .client = clp,
7250 .dir = NFS4_CDFC4_FORE_OR_BOTH,
7251 };
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007252 struct nfs41_bind_conn_to_session_res res;
7253 struct rpc_message msg = {
7254 .rpc_proc =
7255 &nfs4_procedures[NFSPROC4_CLNT_BIND_CONN_TO_SESSION],
Trond Myklebust71a097c2015-02-18 09:27:18 -08007256 .rpc_argp = &args,
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007257 .rpc_resp = &res,
Trond Myklebust2cf047c2012-05-25 17:57:41 -04007258 .rpc_cred = cred,
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007259 };
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05007260 struct rpc_task_setup task_setup_data = {
7261 .rpc_client = clnt,
7262 .rpc_xprt = xprt,
Andy Adamson02a95de2016-02-05 16:08:37 -05007263 .callback_ops = &nfs4_bind_one_conn_to_session_ops,
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05007264 .rpc_message = &msg,
7265 .flags = RPC_TASK_TIMEOUT,
7266 };
7267 struct rpc_task *task;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007268
Trond Myklebust71a097c2015-02-18 09:27:18 -08007269 nfs4_copy_sessionid(&args.sessionid, &clp->cl_session->sess_id);
7270 if (!(clp->cl_session->flags & SESSION4_BACK_CHAN))
7271 args.dir = NFS4_CDFC4_FORE;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007272
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05007273 /* Do not set the backchannel flag unless this is clnt->cl_xprt */
7274 if (xprt != rcu_access_pointer(clnt->cl_xprt))
7275 args.dir = NFS4_CDFC4_FORE;
7276
7277 task = rpc_run_task(&task_setup_data);
7278 if (!IS_ERR(task)) {
7279 status = task->tk_status;
7280 rpc_put_task(task);
7281 } else
7282 status = PTR_ERR(task);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04007283 trace_nfs4_bind_conn_to_session(clp, status);
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007284 if (status == 0) {
Trond Myklebust71a097c2015-02-18 09:27:18 -08007285 if (memcmp(res.sessionid.data,
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007286 clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) {
7287 dprintk("NFS: %s: Session ID mismatch\n", __func__);
Anna Schumakerc7ae7632017-04-07 14:15:21 -04007288 return -EIO;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007289 }
Trond Myklebust71a097c2015-02-18 09:27:18 -08007290 if ((res.dir & args.dir) != res.dir || res.dir == 0) {
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007291 dprintk("NFS: %s: Unexpected direction from server\n",
7292 __func__);
Anna Schumakerc7ae7632017-04-07 14:15:21 -04007293 return -EIO;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007294 }
Trond Myklebust71a097c2015-02-18 09:27:18 -08007295 if (res.use_conn_in_rdma_mode != args.use_conn_in_rdma_mode) {
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007296 dprintk("NFS: %s: Server returned RDMA mode = true\n",
7297 __func__);
Anna Schumakerc7ae7632017-04-07 14:15:21 -04007298 return -EIO;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007299 }
7300 }
Anna Schumakerc7ae7632017-04-07 14:15:21 -04007301
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007302 return status;
7303}
7304
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05007305struct rpc_bind_conn_calldata {
7306 struct nfs_client *clp;
7307 struct rpc_cred *cred;
7308};
7309
7310static int
7311nfs4_proc_bind_conn_to_session_callback(struct rpc_clnt *clnt,
7312 struct rpc_xprt *xprt,
7313 void *calldata)
7314{
7315 struct rpc_bind_conn_calldata *p = calldata;
7316
7317 return nfs4_proc_bind_one_conn_to_session(clnt, xprt, p->clp, p->cred);
7318}
7319
7320int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred)
7321{
7322 struct rpc_bind_conn_calldata data = {
7323 .clp = clp,
7324 .cred = cred,
7325 };
7326 return rpc_clnt_iterate_for_each_xprt(clp->cl_rpcclient,
7327 nfs4_proc_bind_conn_to_session_callback, &data);
7328}
7329
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04007330/*
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04007331 * Minimum set of SP4_MACH_CRED operations from RFC 5661 in the enforce map
7332 * and operations we'd like to see to enable certain features in the allow map
Benny Halevy99fe60d2009-04-01 09:22:29 -04007333 */
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007334static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = {
7335 .how = SP4_MACH_CRED,
7336 .enforce.u.words = {
7337 [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
7338 1 << (OP_EXCHANGE_ID - 32) |
7339 1 << (OP_CREATE_SESSION - 32) |
7340 1 << (OP_DESTROY_SESSION - 32) |
7341 1 << (OP_DESTROY_CLIENTID - 32)
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04007342 },
7343 .allow.u.words = {
7344 [0] = 1 << (OP_CLOSE) |
Andrew Elble99ade3c2015-12-02 09:39:51 -05007345 1 << (OP_OPEN_DOWNGRADE) |
Weston Andros Adamsona0279622013-09-10 18:44:30 -04007346 1 << (OP_LOCKU) |
Andrew Elble99ade3c2015-12-02 09:39:51 -05007347 1 << (OP_DELEGRETURN) |
Weston Andros Adamsona0279622013-09-10 18:44:30 -04007348 1 << (OP_COMMIT),
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04007349 [1] = 1 << (OP_SECINFO - 32) |
Weston Andros Adamson3787d502013-08-13 16:37:36 -04007350 1 << (OP_SECINFO_NO_NAME - 32) |
Andrew Elble99ade3c2015-12-02 09:39:51 -05007351 1 << (OP_LAYOUTRETURN - 32) |
Weston Andros Adamson3787d502013-08-13 16:37:36 -04007352 1 << (OP_TEST_STATEID - 32) |
Weston Andros Adamsona0279622013-09-10 18:44:30 -04007353 1 << (OP_FREE_STATEID - 32) |
7354 1 << (OP_WRITE - 32)
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007355 }
7356};
7357
7358/*
7359 * Select the state protection mode for client `clp' given the server results
7360 * from exchange_id in `sp'.
7361 *
7362 * Returns 0 on success, negative errno otherwise.
7363 */
7364static int nfs4_sp4_select_mode(struct nfs_client *clp,
7365 struct nfs41_state_protection *sp)
7366{
7367 static const u32 supported_enforce[NFS4_OP_MAP_NUM_WORDS] = {
7368 [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
7369 1 << (OP_EXCHANGE_ID - 32) |
7370 1 << (OP_CREATE_SESSION - 32) |
7371 1 << (OP_DESTROY_SESSION - 32) |
7372 1 << (OP_DESTROY_CLIENTID - 32)
7373 };
Trond Myklebust937e3132017-08-01 07:32:50 -04007374 unsigned long flags = 0;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007375 unsigned int i;
Trond Myklebust937e3132017-08-01 07:32:50 -04007376 int ret = 0;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007377
7378 if (sp->how == SP4_MACH_CRED) {
7379 /* Print state protect result */
7380 dfprintk(MOUNT, "Server SP4_MACH_CRED support:\n");
7381 for (i = 0; i <= LAST_NFS4_OP; i++) {
7382 if (test_bit(i, sp->enforce.u.longs))
7383 dfprintk(MOUNT, " enforce op %d\n", i);
7384 if (test_bit(i, sp->allow.u.longs))
7385 dfprintk(MOUNT, " allow op %d\n", i);
7386 }
7387
7388 /* make sure nothing is on enforce list that isn't supported */
7389 for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++) {
7390 if (sp->enforce.u.words[i] & ~supported_enforce[i]) {
7391 dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04007392 ret = -EINVAL;
7393 goto out;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007394 }
7395 }
7396
7397 /*
7398 * Minimal mode - state operations are allowed to use machine
7399 * credential. Note this already happens by default, so the
7400 * client doesn't have to do anything more than the negotiation.
7401 *
7402 * NOTE: we don't care if EXCHANGE_ID is in the list -
7403 * we're already using the machine cred for exchange_id
7404 * and will never use a different cred.
7405 */
7406 if (test_bit(OP_BIND_CONN_TO_SESSION, sp->enforce.u.longs) &&
7407 test_bit(OP_CREATE_SESSION, sp->enforce.u.longs) &&
7408 test_bit(OP_DESTROY_SESSION, sp->enforce.u.longs) &&
7409 test_bit(OP_DESTROY_CLIENTID, sp->enforce.u.longs)) {
7410 dfprintk(MOUNT, "sp4_mach_cred:\n");
7411 dfprintk(MOUNT, " minimal mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04007412 __set_bit(NFS_SP4_MACH_CRED_MINIMAL, &flags);
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007413 } else {
7414 dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04007415 ret = -EINVAL;
7416 goto out;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007417 }
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04007418
7419 if (test_bit(OP_CLOSE, sp->allow.u.longs) &&
Andrew Elble99ade3c2015-12-02 09:39:51 -05007420 test_bit(OP_OPEN_DOWNGRADE, sp->allow.u.longs) &&
7421 test_bit(OP_DELEGRETURN, sp->allow.u.longs) &&
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04007422 test_bit(OP_LOCKU, sp->allow.u.longs)) {
7423 dfprintk(MOUNT, " cleanup mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04007424 __set_bit(NFS_SP4_MACH_CRED_CLEANUP, &flags);
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04007425 }
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04007426
Andrew Elble99ade3c2015-12-02 09:39:51 -05007427 if (test_bit(OP_LAYOUTRETURN, sp->allow.u.longs)) {
7428 dfprintk(MOUNT, " pnfs cleanup mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04007429 __set_bit(NFS_SP4_MACH_CRED_PNFS_CLEANUP, &flags);
Andrew Elble99ade3c2015-12-02 09:39:51 -05007430 }
7431
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04007432 if (test_bit(OP_SECINFO, sp->allow.u.longs) &&
7433 test_bit(OP_SECINFO_NO_NAME, sp->allow.u.longs)) {
7434 dfprintk(MOUNT, " secinfo mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04007435 __set_bit(NFS_SP4_MACH_CRED_SECINFO, &flags);
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04007436 }
Weston Andros Adamson3787d502013-08-13 16:37:36 -04007437
7438 if (test_bit(OP_TEST_STATEID, sp->allow.u.longs) &&
7439 test_bit(OP_FREE_STATEID, sp->allow.u.longs)) {
7440 dfprintk(MOUNT, " stateid mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04007441 __set_bit(NFS_SP4_MACH_CRED_STATEID, &flags);
Weston Andros Adamson3787d502013-08-13 16:37:36 -04007442 }
Weston Andros Adamson8c21c622013-08-13 16:37:37 -04007443
7444 if (test_bit(OP_WRITE, sp->allow.u.longs)) {
7445 dfprintk(MOUNT, " write mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04007446 __set_bit(NFS_SP4_MACH_CRED_WRITE, &flags);
Weston Andros Adamson8c21c622013-08-13 16:37:37 -04007447 }
7448
7449 if (test_bit(OP_COMMIT, sp->allow.u.longs)) {
7450 dfprintk(MOUNT, " commit mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04007451 __set_bit(NFS_SP4_MACH_CRED_COMMIT, &flags);
Weston Andros Adamson8c21c622013-08-13 16:37:37 -04007452 }
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007453 }
Trond Myklebust937e3132017-08-01 07:32:50 -04007454out:
7455 clp->cl_sp4_flags = flags;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007456 return 0;
7457}
7458
Andy Adamson8d89bd72016-09-09 09:22:18 -04007459struct nfs41_exchange_id_data {
7460 struct nfs41_exchange_id_res res;
7461 struct nfs41_exchange_id_args args;
Andy Adamson8d89bd72016-09-09 09:22:18 -04007462};
7463
Andy Adamson8d89bd72016-09-09 09:22:18 -04007464static void nfs4_exchange_id_release(void *data)
7465{
7466 struct nfs41_exchange_id_data *cdata =
7467 (struct nfs41_exchange_id_data *)data;
7468
Olga Kornievskaia63513232017-03-13 10:36:19 -04007469 nfs_put_client(cdata->args.client);
Andy Adamson8d89bd72016-09-09 09:22:18 -04007470 kfree(cdata->res.impl_id);
7471 kfree(cdata->res.server_scope);
7472 kfree(cdata->res.server_owner);
7473 kfree(cdata);
7474}
7475
7476static const struct rpc_call_ops nfs4_exchange_id_call_ops = {
Andy Adamson8d89bd72016-09-09 09:22:18 -04007477 .rpc_release = nfs4_exchange_id_release,
7478};
7479
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007480/*
7481 * _nfs4_proc_exchange_id()
7482 *
7483 * Wrapper for EXCHANGE_ID operation.
7484 */
Trond Myklebust9c760d12017-07-31 18:38:50 -04007485static struct rpc_task *
7486nfs4_run_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
Andy Adamsonad0849a2016-09-09 09:22:28 -04007487 u32 sp4_how, struct rpc_xprt *xprt)
Benny Halevy99fe60d2009-04-01 09:22:29 -04007488{
Benny Halevy99fe60d2009-04-01 09:22:29 -04007489 struct rpc_message msg = {
7490 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID],
Benny Halevy99fe60d2009-04-01 09:22:29 -04007491 .rpc_cred = cred,
7492 };
Andy Adamson8d89bd72016-09-09 09:22:18 -04007493 struct rpc_task_setup task_setup_data = {
7494 .rpc_client = clp->cl_rpcclient,
7495 .callback_ops = &nfs4_exchange_id_call_ops,
7496 .rpc_message = &msg,
Trond Myklebustd9cb7332017-08-01 16:02:48 -04007497 .flags = RPC_TASK_TIMEOUT,
Andy Adamson8d89bd72016-09-09 09:22:18 -04007498 };
7499 struct nfs41_exchange_id_data *calldata;
Anna Schumakere917f0d2017-04-07 14:15:22 -04007500 int status;
Andy Adamson8d89bd72016-09-09 09:22:18 -04007501
Elena Reshetova212bf412017-10-20 12:53:38 +03007502 if (!refcount_inc_not_zero(&clp->cl_count))
Trond Myklebust9c760d12017-07-31 18:38:50 -04007503 return ERR_PTR(-EIO);
Andy Adamson8d89bd72016-09-09 09:22:18 -04007504
Trond Myklebust9c760d12017-07-31 18:38:50 -04007505 status = -ENOMEM;
Andy Adamson8d89bd72016-09-09 09:22:18 -04007506 calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
Trond Myklebust9c760d12017-07-31 18:38:50 -04007507 if (!calldata)
7508 goto out;
Benny Halevy99fe60d2009-04-01 09:22:29 -04007509
Trond Myklebustfd405592017-08-01 16:02:47 -04007510 nfs4_init_boot_verifier(clp, &calldata->args.verifier);
Jeff Layton873e3852015-06-09 19:44:00 -04007511
7512 status = nfs4_init_uniform_client_string(clp);
7513 if (status)
Andy Adamson8d89bd72016-09-09 09:22:18 -04007514 goto out_calldata;
Jeff Layton3a6bb732015-06-09 19:43:57 -04007515
Andy Adamson8d89bd72016-09-09 09:22:18 -04007516 calldata->res.server_owner = kzalloc(sizeof(struct nfs41_server_owner),
7517 GFP_NOFS);
7518 status = -ENOMEM;
7519 if (unlikely(calldata->res.server_owner == NULL))
7520 goto out_calldata;
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04007521
Andy Adamson8d89bd72016-09-09 09:22:18 -04007522 calldata->res.server_scope = kzalloc(sizeof(struct nfs41_server_scope),
Trond Myklebustbbafffd2012-05-24 16:31:39 -04007523 GFP_NOFS);
Andy Adamson8d89bd72016-09-09 09:22:18 -04007524 if (unlikely(calldata->res.server_scope == NULL))
Chuck Leveracdeb692012-05-21 22:46:16 -04007525 goto out_server_owner;
Benny Halevy99fe60d2009-04-01 09:22:29 -04007526
Andy Adamson8d89bd72016-09-09 09:22:18 -04007527 calldata->res.impl_id = kzalloc(sizeof(struct nfs41_impl_id), GFP_NOFS);
7528 if (unlikely(calldata->res.impl_id == NULL))
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05007529 goto out_server_scope;
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05007530
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007531 switch (sp4_how) {
7532 case SP4_NONE:
Andy Adamson8d89bd72016-09-09 09:22:18 -04007533 calldata->args.state_protect.how = SP4_NONE;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007534 break;
7535
7536 case SP4_MACH_CRED:
Andy Adamson8d89bd72016-09-09 09:22:18 -04007537 calldata->args.state_protect = nfs4_sp4_mach_cred_request;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007538 break;
7539
7540 default:
7541 /* unsupported! */
7542 WARN_ON_ONCE(1);
7543 status = -EINVAL;
Kinglong Mee6b559702015-07-01 11:54:53 +08007544 goto out_impl_id;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007545 }
Andy Adamsonad0849a2016-09-09 09:22:28 -04007546 if (xprt) {
Andy Adamsonad0849a2016-09-09 09:22:28 -04007547 task_setup_data.rpc_xprt = xprt;
Trond Myklebustd9cb7332017-08-01 16:02:48 -04007548 task_setup_data.flags |= RPC_TASK_SOFTCONN;
Trond Myklebustfd405592017-08-01 16:02:47 -04007549 memcpy(calldata->args.verifier.data, clp->cl_confirm.data,
7550 sizeof(calldata->args.verifier.data));
Andy Adamsonad0849a2016-09-09 09:22:28 -04007551 }
Andy Adamson8d89bd72016-09-09 09:22:18 -04007552 calldata->args.client = clp;
Trond Myklebustbfab2812017-08-01 08:17:34 -04007553 calldata->args.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER |
7554 EXCHGID4_FLAG_BIND_PRINC_STATEID;
Andy Adamson8d89bd72016-09-09 09:22:18 -04007555#ifdef CONFIG_NFS_V4_1_MIGRATION
Trond Myklebustbfab2812017-08-01 08:17:34 -04007556 calldata->args.flags |= EXCHGID4_FLAG_SUPP_MOVED_MIGR;
Andy Adamson8d89bd72016-09-09 09:22:18 -04007557#endif
7558 msg.rpc_argp = &calldata->args;
7559 msg.rpc_resp = &calldata->res;
7560 task_setup_data.callback_data = calldata;
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04007561
Trond Myklebust9c760d12017-07-31 18:38:50 -04007562 return rpc_run_task(&task_setup_data);
Andy Adamson8d89bd72016-09-09 09:22:18 -04007563
7564out_impl_id:
7565 kfree(calldata->res.impl_id);
7566out_server_scope:
7567 kfree(calldata->res.server_scope);
7568out_server_owner:
7569 kfree(calldata->res.server_owner);
7570out_calldata:
7571 kfree(calldata);
Trond Myklebust9c760d12017-07-31 18:38:50 -04007572out:
Olga Kornievskaia63513232017-03-13 10:36:19 -04007573 nfs_put_client(clp);
Trond Myklebust9c760d12017-07-31 18:38:50 -04007574 return ERR_PTR(status);
7575}
7576
7577/*
7578 * _nfs4_proc_exchange_id()
7579 *
7580 * Wrapper for EXCHANGE_ID operation.
7581 */
7582static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
7583 u32 sp4_how)
7584{
7585 struct rpc_task *task;
7586 struct nfs41_exchange_id_args *argp;
7587 struct nfs41_exchange_id_res *resp;
7588 int status;
7589
7590 task = nfs4_run_exchange_id(clp, cred, sp4_how, NULL);
7591 if (IS_ERR(task))
7592 return PTR_ERR(task);
7593
7594 argp = task->tk_msg.rpc_argp;
7595 resp = task->tk_msg.rpc_resp;
7596 status = task->tk_status;
7597 if (status != 0)
7598 goto out;
7599
7600 status = nfs4_check_cl_exchange_flags(resp->flags);
7601 if (status != 0)
7602 goto out;
7603
7604 status = nfs4_sp4_select_mode(clp, &resp->state_protect);
7605 if (status != 0)
7606 goto out;
7607
7608 clp->cl_clientid = resp->clientid;
7609 clp->cl_exchange_flags = resp->flags;
7610 clp->cl_seqid = resp->seqid;
7611 /* Client ID is not confirmed */
7612 if (!(resp->flags & EXCHGID4_FLAG_CONFIRMED_R))
7613 clear_bit(NFS4_SESSION_ESTABLISHED,
7614 &clp->cl_session->session_state);
7615
7616 if (clp->cl_serverscope != NULL &&
7617 !nfs41_same_server_scope(clp->cl_serverscope,
7618 resp->server_scope)) {
7619 dprintk("%s: server_scope mismatch detected\n",
7620 __func__);
7621 set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state);
7622 }
7623
7624 swap(clp->cl_serverowner, resp->server_owner);
7625 swap(clp->cl_serverscope, resp->server_scope);
7626 swap(clp->cl_implid, resp->impl_id);
7627
7628 /* Save the EXCHANGE_ID verifier session trunk tests */
7629 memcpy(clp->cl_confirm.data, argp->verifier.data,
7630 sizeof(clp->cl_confirm.data));
7631out:
7632 trace_nfs4_exchange_id(clp, status);
7633 rpc_put_task(task);
7634 return status;
Benny Halevy99fe60d2009-04-01 09:22:29 -04007635}
7636
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007637/*
7638 * nfs4_proc_exchange_id()
7639 *
7640 * Returns zero, a negative errno, or a negative NFS4ERR status code.
7641 *
7642 * Since the clientid has expired, all compounds using sessions
7643 * associated with the stale clientid will be returning
7644 * NFS4ERR_BADSESSION in the sequence operation, and will therefore
7645 * be in some phase of session reset.
7646 *
7647 * Will attempt to negotiate SP4_MACH_CRED if krb5i / krb5p auth is used.
7648 */
7649int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
7650{
7651 rpc_authflavor_t authflavor = clp->cl_rpcclient->cl_auth->au_flavor;
7652 int status;
7653
7654 /* try SP4_MACH_CRED if krb5i/p */
7655 if (authflavor == RPC_AUTH_GSS_KRB5I ||
7656 authflavor == RPC_AUTH_GSS_KRB5P) {
Trond Myklebust9c760d12017-07-31 18:38:50 -04007657 status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED);
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007658 if (!status)
7659 return 0;
7660 }
7661
7662 /* try SP4_NONE */
Trond Myklebust9c760d12017-07-31 18:38:50 -04007663 return _nfs4_proc_exchange_id(clp, cred, SP4_NONE);
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04007664}
7665
Andy Adamson04fa2c62016-09-09 09:22:29 -04007666/**
7667 * nfs4_test_session_trunk
7668 *
7669 * This is an add_xprt_test() test function called from
7670 * rpc_clnt_setup_test_and_add_xprt.
7671 *
7672 * The rpc_xprt_switch is referrenced by rpc_clnt_setup_test_and_add_xprt
7673 * and is dereferrenced in nfs4_exchange_id_release
7674 *
7675 * Upon success, add the new transport to the rpc_clnt
7676 *
7677 * @clnt: struct rpc_clnt to get new transport
7678 * @xprt: the rpc_xprt to test
7679 * @data: call data for _nfs4_proc_exchange_id.
7680 */
7681int nfs4_test_session_trunk(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
7682 void *data)
7683{
7684 struct nfs4_add_xprt_data *adata = (struct nfs4_add_xprt_data *)data;
Trond Myklebust9c760d12017-07-31 18:38:50 -04007685 struct rpc_task *task;
7686 int status;
7687
Andy Adamson04fa2c62016-09-09 09:22:29 -04007688 u32 sp4_how;
7689
7690 dprintk("--> %s try %s\n", __func__,
7691 xprt->address_strings[RPC_DISPLAY_ADDR]);
7692
7693 sp4_how = (adata->clp->cl_sp4_flags == 0 ? SP4_NONE : SP4_MACH_CRED);
7694
7695 /* Test connection for session trunking. Async exchange_id call */
Trond Myklebust9c760d12017-07-31 18:38:50 -04007696 task = nfs4_run_exchange_id(adata->clp, adata->cred, sp4_how, xprt);
7697 if (IS_ERR(task))
7698 return PTR_ERR(task);
7699
7700 status = task->tk_status;
7701 if (status == 0)
7702 status = nfs4_detect_session_trunking(adata->clp,
7703 task->tk_msg.rpc_resp, xprt);
7704
7705 rpc_put_task(task);
7706 return status;
Andy Adamson04fa2c62016-09-09 09:22:29 -04007707}
7708EXPORT_SYMBOL_GPL(nfs4_test_session_trunk);
7709
Trond Myklebust66245532012-05-25 17:18:09 -04007710static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
7711 struct rpc_cred *cred)
7712{
7713 struct rpc_message msg = {
7714 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_CLIENTID],
7715 .rpc_argp = clp,
7716 .rpc_cred = cred,
7717 };
7718 int status;
7719
7720 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04007721 trace_nfs4_destroy_clientid(clp, status);
Trond Myklebust66245532012-05-25 17:18:09 -04007722 if (status)
Trond Myklebust02c67522012-06-07 13:45:53 -04007723 dprintk("NFS: Got error %d from the server %s on "
Trond Myklebust66245532012-05-25 17:18:09 -04007724 "DESTROY_CLIENTID.", status, clp->cl_hostname);
7725 return status;
7726}
7727
7728static int nfs4_proc_destroy_clientid(struct nfs_client *clp,
7729 struct rpc_cred *cred)
7730{
7731 unsigned int loop;
7732 int ret;
7733
7734 for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
7735 ret = _nfs4_proc_destroy_clientid(clp, cred);
7736 switch (ret) {
7737 case -NFS4ERR_DELAY:
7738 case -NFS4ERR_CLIENTID_BUSY:
7739 ssleep(1);
7740 break;
7741 default:
7742 return ret;
7743 }
7744 }
7745 return 0;
7746}
7747
7748int nfs4_destroy_clientid(struct nfs_client *clp)
7749{
7750 struct rpc_cred *cred;
7751 int ret = 0;
7752
7753 if (clp->cl_mvops->minor_version < 1)
7754 goto out;
7755 if (clp->cl_exchange_flags == 0)
7756 goto out;
Chuck Lever05f4c352012-09-14 17:24:32 -04007757 if (clp->cl_preserve_clid)
7758 goto out;
Chuck Lever73d8bde2013-07-24 12:28:37 -04007759 cred = nfs4_get_clid_cred(clp);
Trond Myklebust66245532012-05-25 17:18:09 -04007760 ret = nfs4_proc_destroy_clientid(clp, cred);
7761 if (cred)
7762 put_rpccred(cred);
7763 switch (ret) {
7764 case 0:
7765 case -NFS4ERR_STALE_CLIENTID:
7766 clp->cl_exchange_flags = 0;
7767 }
7768out:
7769 return ret;
7770}
7771
Andy Adamson2050f0c2009-04-01 09:22:30 -04007772struct nfs4_get_lease_time_data {
7773 struct nfs4_get_lease_time_args *args;
7774 struct nfs4_get_lease_time_res *res;
7775 struct nfs_client *clp;
7776};
7777
7778static void nfs4_get_lease_time_prepare(struct rpc_task *task,
7779 void *calldata)
7780{
Andy Adamson2050f0c2009-04-01 09:22:30 -04007781 struct nfs4_get_lease_time_data *data =
7782 (struct nfs4_get_lease_time_data *)calldata;
7783
7784 dprintk("--> %s\n", __func__);
7785 /* just setup sequence, do not trigger session recovery
7786 since we're invoked within one */
Anna Schumaker7981c8a2017-01-10 11:39:53 -05007787 nfs4_setup_sequence(data->clp,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04007788 &data->args->la_seq_args,
7789 &data->res->lr_seq_res,
7790 task);
Andy Adamson2050f0c2009-04-01 09:22:30 -04007791 dprintk("<-- %s\n", __func__);
7792}
7793
7794/*
7795 * Called from nfs4_state_manager thread for session setup, so don't recover
7796 * from sequence operation or clientid errors.
7797 */
7798static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
7799{
7800 struct nfs4_get_lease_time_data *data =
7801 (struct nfs4_get_lease_time_data *)calldata;
7802
7803 dprintk("--> %s\n", __func__);
Trond Myklebust14516c32010-07-31 14:29:06 -04007804 if (!nfs41_sequence_done(task, &data->res->lr_seq_res))
7805 return;
Andy Adamson2050f0c2009-04-01 09:22:30 -04007806 switch (task->tk_status) {
7807 case -NFS4ERR_DELAY:
7808 case -NFS4ERR_GRACE:
7809 dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
7810 rpc_delay(task, NFS4_POLL_RETRY_MIN);
7811 task->tk_status = 0;
Andy Adamsona8a4ae32011-05-03 13:43:03 -04007812 /* fall through */
7813 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebustd00c5d42011-10-19 12:17:29 -07007814 rpc_restart_call_prepare(task);
Andy Adamson2050f0c2009-04-01 09:22:30 -04007815 return;
7816 }
Andy Adamson2050f0c2009-04-01 09:22:30 -04007817 dprintk("<-- %s\n", __func__);
7818}
7819
Trond Myklebust17280172012-03-11 13:11:00 -04007820static const struct rpc_call_ops nfs4_get_lease_time_ops = {
Andy Adamson2050f0c2009-04-01 09:22:30 -04007821 .rpc_call_prepare = nfs4_get_lease_time_prepare,
7822 .rpc_call_done = nfs4_get_lease_time_done,
7823};
7824
7825int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
7826{
7827 struct rpc_task *task;
7828 struct nfs4_get_lease_time_args args;
7829 struct nfs4_get_lease_time_res res = {
7830 .lr_fsinfo = fsinfo,
7831 };
7832 struct nfs4_get_lease_time_data data = {
7833 .args = &args,
7834 .res = &res,
7835 .clp = clp,
7836 };
7837 struct rpc_message msg = {
7838 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME],
7839 .rpc_argp = &args,
7840 .rpc_resp = &res,
7841 };
7842 struct rpc_task_setup task_setup = {
7843 .rpc_client = clp->cl_rpcclient,
7844 .rpc_message = &msg,
7845 .callback_ops = &nfs4_get_lease_time_ops,
Trond Myklebust1bd714f2011-04-24 14:29:33 -04007846 .callback_data = &data,
7847 .flags = RPC_TASK_TIMEOUT,
Andy Adamson2050f0c2009-04-01 09:22:30 -04007848 };
7849 int status;
7850
Chuck Levera9c92d62013-08-09 12:48:18 -04007851 nfs4_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04007852 nfs4_set_sequence_privileged(&args.la_seq_args);
Andy Adamson2050f0c2009-04-01 09:22:30 -04007853 task = rpc_run_task(&task_setup);
7854
7855 if (IS_ERR(task))
Anna Schumakerf6148712017-04-07 14:15:23 -04007856 return PTR_ERR(task);
Andy Adamson2050f0c2009-04-01 09:22:30 -04007857
Anna Schumakerf6148712017-04-07 14:15:23 -04007858 status = task->tk_status;
7859 rpc_put_task(task);
Andy Adamson2050f0c2009-04-01 09:22:30 -04007860 return status;
7861}
7862
Andy Adamsonfc931582009-04-01 09:22:31 -04007863/*
7864 * Initialize the values to be used by the client in CREATE_SESSION
7865 * If nfs4_init_session set the fore channel request and response sizes,
7866 * use them.
7867 *
7868 * Set the back channel max_resp_sz_cached to zero to force the client to
7869 * always set csa_cachethis to FALSE because the current implementation
7870 * of the back channel DRC only supports caching the CB_SEQUENCE operation.
7871 */
Chuck Lever6b26cc82016-05-02 14:40:40 -04007872static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args,
7873 struct rpc_clnt *clnt)
Andy Adamsonfc931582009-04-01 09:22:31 -04007874{
Andy Adamson18aad3d2013-06-26 12:21:49 -04007875 unsigned int max_rqst_sz, max_resp_sz;
Chuck Lever6b26cc82016-05-02 14:40:40 -04007876 unsigned int max_bc_payload = rpc_max_bc_payload(clnt);
Andy Adamsonfc931582009-04-01 09:22:31 -04007877
Andy Adamson18aad3d2013-06-26 12:21:49 -04007878 max_rqst_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxwrite_overhead;
7879 max_resp_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxread_overhead;
7880
Andy Adamsonfc931582009-04-01 09:22:31 -04007881 /* Fore channel attributes */
Andy Adamson18aad3d2013-06-26 12:21:49 -04007882 args->fc_attrs.max_rqst_sz = max_rqst_sz;
7883 args->fc_attrs.max_resp_sz = max_resp_sz;
Andy Adamsonfc931582009-04-01 09:22:31 -04007884 args->fc_attrs.max_ops = NFS4_MAX_OPS;
Trond Myklebustef159e92012-02-06 19:50:40 -05007885 args->fc_attrs.max_reqs = max_session_slots;
Andy Adamsonfc931582009-04-01 09:22:31 -04007886
7887 dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u "
Mike Sager8e0d46e2009-12-17 12:06:26 -05007888 "max_ops=%u max_reqs=%u\n",
Andy Adamsonfc931582009-04-01 09:22:31 -04007889 __func__,
7890 args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz,
Mike Sager8e0d46e2009-12-17 12:06:26 -05007891 args->fc_attrs.max_ops, args->fc_attrs.max_reqs);
Andy Adamsonfc931582009-04-01 09:22:31 -04007892
7893 /* Back channel attributes */
Chuck Lever6b26cc82016-05-02 14:40:40 -04007894 args->bc_attrs.max_rqst_sz = max_bc_payload;
7895 args->bc_attrs.max_resp_sz = max_bc_payload;
Andy Adamsonfc931582009-04-01 09:22:31 -04007896 args->bc_attrs.max_resp_sz_cached = 0;
7897 args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS;
Trond Myklebust5405fc42016-08-29 20:03:52 -04007898 args->bc_attrs.max_reqs = min_t(unsigned short, max_session_cb_slots, 1);
Andy Adamsonfc931582009-04-01 09:22:31 -04007899
7900 dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u "
7901 "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
7902 __func__,
7903 args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz,
7904 args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops,
7905 args->bc_attrs.max_reqs);
7906}
7907
Trond Myklebust79969dd2015-02-18 11:30:18 -08007908static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args,
7909 struct nfs41_create_session_res *res)
Andy Adamson8d353012009-04-01 09:22:32 -04007910{
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007911 struct nfs4_channel_attrs *sent = &args->fc_attrs;
Trond Myklebust79969dd2015-02-18 11:30:18 -08007912 struct nfs4_channel_attrs *rcvd = &res->fc_attrs;
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007913
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007914 if (rcvd->max_resp_sz > sent->max_resp_sz)
7915 return -EINVAL;
7916 /*
7917 * Our requested max_ops is the minimum we need; we're not
7918 * prepared to break up compounds into smaller pieces than that.
7919 * So, no point even trying to continue if the server won't
7920 * cooperate:
7921 */
7922 if (rcvd->max_ops < sent->max_ops)
7923 return -EINVAL;
7924 if (rcvd->max_reqs == 0)
7925 return -EINVAL;
Vitaliy Gusevb4b9a0c2012-02-15 19:38:25 +04007926 if (rcvd->max_reqs > NFS4_MAX_SLOT_TABLE)
7927 rcvd->max_reqs = NFS4_MAX_SLOT_TABLE;
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007928 return 0;
Andy Adamson8d353012009-04-01 09:22:32 -04007929}
7930
Trond Myklebust79969dd2015-02-18 11:30:18 -08007931static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args,
7932 struct nfs41_create_session_res *res)
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007933{
7934 struct nfs4_channel_attrs *sent = &args->bc_attrs;
Trond Myklebust79969dd2015-02-18 11:30:18 -08007935 struct nfs4_channel_attrs *rcvd = &res->bc_attrs;
Andy Adamson8d353012009-04-01 09:22:32 -04007936
Trond Myklebustb1c0df52015-02-18 11:34:58 -08007937 if (!(res->flags & SESSION4_BACK_CHAN))
7938 goto out;
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007939 if (rcvd->max_rqst_sz > sent->max_rqst_sz)
7940 return -EINVAL;
7941 if (rcvd->max_resp_sz < sent->max_resp_sz)
7942 return -EINVAL;
7943 if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
7944 return -EINVAL;
Trond Myklebust5405fc42016-08-29 20:03:52 -04007945 if (rcvd->max_ops > sent->max_ops)
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007946 return -EINVAL;
Trond Myklebust5405fc42016-08-29 20:03:52 -04007947 if (rcvd->max_reqs > sent->max_reqs)
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007948 return -EINVAL;
Trond Myklebustb1c0df52015-02-18 11:34:58 -08007949out:
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007950 return 0;
7951}
Andy Adamson8d353012009-04-01 09:22:32 -04007952
Andy Adamson8d353012009-04-01 09:22:32 -04007953static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args,
Trond Myklebust79969dd2015-02-18 11:30:18 -08007954 struct nfs41_create_session_res *res)
Andy Adamson8d353012009-04-01 09:22:32 -04007955{
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007956 int ret;
Andy Adamson8d353012009-04-01 09:22:32 -04007957
Trond Myklebust79969dd2015-02-18 11:30:18 -08007958 ret = nfs4_verify_fore_channel_attrs(args, res);
J. Bruce Fields43c2e882010-10-02 15:19:01 -04007959 if (ret)
7960 return ret;
Trond Myklebust79969dd2015-02-18 11:30:18 -08007961 return nfs4_verify_back_channel_attrs(args, res);
7962}
7963
7964static void nfs4_update_session(struct nfs4_session *session,
7965 struct nfs41_create_session_res *res)
7966{
7967 nfs4_copy_sessionid(&session->sess_id, &res->sessionid);
Trond Myklebuste11259f2015-03-03 20:35:31 -05007968 /* Mark client id and session as being confirmed */
7969 session->clp->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
7970 set_bit(NFS4_SESSION_ESTABLISHED, &session->session_state);
Trond Myklebust79969dd2015-02-18 11:30:18 -08007971 session->flags = res->flags;
7972 memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs));
Trond Myklebustb1c0df52015-02-18 11:34:58 -08007973 if (res->flags & SESSION4_BACK_CHAN)
7974 memcpy(&session->bc_attrs, &res->bc_attrs,
7975 sizeof(session->bc_attrs));
Andy Adamson8d353012009-04-01 09:22:32 -04007976}
7977
Trond Myklebust848f5bd2012-05-25 17:51:23 -04007978static int _nfs4_proc_create_session(struct nfs_client *clp,
7979 struct rpc_cred *cred)
Andy Adamsonfc931582009-04-01 09:22:31 -04007980{
7981 struct nfs4_session *session = clp->cl_session;
7982 struct nfs41_create_session_args args = {
7983 .client = clp,
Trond Myklebust79969dd2015-02-18 11:30:18 -08007984 .clientid = clp->cl_clientid,
7985 .seqid = clp->cl_seqid,
Andy Adamsonfc931582009-04-01 09:22:31 -04007986 .cb_program = NFS4_CALLBACK,
7987 };
Trond Myklebust79969dd2015-02-18 11:30:18 -08007988 struct nfs41_create_session_res res;
7989
Andy Adamsonfc931582009-04-01 09:22:31 -04007990 struct rpc_message msg = {
7991 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION],
7992 .rpc_argp = &args,
7993 .rpc_resp = &res,
Trond Myklebust848f5bd2012-05-25 17:51:23 -04007994 .rpc_cred = cred,
Andy Adamsonfc931582009-04-01 09:22:31 -04007995 };
7996 int status;
7997
Chuck Lever6b26cc82016-05-02 14:40:40 -04007998 nfs4_init_channel_attrs(&args, clp->cl_rpcclient);
Andy Adamson0f914212009-04-01 09:23:16 -04007999 args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
Andy Adamsonfc931582009-04-01 09:22:31 -04008000
Trond Myklebust1bd714f2011-04-24 14:29:33 -04008001 status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04008002 trace_nfs4_create_session(clp, status);
Andy Adamsonfc931582009-04-01 09:22:31 -04008003
Trond Myklebustb519d402016-09-11 14:50:01 -04008004 switch (status) {
8005 case -NFS4ERR_STALE_CLIENTID:
8006 case -NFS4ERR_DELAY:
8007 case -ETIMEDOUT:
8008 case -EACCES:
8009 case -EAGAIN:
8010 goto out;
8011 };
8012
8013 clp->cl_seqid++;
Trond Myklebust43095d32012-11-20 11:13:12 -05008014 if (!status) {
Andy Adamson8d353012009-04-01 09:22:32 -04008015 /* Verify the session's negotiated channel_attrs values */
Trond Myklebust79969dd2015-02-18 11:30:18 -08008016 status = nfs4_verify_channel_attrs(&args, &res);
Andy Adamsonfc931582009-04-01 09:22:31 -04008017 /* Increment the clientid slot sequence id */
Trond Myklebust79969dd2015-02-18 11:30:18 -08008018 if (status)
8019 goto out;
8020 nfs4_update_session(session, &res);
Andy Adamsonfc931582009-04-01 09:22:31 -04008021 }
Trond Myklebust79969dd2015-02-18 11:30:18 -08008022out:
Andy Adamsonfc931582009-04-01 09:22:31 -04008023 return status;
8024}
8025
8026/*
8027 * Issues a CREATE_SESSION operation to the server.
8028 * It is the responsibility of the caller to verify the session is
8029 * expired before calling this routine.
8030 */
Trond Myklebust848f5bd2012-05-25 17:51:23 -04008031int nfs4_proc_create_session(struct nfs_client *clp, struct rpc_cred *cred)
Andy Adamsonfc931582009-04-01 09:22:31 -04008032{
8033 int status;
8034 unsigned *ptr;
Andy Adamsonfc931582009-04-01 09:22:31 -04008035 struct nfs4_session *session = clp->cl_session;
8036
8037 dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
8038
Trond Myklebust848f5bd2012-05-25 17:51:23 -04008039 status = _nfs4_proc_create_session(clp, cred);
Andy Adamsonfc931582009-04-01 09:22:31 -04008040 if (status)
8041 goto out;
8042
Andy Adamsonaacd5532011-11-09 13:58:21 -05008043 /* Init or reset the session slot tables */
8044 status = nfs4_setup_session_slot_tables(session);
8045 dprintk("slot table setup returned %d\n", status);
Andy Adamsonfc931582009-04-01 09:22:31 -04008046 if (status)
8047 goto out;
8048
8049 ptr = (unsigned *)&session->sess_id.data[0];
8050 dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__,
8051 clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]);
Andy Adamsonfc931582009-04-01 09:22:31 -04008052out:
8053 dprintk("<-- %s\n", __func__);
8054 return status;
8055}
8056
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008057/*
8058 * Issue the over-the-wire RPC DESTROY_SESSION.
8059 * The caller must serialize access to this routine.
8060 */
Trond Myklebust848f5bd2012-05-25 17:51:23 -04008061int nfs4_proc_destroy_session(struct nfs4_session *session,
8062 struct rpc_cred *cred)
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008063{
Trond Myklebust848f5bd2012-05-25 17:51:23 -04008064 struct rpc_message msg = {
8065 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION],
8066 .rpc_argp = session,
8067 .rpc_cred = cred,
8068 };
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008069 int status = 0;
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008070
8071 dprintk("--> nfs4_proc_destroy_session\n");
8072
8073 /* session is still being setup */
Trond Myklebuste11259f2015-03-03 20:35:31 -05008074 if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state))
8075 return 0;
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008076
Trond Myklebust1bd714f2011-04-24 14:29:33 -04008077 status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04008078 trace_nfs4_destroy_session(session->clp, status);
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008079
8080 if (status)
Trond Myklebust08106ac2012-06-05 10:08:24 -04008081 dprintk("NFS: Got error %d from the server on DESTROY_SESSION. "
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008082 "Session has been destroyed regardless...\n", status);
8083
8084 dprintk("<-- nfs4_proc_destroy_session\n");
8085 return status;
8086}
8087
Trond Myklebust7b38c362012-05-23 13:23:31 -04008088/*
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008089 * Renew the cl_session lease.
8090 */
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008091struct nfs4_sequence_data {
8092 struct nfs_client *clp;
8093 struct nfs4_sequence_args args;
8094 struct nfs4_sequence_res res;
8095};
8096
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008097static void nfs41_sequence_release(void *data)
8098{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008099 struct nfs4_sequence_data *calldata = data;
8100 struct nfs_client *clp = calldata->clp;
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008101
Elena Reshetova212bf412017-10-20 12:53:38 +03008102 if (refcount_read(&clp->cl_count) > 1)
Alexandros Batsakis71358402010-02-05 03:45:05 -08008103 nfs4_schedule_state_renewal(clp);
8104 nfs_put_client(clp);
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008105 kfree(calldata);
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008106}
8107
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008108static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp)
8109{
8110 switch(task->tk_status) {
8111 case -NFS4ERR_DELAY:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008112 rpc_delay(task, NFS4_POLL_RETRY_MAX);
8113 return -EAGAIN;
8114 default:
Trond Myklebust0400a6b2011-03-09 16:00:53 -05008115 nfs4_schedule_lease_recovery(clp);
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008116 }
8117 return 0;
8118}
8119
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008120static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008121{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008122 struct nfs4_sequence_data *calldata = data;
8123 struct nfs_client *clp = calldata->clp;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008124
Trond Myklebust14516c32010-07-31 14:29:06 -04008125 if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
8126 return;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008127
Trond Myklebustc6d01c62013-08-09 11:51:26 -04008128 trace_nfs4_sequence(clp, task->tk_status);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008129 if (task->tk_status < 0) {
8130 dprintk("%s ERROR %d\n", __func__, task->tk_status);
Elena Reshetova212bf412017-10-20 12:53:38 +03008131 if (refcount_read(&clp->cl_count) == 1)
Alexandros Batsakis71358402010-02-05 03:45:05 -08008132 goto out;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008133
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008134 if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) {
8135 rpc_restart_call_prepare(task);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008136 return;
8137 }
8138 }
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008139 dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
Alexandros Batsakis71358402010-02-05 03:45:05 -08008140out:
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008141 dprintk("<-- %s\n", __func__);
8142}
8143
8144static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
8145{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008146 struct nfs4_sequence_data *calldata = data;
8147 struct nfs_client *clp = calldata->clp;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008148 struct nfs4_sequence_args *args;
8149 struct nfs4_sequence_res *res;
8150
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008151 args = task->tk_msg.rpc_argp;
8152 res = task->tk_msg.rpc_resp;
8153
Anna Schumaker7981c8a2017-01-10 11:39:53 -05008154 nfs4_setup_sequence(clp, args, res, task);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008155}
8156
8157static const struct rpc_call_ops nfs41_sequence_ops = {
8158 .rpc_call_done = nfs41_sequence_call_done,
8159 .rpc_call_prepare = nfs41_sequence_prepare,
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008160 .rpc_release = nfs41_sequence_release,
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008161};
8162
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04008163static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
8164 struct rpc_cred *cred,
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04008165 struct nfs4_slot *slot,
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04008166 bool is_privileged)
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008167{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008168 struct nfs4_sequence_data *calldata;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008169 struct rpc_message msg = {
8170 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
8171 .rpc_cred = cred,
8172 };
Trond Myklebust71ac6da2010-06-16 09:52:26 -04008173 struct rpc_task_setup task_setup_data = {
8174 .rpc_client = clp->cl_rpcclient,
8175 .rpc_message = &msg,
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04008176 .callback_ops = &nfs41_sequence_ops,
Trond Myklebustbc7a05c2013-04-08 17:50:28 -04008177 .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
Trond Myklebust71ac6da2010-06-16 09:52:26 -04008178 };
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04008179 struct rpc_task *ret;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008180
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04008181 ret = ERR_PTR(-EIO);
Elena Reshetova212bf412017-10-20 12:53:38 +03008182 if (!refcount_inc_not_zero(&clp->cl_count))
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04008183 goto out_err;
8184
8185 ret = ERR_PTR(-ENOMEM);
Benny Halevydfb4f3092010-09-24 09:17:01 -04008186 calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04008187 if (calldata == NULL)
8188 goto out_put_clp;
Chuck Levera9c92d62013-08-09 12:48:18 -04008189 nfs4_init_sequence(&calldata->args, &calldata->res, 0);
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04008190 nfs4_sequence_attach_slot(&calldata->args, &calldata->res, slot);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04008191 if (is_privileged)
8192 nfs4_set_sequence_privileged(&calldata->args);
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008193 msg.rpc_argp = &calldata->args;
8194 msg.rpc_resp = &calldata->res;
8195 calldata->clp = clp;
Trond Myklebust71ac6da2010-06-16 09:52:26 -04008196 task_setup_data.callback_data = calldata;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008197
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04008198 ret = rpc_run_task(&task_setup_data);
8199 if (IS_ERR(ret))
8200 goto out_err;
8201 return ret;
8202out_put_clp:
8203 nfs_put_client(clp);
8204out_err:
8205 nfs41_release_slot(slot);
8206 return ret;
Trond Myklebust71ac6da2010-06-16 09:52:26 -04008207}
8208
Trond Myklebust2f60ea62011-08-24 15:07:37 -04008209static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags)
Trond Myklebust71ac6da2010-06-16 09:52:26 -04008210{
8211 struct rpc_task *task;
8212 int ret = 0;
8213
Trond Myklebust2f60ea62011-08-24 15:07:37 -04008214 if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
Andy Adamsond1f456b2014-09-29 12:31:57 -04008215 return -EAGAIN;
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04008216 task = _nfs41_proc_sequence(clp, cred, NULL, false);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04008217 if (IS_ERR(task))
8218 ret = PTR_ERR(task);
8219 else
Trond Myklebustbf294b42011-02-21 11:05:41 -08008220 rpc_put_task_async(task);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04008221 dprintk("<-- %s status=%d\n", __func__, ret);
8222 return ret;
8223}
8224
8225static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
8226{
8227 struct rpc_task *task;
8228 int ret;
8229
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04008230 task = _nfs41_proc_sequence(clp, cred, NULL, true);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04008231 if (IS_ERR(task)) {
8232 ret = PTR_ERR(task);
8233 goto out;
8234 }
8235 ret = rpc_wait_for_completion_task(task);
Trond Myklebustbe824162015-07-05 14:50:46 -04008236 if (!ret)
Trond Myklebust71ac6da2010-06-16 09:52:26 -04008237 ret = task->tk_status;
8238 rpc_put_task(task);
8239out:
8240 dprintk("<-- %s status=%d\n", __func__, ret);
8241 return ret;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008242}
8243
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008244struct nfs4_reclaim_complete_data {
8245 struct nfs_client *clp;
8246 struct nfs41_reclaim_complete_args arg;
8247 struct nfs41_reclaim_complete_res res;
8248};
8249
8250static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
8251{
8252 struct nfs4_reclaim_complete_data *calldata = data;
8253
Anna Schumaker7981c8a2017-01-10 11:39:53 -05008254 nfs4_setup_sequence(calldata->clp,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04008255 &calldata->arg.seq_args,
8256 &calldata->res.seq_res,
8257 task);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008258}
8259
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008260static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp)
8261{
8262 switch(task->tk_status) {
8263 case 0:
8264 case -NFS4ERR_COMPLETE_ALREADY:
8265 case -NFS4ERR_WRONG_CRED: /* What to do here? */
8266 break;
8267 case -NFS4ERR_DELAY:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008268 rpc_delay(task, NFS4_POLL_RETRY_MAX);
Andy Adamsona8a4ae32011-05-03 13:43:03 -04008269 /* fall through */
8270 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008271 return -EAGAIN;
Trond Myklebust0048fdd2017-05-04 13:44:04 -04008272 case -NFS4ERR_BADSESSION:
8273 case -NFS4ERR_DEADSESSION:
8274 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
8275 nfs4_schedule_session_recovery(clp->cl_session,
8276 task->tk_status);
8277 break;
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008278 default:
Trond Myklebust0400a6b2011-03-09 16:00:53 -05008279 nfs4_schedule_lease_recovery(clp);
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008280 }
8281 return 0;
8282}
8283
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008284static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
8285{
8286 struct nfs4_reclaim_complete_data *calldata = data;
8287 struct nfs_client *clp = calldata->clp;
8288 struct nfs4_sequence_res *res = &calldata->res.seq_res;
8289
8290 dprintk("--> %s\n", __func__);
Trond Myklebust14516c32010-07-31 14:29:06 -04008291 if (!nfs41_sequence_done(task, res))
8292 return;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008293
Trond Myklebustc6d01c62013-08-09 11:51:26 -04008294 trace_nfs4_reclaim_complete(clp, task->tk_status);
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008295 if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) {
8296 rpc_restart_call_prepare(task);
8297 return;
8298 }
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008299 dprintk("<-- %s\n", __func__);
8300}
8301
8302static void nfs4_free_reclaim_complete_data(void *data)
8303{
8304 struct nfs4_reclaim_complete_data *calldata = data;
8305
8306 kfree(calldata);
8307}
8308
8309static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = {
8310 .rpc_call_prepare = nfs4_reclaim_complete_prepare,
8311 .rpc_call_done = nfs4_reclaim_complete_done,
8312 .rpc_release = nfs4_free_reclaim_complete_data,
8313};
8314
8315/*
8316 * Issue a global reclaim complete.
8317 */
Trond Myklebust965e9c22013-05-20 11:05:17 -04008318static int nfs41_proc_reclaim_complete(struct nfs_client *clp,
8319 struct rpc_cred *cred)
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008320{
8321 struct nfs4_reclaim_complete_data *calldata;
8322 struct rpc_task *task;
8323 struct rpc_message msg = {
8324 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE],
Trond Myklebust965e9c22013-05-20 11:05:17 -04008325 .rpc_cred = cred,
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008326 };
8327 struct rpc_task_setup task_setup_data = {
8328 .rpc_client = clp->cl_rpcclient,
8329 .rpc_message = &msg,
8330 .callback_ops = &nfs4_reclaim_complete_call_ops,
8331 .flags = RPC_TASK_ASYNC,
8332 };
8333 int status = -ENOMEM;
8334
8335 dprintk("--> %s\n", __func__);
Trond Myklebust8535b2b2010-05-13 12:51:01 -04008336 calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008337 if (calldata == NULL)
8338 goto out;
8339 calldata->clp = clp;
8340 calldata->arg.one_fs = 0;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008341
Chuck Levera9c92d62013-08-09 12:48:18 -04008342 nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04008343 nfs4_set_sequence_privileged(&calldata->arg.seq_args);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008344 msg.rpc_argp = &calldata->arg;
8345 msg.rpc_resp = &calldata->res;
8346 task_setup_data.callback_data = calldata;
8347 task = rpc_run_task(&task_setup_data);
Dan Carpenteracf82b82010-04-22 11:28:39 +02008348 if (IS_ERR(task)) {
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008349 status = PTR_ERR(task);
Dan Carpenteracf82b82010-04-22 11:28:39 +02008350 goto out;
8351 }
Anna Schumaker820bf852017-01-11 15:01:43 -05008352 status = rpc_wait_for_completion_task(task);
Andy Adamsonc34c32e2011-03-09 13:13:46 -05008353 if (status == 0)
8354 status = task->tk_status;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05008355 rpc_put_task(task);
8356out:
8357 dprintk("<-- %s status=%d\n", __func__, status);
8358 return status;
8359}
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008360
8361static void
8362nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
8363{
8364 struct nfs4_layoutget *lgp = calldata;
Fred Isamanc31663d2011-01-06 11:36:24 +00008365 struct nfs_server *server = NFS_SERVER(lgp->args.inode);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008366
8367 dprintk("--> %s\n", __func__);
Anna Schumaker7981c8a2017-01-10 11:39:53 -05008368 nfs4_setup_sequence(server->nfs_client, &lgp->args.seq_args,
Jeff Layton183d9e72016-05-17 12:28:47 -04008369 &lgp->res.seq_res, task);
8370 dprintk("<-- %s\n", __func__);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008371}
8372
8373static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
8374{
8375 struct nfs4_layoutget *lgp = calldata;
Jeff Layton183d9e72016-05-17 12:28:47 -04008376
8377 dprintk("--> %s\n", __func__);
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04008378 nfs41_sequence_process(task, &lgp->res.seq_res);
Jeff Layton183d9e72016-05-17 12:28:47 -04008379 dprintk("<-- %s\n", __func__);
8380}
8381
8382static int
8383nfs4_layoutget_handle_exception(struct rpc_task *task,
8384 struct nfs4_layoutget *lgp, struct nfs4_exception *exception)
8385{
Trond Myklebustee314c22012-10-01 17:25:48 -07008386 struct inode *inode = lgp->args.inode;
8387 struct nfs_server *server = NFS_SERVER(inode);
8388 struct pnfs_layout_hdr *lo;
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04008389 int nfs4err = task->tk_status;
8390 int err, status = 0;
Trond Myklebustf7db0b22016-07-14 15:14:02 -04008391 LIST_HEAD(head);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008392
Boaz Harroshed7e5422014-01-22 20:34:54 +02008393 dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008394
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04008395 switch (nfs4err) {
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008396 case 0:
Trond Myklebustee314c22012-10-01 17:25:48 -07008397 goto out;
Peng Tao7c1e6e52015-12-05 17:01:01 +08008398
8399 /*
8400 * NFS4ERR_LAYOUTUNAVAILABLE means we are not supposed to use pnfs
8401 * on the file. set tk_status to -ENODATA to tell upper layer to
8402 * retry go inband.
8403 */
8404 case -NFS4ERR_LAYOUTUNAVAILABLE:
Jeff Layton183d9e72016-05-17 12:28:47 -04008405 status = -ENODATA;
Peng Tao7c1e6e52015-12-05 17:01:01 +08008406 goto out;
Boaz Harroshed7e5422014-01-22 20:34:54 +02008407 /*
Trond Myklebust21b874c2015-08-31 01:19:22 -07008408 * NFS4ERR_BADLAYOUT means the MDS cannot return a layout of
8409 * length lgp->args.minlength != 0 (see RFC5661 section 18.43.3).
8410 */
8411 case -NFS4ERR_BADLAYOUT:
Jeff Layton183d9e72016-05-17 12:28:47 -04008412 status = -EOVERFLOW;
8413 goto out;
Trond Myklebust21b874c2015-08-31 01:19:22 -07008414 /*
Boaz Harroshed7e5422014-01-22 20:34:54 +02008415 * NFS4ERR_LAYOUTTRYLATER is a conflict with another client
Trond Myklebust21b874c2015-08-31 01:19:22 -07008416 * (or clients) writing to the same RAID stripe except when
8417 * the minlength argument is 0 (see RFC5661 section 18.43.3).
Jeff Layton183d9e72016-05-17 12:28:47 -04008418 *
8419 * Treat it like we would RECALLCONFLICT -- we retry for a little
8420 * while, and then eventually give up.
Boaz Harroshed7e5422014-01-22 20:34:54 +02008421 */
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008422 case -NFS4ERR_LAYOUTTRYLATER:
Jeff Layton183d9e72016-05-17 12:28:47 -04008423 if (lgp->args.minlength == 0) {
8424 status = -EOVERFLOW;
8425 goto out;
Boaz Harroshed7e5422014-01-22 20:34:54 +02008426 }
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04008427 status = -EBUSY;
8428 break;
Jeff Layton183d9e72016-05-17 12:28:47 -04008429 case -NFS4ERR_RECALLCONFLICT:
Jeff Layton183d9e72016-05-17 12:28:47 -04008430 status = -ERECALLCONFLICT;
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04008431 break;
Trond Myklebust26f47442016-09-22 13:39:10 -04008432 case -NFS4ERR_DELEG_REVOKED:
8433 case -NFS4ERR_ADMIN_REVOKED:
Trond Myklebustee314c22012-10-01 17:25:48 -07008434 case -NFS4ERR_EXPIRED:
8435 case -NFS4ERR_BAD_STATEID:
Jeff Layton183d9e72016-05-17 12:28:47 -04008436 exception->timeout = 0;
Trond Myklebustee314c22012-10-01 17:25:48 -07008437 spin_lock(&inode->i_lock);
Trond Myklebustf7db0b22016-07-14 15:14:02 -04008438 lo = NFS_I(inode)->layout;
8439 /* If the open stateid was bad, then recover it. */
8440 if (!lo || test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) ||
Trond Myklebuste8fa33a2017-10-04 13:49:12 -04008441 !nfs4_stateid_match_other(&lgp->args.stateid, &lo->plh_stateid)) {
Trond Myklebustee314c22012-10-01 17:25:48 -07008442 spin_unlock(&inode->i_lock);
Jeff Layton183d9e72016-05-17 12:28:47 -04008443 exception->state = lgp->args.ctx->state;
Trond Myklebust26f47442016-09-22 13:39:10 -04008444 exception->stateid = &lgp->args.stateid;
Trond Myklebust2259f962015-09-20 13:30:30 -04008445 break;
8446 }
Trond Myklebustee314c22012-10-01 17:25:48 -07008447
Trond Myklebustf7db0b22016-07-14 15:14:02 -04008448 /*
8449 * Mark the bad layout state as invalid, then retry
8450 */
Trond Myklebust668f4552016-07-24 17:08:59 -04008451 pnfs_mark_layout_stateid_invalid(lo, &head);
Trond Myklebustf7db0b22016-07-14 15:14:02 -04008452 spin_unlock(&inode->i_lock);
Trond Myklebust1f18b822017-04-29 10:10:17 -04008453 nfs_commit_inode(inode, 0);
Trond Myklebustf7db0b22016-07-14 15:14:02 -04008454 pnfs_free_lseg_list(&head);
8455 status = -EAGAIN;
8456 goto out;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008457 }
Jeff Layton183d9e72016-05-17 12:28:47 -04008458
Trond Myklebust8ac09252017-01-23 22:44:12 -05008459 nfs4_sequence_free_slot(&lgp->res.seq_res);
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04008460 err = nfs4_handle_exception(server, nfs4err, exception);
8461 if (!status) {
8462 if (exception->retry)
8463 status = -EAGAIN;
8464 else
8465 status = err;
8466 }
Trond Myklebustee314c22012-10-01 17:25:48 -07008467out:
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008468 dprintk("<-- %s\n", __func__);
Jeff Layton183d9e72016-05-17 12:28:47 -04008469 return status;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008470}
8471
Idan Kedar85541162012-08-02 11:47:10 +03008472static size_t max_response_pages(struct nfs_server *server)
8473{
8474 u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
8475 return nfs_page_array_len(0, max_resp_sz);
8476}
8477
8478static void nfs4_free_pages(struct page **pages, size_t size)
8479{
8480 int i;
8481
8482 if (!pages)
8483 return;
8484
8485 for (i = 0; i < size; i++) {
8486 if (!pages[i])
8487 break;
8488 __free_page(pages[i]);
8489 }
8490 kfree(pages);
8491}
8492
8493static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)
8494{
8495 struct page **pages;
8496 int i;
8497
8498 pages = kcalloc(size, sizeof(struct page *), gfp_flags);
8499 if (!pages) {
8500 dprintk("%s: can't alloc array of %zu pages\n", __func__, size);
8501 return NULL;
8502 }
8503
8504 for (i = 0; i < size; i++) {
8505 pages[i] = alloc_page(gfp_flags);
8506 if (!pages[i]) {
8507 dprintk("%s: failed to allocate page\n", __func__);
8508 nfs4_free_pages(pages, size);
8509 return NULL;
8510 }
8511 }
8512
8513 return pages;
8514}
8515
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008516static void nfs4_layoutget_release(void *calldata)
8517{
8518 struct nfs4_layoutget *lgp = calldata;
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05008519 struct inode *inode = lgp->args.inode;
8520 struct nfs_server *server = NFS_SERVER(inode);
Idan Kedar85541162012-08-02 11:47:10 +03008521 size_t max_pages = max_response_pages(server);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008522
8523 dprintk("--> %s\n", __func__);
Trond Myklebustbd171932017-06-27 17:33:38 -04008524 nfs4_sequence_free_slot(&lgp->res.seq_res);
Idan Kedar85541162012-08-02 11:47:10 +03008525 nfs4_free_pages(lgp->args.layout.pages, max_pages);
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05008526 pnfs_put_layout_hdr(NFS_I(inode)->layout);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008527 put_nfs_open_context(lgp->args.ctx);
8528 kfree(calldata);
8529 dprintk("<-- %s\n", __func__);
8530}
8531
8532static const struct rpc_call_ops nfs4_layoutget_call_ops = {
8533 .rpc_call_prepare = nfs4_layoutget_prepare,
8534 .rpc_call_done = nfs4_layoutget_done,
8535 .rpc_release = nfs4_layoutget_release,
8536};
8537
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04008538struct pnfs_layout_segment *
Jeff Layton183d9e72016-05-17 12:28:47 -04008539nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout, gfp_t gfp_flags)
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008540{
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05008541 struct inode *inode = lgp->args.inode;
8542 struct nfs_server *server = NFS_SERVER(inode);
Idan Kedar85541162012-08-02 11:47:10 +03008543 size_t max_pages = max_response_pages(server);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008544 struct rpc_task *task;
8545 struct rpc_message msg = {
8546 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
8547 .rpc_argp = &lgp->args,
8548 .rpc_resp = &lgp->res,
Trond Myklebust6ab59342013-05-20 10:49:34 -04008549 .rpc_cred = lgp->cred,
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008550 };
8551 struct rpc_task_setup task_setup_data = {
8552 .rpc_client = server->client,
8553 .rpc_message = &msg,
8554 .callback_ops = &nfs4_layoutget_call_ops,
8555 .callback_data = lgp,
8556 .flags = RPC_TASK_ASYNC,
8557 };
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04008558 struct pnfs_layout_segment *lseg = NULL;
Trond Myklebustbc236762016-06-17 16:48:18 -04008559 struct nfs4_exception exception = {
8560 .inode = inode,
8561 .timeout = *timeout,
8562 };
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008563 int status = 0;
8564
8565 dprintk("--> %s\n", __func__);
8566
Peng Tao4bd5a982014-11-17 11:05:17 +08008567 /* nfs4_layoutget_release calls pnfs_put_layout_hdr */
8568 pnfs_get_layout_hdr(NFS_I(inode)->layout);
8569
Idan Kedar85541162012-08-02 11:47:10 +03008570 lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
8571 if (!lgp->args.layout.pages) {
8572 nfs4_layoutget_release(lgp);
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04008573 return ERR_PTR(-ENOMEM);
Idan Kedar85541162012-08-02 11:47:10 +03008574 }
8575 lgp->args.layout.pglen = max_pages * PAGE_SIZE;
8576
Weston Andros Adamson35124a02011-03-24 16:48:21 -04008577 lgp->res.layoutp = &lgp->args.layout;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008578 lgp->res.seq_res.sr_slot = NULL;
Chuck Levera9c92d62013-08-09 12:48:18 -04008579 nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05008580
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008581 task = rpc_run_task(&task_setup_data);
8582 if (IS_ERR(task))
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04008583 return ERR_CAST(task);
Anna Schumaker820bf852017-01-11 15:01:43 -05008584 status = rpc_wait_for_completion_task(task);
Jeff Layton183d9e72016-05-17 12:28:47 -04008585 if (status == 0) {
8586 status = nfs4_layoutget_handle_exception(task, lgp, &exception);
8587 *timeout = exception.timeout;
8588 }
8589
Trond Myklebust1037e6e2013-08-14 16:36:51 -04008590 trace_nfs4_layoutget(lgp->args.ctx,
8591 &lgp->args.range,
8592 &lgp->res.range,
Olga Kornievskaia48c95792015-11-24 13:29:41 -05008593 &lgp->res.stateid,
Trond Myklebust1037e6e2013-08-14 16:36:51 -04008594 status);
Jeff Layton183d9e72016-05-17 12:28:47 -04008595
Weston Andros Adamson085b7a42013-02-15 16:03:46 -05008596 /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
8597 if (status == 0 && lgp->res.layoutp->len)
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04008598 lseg = pnfs_layout_process(lgp);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008599 rpc_put_task(task);
8600 dprintk("<-- %s status=%d\n", __func__, status);
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04008601 if (status)
8602 return ERR_PTR(status);
8603 return lseg;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008604}
8605
Benny Halevycbe82602011-05-22 19:52:37 +03008606static void
8607nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
8608{
8609 struct nfs4_layoutreturn *lrp = calldata;
8610
8611 dprintk("--> %s\n", __func__);
Anna Schumaker7981c8a2017-01-10 11:39:53 -05008612 nfs4_setup_sequence(lrp->clp,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04008613 &lrp->args.seq_args,
8614 &lrp->res.seq_res,
8615 task);
Benny Halevycbe82602011-05-22 19:52:37 +03008616}
8617
8618static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
8619{
8620 struct nfs4_layoutreturn *lrp = calldata;
8621 struct nfs_server *server;
8622
8623 dprintk("--> %s\n", __func__);
8624
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04008625 if (!nfs41_sequence_process(task, &lrp->res.seq_res))
Benny Halevycbe82602011-05-22 19:52:37 +03008626 return;
8627
8628 server = NFS_SERVER(lrp->args.inode);
Trond Myklebustf22e5ed2013-12-04 12:09:45 -05008629 switch (task->tk_status) {
8630 default:
8631 task->tk_status = 0;
8632 case 0:
8633 break;
8634 case -NFS4ERR_DELAY:
NeilBrown8478eaa2014-09-18 16:09:27 +10008635 if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN)
Trond Myklebustf22e5ed2013-12-04 12:09:45 -05008636 break;
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04008637 nfs4_sequence_free_slot(&lrp->res.seq_res);
Trond Myklebustd00c5d42011-10-19 12:17:29 -07008638 rpc_restart_call_prepare(task);
Benny Halevycbe82602011-05-22 19:52:37 +03008639 return;
8640 }
Benny Halevycbe82602011-05-22 19:52:37 +03008641 dprintk("<-- %s\n", __func__);
8642}
8643
8644static void nfs4_layoutreturn_release(void *calldata)
8645{
8646 struct nfs4_layoutreturn *lrp = calldata;
Trond Myklebust849b2862012-09-24 14:18:39 -04008647 struct pnfs_layout_hdr *lo = lrp->args.layout;
Benny Halevycbe82602011-05-22 19:52:37 +03008648
8649 dprintk("--> %s\n", __func__);
Trond Myklebust2a974422016-11-20 13:13:54 -05008650 pnfs_layoutreturn_free_lsegs(lo, &lrp->args.stateid, &lrp->args.range,
Trond Myklebust68f74472016-10-12 19:50:54 -04008651 lrp->res.lrs_present ? &lrp->res.stateid : NULL);
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04008652 nfs4_sequence_free_slot(&lrp->res.seq_res);
Trond Myklebust4d796d72016-09-23 11:38:08 -04008653 if (lrp->ld_private.ops && lrp->ld_private.ops->free)
8654 lrp->ld_private.ops->free(&lrp->ld_private);
Trond Myklebust2f065dd2016-12-07 12:29:26 -05008655 pnfs_put_layout_hdr(lrp->args.layout);
8656 nfs_iput_and_deactive(lrp->inode);
Benny Halevycbe82602011-05-22 19:52:37 +03008657 kfree(calldata);
8658 dprintk("<-- %s\n", __func__);
8659}
8660
8661static const struct rpc_call_ops nfs4_layoutreturn_call_ops = {
8662 .rpc_call_prepare = nfs4_layoutreturn_prepare,
8663 .rpc_call_done = nfs4_layoutreturn_done,
8664 .rpc_release = nfs4_layoutreturn_release,
8665};
8666
Peng Tao6c166052014-11-17 09:30:40 +08008667int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync)
Benny Halevycbe82602011-05-22 19:52:37 +03008668{
8669 struct rpc_task *task;
8670 struct rpc_message msg = {
8671 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN],
8672 .rpc_argp = &lrp->args,
8673 .rpc_resp = &lrp->res,
Trond Myklebust95560002013-05-20 10:43:47 -04008674 .rpc_cred = lrp->cred,
Benny Halevycbe82602011-05-22 19:52:37 +03008675 };
8676 struct rpc_task_setup task_setup_data = {
Andy Adamson1771c572013-07-22 12:42:05 -04008677 .rpc_client = NFS_SERVER(lrp->args.inode)->client,
Benny Halevycbe82602011-05-22 19:52:37 +03008678 .rpc_message = &msg,
8679 .callback_ops = &nfs4_layoutreturn_call_ops,
8680 .callback_data = lrp,
8681 };
Peng Tao6c166052014-11-17 09:30:40 +08008682 int status = 0;
Benny Halevycbe82602011-05-22 19:52:37 +03008683
Andrew Elble99ade3c2015-12-02 09:39:51 -05008684 nfs4_state_protect(NFS_SERVER(lrp->args.inode)->nfs_client,
8685 NFS_SP4_MACH_CRED_PNFS_CLEANUP,
8686 &task_setup_data.rpc_client, &msg);
8687
Benny Halevycbe82602011-05-22 19:52:37 +03008688 dprintk("--> %s\n", __func__);
Trond Myklebust5a0ec8ac2015-02-05 16:35:16 -05008689 if (!sync) {
8690 lrp->inode = nfs_igrab_and_active(lrp->args.inode);
8691 if (!lrp->inode) {
8692 nfs4_layoutreturn_release(lrp);
8693 return -EAGAIN;
8694 }
8695 task_setup_data.flags |= RPC_TASK_ASYNC;
8696 }
Chuck Levera9c92d62013-08-09 12:48:18 -04008697 nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
Benny Halevycbe82602011-05-22 19:52:37 +03008698 task = rpc_run_task(&task_setup_data);
8699 if (IS_ERR(task))
8700 return PTR_ERR(task);
Trond Myklebust5a0ec8ac2015-02-05 16:35:16 -05008701 if (sync)
8702 status = task->tk_status;
Olga Kornievskaia48c95792015-11-24 13:29:41 -05008703 trace_nfs4_layoutreturn(lrp->args.inode, &lrp->args.stateid, status);
Benny Halevycbe82602011-05-22 19:52:37 +03008704 dprintk("<-- %s status=%d\n", __func__, status);
8705 rpc_put_task(task);
8706 return status;
8707}
8708
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008709static int
Trond Myklebustcd5875f2013-05-20 11:42:54 -04008710_nfs4_proc_getdeviceinfo(struct nfs_server *server,
8711 struct pnfs_device *pdev,
8712 struct rpc_cred *cred)
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008713{
8714 struct nfs4_getdeviceinfo_args args = {
8715 .pdev = pdev,
Trond Myklebust4e590802015-03-09 14:01:25 -04008716 .notify_types = NOTIFY_DEVICEID4_CHANGE |
8717 NOTIFY_DEVICEID4_DELETE,
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008718 };
8719 struct nfs4_getdeviceinfo_res res = {
8720 .pdev = pdev,
8721 };
8722 struct rpc_message msg = {
8723 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO],
8724 .rpc_argp = &args,
8725 .rpc_resp = &res,
Trond Myklebustcd5875f2013-05-20 11:42:54 -04008726 .rpc_cred = cred,
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008727 };
8728 int status;
8729
8730 dprintk("--> %s\n", __func__);
Bryan Schumaker7c513052011-03-24 17:12:24 +00008731 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Trond Myklebust4e590802015-03-09 14:01:25 -04008732 if (res.notification & ~args.notify_types)
8733 dprintk("%s: unsupported notification\n", __func__);
Trond Myklebustdf526992015-03-09 14:48:32 -04008734 if (res.notification != args.notify_types)
8735 pdev->nocache = 1;
Trond Myklebust4e590802015-03-09 14:01:25 -04008736
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008737 dprintk("<-- %s status=%d\n", __func__, status);
8738
8739 return status;
8740}
8741
Trond Myklebustcd5875f2013-05-20 11:42:54 -04008742int nfs4_proc_getdeviceinfo(struct nfs_server *server,
8743 struct pnfs_device *pdev,
8744 struct rpc_cred *cred)
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008745{
8746 struct nfs4_exception exception = { };
8747 int err;
8748
8749 do {
8750 err = nfs4_handle_exception(server,
Trond Myklebustcd5875f2013-05-20 11:42:54 -04008751 _nfs4_proc_getdeviceinfo(server, pdev, cred),
Andy Adamsonb1f69b72010-10-20 00:18:03 -04008752 &exception);
8753 } while (exception.retry);
8754 return err;
8755}
8756EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo);
8757
Andy Adamson863a3c62011-03-23 13:27:54 +00008758static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
8759{
8760 struct nfs4_layoutcommit_data *data = calldata;
8761 struct nfs_server *server = NFS_SERVER(data->args.inode);
8762
Anna Schumaker7981c8a2017-01-10 11:39:53 -05008763 nfs4_setup_sequence(server->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04008764 &data->args.seq_args,
8765 &data->res.seq_res,
8766 task);
Andy Adamson863a3c62011-03-23 13:27:54 +00008767}
8768
8769static void
8770nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
8771{
8772 struct nfs4_layoutcommit_data *data = calldata;
8773 struct nfs_server *server = NFS_SERVER(data->args.inode);
8774
Trond Myklebust6ba7db32012-10-22 20:07:20 -04008775 if (!nfs41_sequence_done(task, &data->res.seq_res))
Andy Adamson863a3c62011-03-23 13:27:54 +00008776 return;
8777
8778 switch (task->tk_status) { /* Just ignore these failures */
Trond Myklebuste59d27e2012-03-27 18:22:19 -04008779 case -NFS4ERR_DELEG_REVOKED: /* layout was recalled */
8780 case -NFS4ERR_BADIOMODE: /* no IOMODE_RW layout for range */
8781 case -NFS4ERR_BADLAYOUT: /* no layout */
8782 case -NFS4ERR_GRACE: /* loca_recalim always false */
Andy Adamson863a3c62011-03-23 13:27:54 +00008783 task->tk_status = 0;
Trond Myklebuste59d27e2012-03-27 18:22:19 -04008784 case 0:
Trond Myklebuste59d27e2012-03-27 18:22:19 -04008785 break;
8786 default:
NeilBrown8478eaa2014-09-18 16:09:27 +10008787 if (nfs4_async_handle_error(task, server, NULL, NULL) == -EAGAIN) {
Trond Myklebuste59d27e2012-03-27 18:22:19 -04008788 rpc_restart_call_prepare(task);
8789 return;
8790 }
8791 }
Andy Adamson863a3c62011-03-23 13:27:54 +00008792}
8793
8794static void nfs4_layoutcommit_release(void *calldata)
8795{
8796 struct nfs4_layoutcommit_data *data = calldata;
8797
Andy Adamsondb29c082011-07-30 20:52:38 -04008798 pnfs_cleanup_layoutcommit(data);
Trond Myklebustd8c951c2014-01-13 12:08:11 -05008799 nfs_post_op_update_inode_force_wcc(data->args.inode,
8800 data->res.fattr);
Andy Adamson863a3c62011-03-23 13:27:54 +00008801 put_rpccred(data->cred);
Trond Myklebust472e2592015-02-05 16:50:30 -05008802 nfs_iput_and_deactive(data->inode);
Andy Adamson863a3c62011-03-23 13:27:54 +00008803 kfree(data);
8804}
8805
8806static const struct rpc_call_ops nfs4_layoutcommit_ops = {
8807 .rpc_call_prepare = nfs4_layoutcommit_prepare,
8808 .rpc_call_done = nfs4_layoutcommit_done,
8809 .rpc_release = nfs4_layoutcommit_release,
8810};
8811
8812int
Andy Adamsonef311532011-03-12 02:58:10 -05008813nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
Andy Adamson863a3c62011-03-23 13:27:54 +00008814{
8815 struct rpc_message msg = {
8816 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTCOMMIT],
8817 .rpc_argp = &data->args,
8818 .rpc_resp = &data->res,
8819 .rpc_cred = data->cred,
8820 };
8821 struct rpc_task_setup task_setup_data = {
8822 .task = &data->task,
8823 .rpc_client = NFS_CLIENT(data->args.inode),
8824 .rpc_message = &msg,
8825 .callback_ops = &nfs4_layoutcommit_ops,
8826 .callback_data = data,
Andy Adamson863a3c62011-03-23 13:27:54 +00008827 };
8828 struct rpc_task *task;
8829 int status = 0;
8830
Kinglong Meeb4839eb2015-07-01 12:00:13 +08008831 dprintk("NFS: initiating layoutcommit call. sync %d "
8832 "lbw: %llu inode %lu\n", sync,
Andy Adamson863a3c62011-03-23 13:27:54 +00008833 data->args.lastbytewritten,
8834 data->args.inode->i_ino);
8835
Trond Myklebust472e2592015-02-05 16:50:30 -05008836 if (!sync) {
8837 data->inode = nfs_igrab_and_active(data->args.inode);
8838 if (data->inode == NULL) {
8839 nfs4_layoutcommit_release(data);
8840 return -EAGAIN;
8841 }
8842 task_setup_data.flags = RPC_TASK_ASYNC;
8843 }
Chuck Levera9c92d62013-08-09 12:48:18 -04008844 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
Andy Adamson863a3c62011-03-23 13:27:54 +00008845 task = rpc_run_task(&task_setup_data);
8846 if (IS_ERR(task))
8847 return PTR_ERR(task);
Trond Myklebust472e2592015-02-05 16:50:30 -05008848 if (sync)
8849 status = task->tk_status;
Olga Kornievskaia48c95792015-11-24 13:29:41 -05008850 trace_nfs4_layoutcommit(data->args.inode, &data->args.stateid, status);
Andy Adamson863a3c62011-03-23 13:27:54 +00008851 dprintk("%s: status %d\n", __func__, status);
8852 rpc_put_task(task);
8853 return status;
8854}
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008855
Andy Adamson97431202013-08-08 10:57:56 -04008856/**
8857 * Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
8858 * possible) as per RFC3530bis and RFC5661 Security Considerations sections
8859 */
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008860static int
8861_nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04008862 struct nfs_fsinfo *info,
8863 struct nfs4_secinfo_flavors *flavors, bool use_integrity)
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008864{
8865 struct nfs41_secinfo_no_name_args args = {
8866 .style = SECINFO_STYLE_CURRENT_FH,
8867 };
8868 struct nfs4_secinfo_res res = {
8869 .flavors = flavors,
8870 };
8871 struct rpc_message msg = {
8872 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO_NO_NAME],
8873 .rpc_argp = &args,
8874 .rpc_resp = &res,
8875 };
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04008876 struct rpc_clnt *clnt = server->client;
Weston Andros Adamson7cb852d2013-09-10 18:44:31 -04008877 struct rpc_cred *cred = NULL;
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04008878 int status;
8879
8880 if (use_integrity) {
8881 clnt = server->nfs_client->cl_rpcclient;
Weston Andros Adamson7cb852d2013-09-10 18:44:31 -04008882 cred = nfs4_get_clid_cred(server->nfs_client);
8883 msg.rpc_cred = cred;
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04008884 }
8885
8886 dprintk("--> %s\n", __func__);
8887 status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
8888 &res.seq_res, 0);
8889 dprintk("<-- %s status=%d\n", __func__, status);
8890
Weston Andros Adamson7cb852d2013-09-10 18:44:31 -04008891 if (cred)
8892 put_rpccred(cred);
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04008893
8894 return status;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008895}
8896
8897static int
8898nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
8899 struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
8900{
8901 struct nfs4_exception exception = { };
8902 int err;
8903 do {
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04008904 /* first try using integrity protection */
8905 err = -NFS4ERR_WRONGSEC;
8906
8907 /* try to use integrity protection with machine cred */
8908 if (_nfs4_is_integrity_protected(server->nfs_client))
8909 err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
8910 flavors, true);
8911
8912 /*
8913 * if unable to use integrity protection, or SECINFO with
8914 * integrity protection returns NFS4ERR_WRONGSEC (which is
8915 * disallowed by spec, but exists in deployed servers) use
8916 * the current filesystem's rpc_client and the user cred.
8917 */
8918 if (err == -NFS4ERR_WRONGSEC)
8919 err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
8920 flavors, false);
8921
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008922 switch (err) {
8923 case 0:
8924 case -NFS4ERR_WRONGSEC:
Weston Andros Adamson78b19ba2014-01-13 16:54:45 -05008925 case -ENOTSUPP:
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04008926 goto out;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008927 default:
8928 err = nfs4_handle_exception(server, err, &exception);
8929 }
8930 } while (exception.retry);
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04008931out:
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008932 return err;
8933}
8934
8935static int
8936nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
8937 struct nfs_fsinfo *info)
8938{
8939 int err;
8940 struct page *page;
Anna Schumaker367156d2013-09-25 17:02:48 -04008941 rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008942 struct nfs4_secinfo_flavors *flavors;
Weston Andros Adamson58a8cf12013-09-24 13:58:02 -04008943 struct nfs4_secinfo4 *secinfo;
8944 int i;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008945
8946 page = alloc_page(GFP_KERNEL);
8947 if (!page) {
8948 err = -ENOMEM;
8949 goto out;
8950 }
8951
8952 flavors = page_address(page);
8953 err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
8954
8955 /*
8956 * Fall back on "guess and check" method if
8957 * the server doesn't support SECINFO_NO_NAME
8958 */
Weston Andros Adamson78b19ba2014-01-13 16:54:45 -05008959 if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008960 err = nfs4_find_root_sec(server, fhandle, info);
8961 goto out_freepage;
8962 }
8963 if (err)
8964 goto out_freepage;
8965
Weston Andros Adamson58a8cf12013-09-24 13:58:02 -04008966 for (i = 0; i < flavors->num_flavors; i++) {
8967 secinfo = &flavors->flavors[i];
8968
8969 switch (secinfo->flavor) {
8970 case RPC_AUTH_NULL:
8971 case RPC_AUTH_UNIX:
8972 case RPC_AUTH_GSS:
8973 flavor = rpcauth_get_pseudoflavor(secinfo->flavor,
8974 &secinfo->flavor_info);
8975 break;
8976 default:
8977 flavor = RPC_AUTH_MAXFLAVOR;
8978 break;
8979 }
8980
Weston Andros Adamson4d4b69d2013-10-18 15:15:19 -04008981 if (!nfs_auth_info_match(&server->auth_info, flavor))
8982 flavor = RPC_AUTH_MAXFLAVOR;
8983
Weston Andros Adamson58a8cf12013-09-24 13:58:02 -04008984 if (flavor != RPC_AUTH_MAXFLAVOR) {
8985 err = nfs4_lookup_root_sec(server, fhandle,
8986 info, flavor);
8987 if (!err)
8988 break;
8989 }
8990 }
8991
8992 if (flavor == RPC_AUTH_MAXFLAVOR)
8993 err = -EPERM;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04008994
8995out_freepage:
8996 put_page(page);
8997 if (err == -EACCES)
8998 return -EPERM;
8999out:
9000 return err;
9001}
Bryan Schumaker1cab0652012-01-31 10:39:29 -05009002
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009003static int _nfs41_test_stateid(struct nfs_server *server,
9004 nfs4_stateid *stateid,
9005 struct rpc_cred *cred)
Bryan Schumaker7d974792011-06-02 14:59:08 -04009006{
9007 int status;
9008 struct nfs41_test_stateid_args args = {
Bryan Schumaker1cab0652012-01-31 10:39:29 -05009009 .stateid = stateid,
Bryan Schumaker7d974792011-06-02 14:59:08 -04009010 };
9011 struct nfs41_test_stateid_res res;
9012 struct rpc_message msg = {
9013 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID],
9014 .rpc_argp = &args,
9015 .rpc_resp = &res,
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009016 .rpc_cred = cred,
Bryan Schumaker7d974792011-06-02 14:59:08 -04009017 };
Weston Andros Adamson3787d502013-08-13 16:37:36 -04009018 struct rpc_clnt *rpc_client = server->client;
9019
9020 nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
9021 &rpc_client, &msg);
Bryan Schumaker1cab0652012-01-31 10:39:29 -05009022
Chuck Lever38527b12012-07-11 16:30:23 -04009023 dprintk("NFS call test_stateid %p\n", stateid);
Chuck Levera9c92d62013-08-09 12:48:18 -04009024 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04009025 nfs4_set_sequence_privileged(&args.seq_args);
Weston Andros Adamson3787d502013-08-13 16:37:36 -04009026 status = nfs4_call_sync_sequence(rpc_client, server, &msg,
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04009027 &args.seq_args, &res.seq_res);
Chuck Lever38527b12012-07-11 16:30:23 -04009028 if (status != NFS_OK) {
9029 dprintk("NFS reply test_stateid: failed, %d\n", status);
Chuck Lever377e5072012-07-11 16:29:45 -04009030 return status;
Chuck Lever38527b12012-07-11 16:30:23 -04009031 }
9032 dprintk("NFS reply test_stateid: succeeded, %d\n", -res.status);
Chuck Lever377e5072012-07-11 16:29:45 -04009033 return -res.status;
Bryan Schumaker7d974792011-06-02 14:59:08 -04009034}
9035
Trond Myklebust43912bb2016-09-22 13:38:56 -04009036static void nfs4_handle_delay_or_session_error(struct nfs_server *server,
9037 int err, struct nfs4_exception *exception)
9038{
9039 exception->retry = 0;
9040 switch(err) {
9041 case -NFS4ERR_DELAY:
Trond Myklebust76e8a1b2016-09-22 13:39:19 -04009042 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebust43912bb2016-09-22 13:38:56 -04009043 nfs4_handle_exception(server, err, exception);
9044 break;
9045 case -NFS4ERR_BADSESSION:
9046 case -NFS4ERR_BADSLOT:
9047 case -NFS4ERR_BAD_HIGH_SLOT:
9048 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
9049 case -NFS4ERR_DEADSESSION:
9050 nfs4_do_handle_exception(server, err, exception);
9051 }
9052}
9053
Chuck Lever38527b12012-07-11 16:30:23 -04009054/**
9055 * nfs41_test_stateid - perform a TEST_STATEID operation
9056 *
9057 * @server: server / transport on which to perform the operation
9058 * @stateid: state ID to test
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009059 * @cred: credential
Chuck Lever38527b12012-07-11 16:30:23 -04009060 *
9061 * Returns NFS_OK if the server recognizes that "stateid" is valid.
9062 * Otherwise a negative NFS4ERR value is returned if the operation
9063 * failed or the state ID is not currently valid.
9064 */
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009065static int nfs41_test_stateid(struct nfs_server *server,
9066 nfs4_stateid *stateid,
9067 struct rpc_cred *cred)
Bryan Schumaker7d974792011-06-02 14:59:08 -04009068{
9069 struct nfs4_exception exception = { };
9070 int err;
9071 do {
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009072 err = _nfs41_test_stateid(server, stateid, cred);
Trond Myklebust43912bb2016-09-22 13:38:56 -04009073 nfs4_handle_delay_or_session_error(server, err, &exception);
Bryan Schumaker7d974792011-06-02 14:59:08 -04009074 } while (exception.retry);
9075 return err;
9076}
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009077
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009078struct nfs_free_stateid_data {
9079 struct nfs_server *server;
9080 struct nfs41_free_stateid_args args;
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009081 struct nfs41_free_stateid_res res;
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009082};
9083
9084static void nfs41_free_stateid_prepare(struct rpc_task *task, void *calldata)
9085{
9086 struct nfs_free_stateid_data *data = calldata;
Anna Schumaker7981c8a2017-01-10 11:39:53 -05009087 nfs4_setup_sequence(data->server->nfs_client,
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009088 &data->args.seq_args,
9089 &data->res.seq_res,
9090 task);
9091}
9092
9093static void nfs41_free_stateid_done(struct rpc_task *task, void *calldata)
9094{
9095 struct nfs_free_stateid_data *data = calldata;
9096
9097 nfs41_sequence_done(task, &data->res.seq_res);
9098
9099 switch (task->tk_status) {
9100 case -NFS4ERR_DELAY:
NeilBrown8478eaa2014-09-18 16:09:27 +10009101 if (nfs4_async_handle_error(task, data->server, NULL, NULL) == -EAGAIN)
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009102 rpc_restart_call_prepare(task);
9103 }
9104}
9105
9106static void nfs41_free_stateid_release(void *calldata)
9107{
9108 kfree(calldata);
9109}
9110
Trond Myklebust17f26b12013-08-21 15:48:42 -04009111static const struct rpc_call_ops nfs41_free_stateid_ops = {
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009112 .rpc_call_prepare = nfs41_free_stateid_prepare,
9113 .rpc_call_done = nfs41_free_stateid_done,
9114 .rpc_release = nfs41_free_stateid_release,
9115};
9116
9117static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009118 const nfs4_stateid *stateid,
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009119 struct rpc_cred *cred,
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009120 bool privileged)
9121{
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009122 struct rpc_message msg = {
9123 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID],
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009124 .rpc_cred = cred,
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009125 };
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009126 struct rpc_task_setup task_setup = {
9127 .rpc_client = server->client,
9128 .rpc_message = &msg,
9129 .callback_ops = &nfs41_free_stateid_ops,
9130 .flags = RPC_TASK_ASYNC,
9131 };
9132 struct nfs_free_stateid_data *data;
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009133
Weston Andros Adamson3787d502013-08-13 16:37:36 -04009134 nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
9135 &task_setup.rpc_client, &msg);
9136
Chuck Lever38527b12012-07-11 16:30:23 -04009137 dprintk("NFS call free_stateid %p\n", stateid);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009138 data = kmalloc(sizeof(*data), GFP_NOFS);
9139 if (!data)
9140 return ERR_PTR(-ENOMEM);
9141 data->server = server;
9142 nfs4_stateid_copy(&data->args.stateid, stateid);
9143
9144 task_setup.callback_data = data;
9145
9146 msg.rpc_argp = &data->args;
9147 msg.rpc_resp = &data->res;
Trond Myklebust76e8a1b2016-09-22 13:39:19 -04009148 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009149 if (privileged)
9150 nfs4_set_sequence_privileged(&data->args.seq_args);
9151
9152 return rpc_run_task(&task_setup);
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009153}
9154
Chuck Lever38527b12012-07-11 16:30:23 -04009155/**
9156 * nfs41_free_stateid - perform a FREE_STATEID operation
9157 *
9158 * @server: server / transport on which to perform the operation
9159 * @stateid: state ID to release
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009160 * @cred: credential
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009161 * @is_recovery: set to true if this call needs to be privileged
Chuck Lever38527b12012-07-11 16:30:23 -04009162 *
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009163 * Note: this function is always asynchronous.
Chuck Lever38527b12012-07-11 16:30:23 -04009164 */
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009165static int nfs41_free_stateid(struct nfs_server *server,
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009166 const nfs4_stateid *stateid,
9167 struct rpc_cred *cred,
9168 bool is_recovery)
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009169{
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009170 struct rpc_task *task;
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009171
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009172 task = _nfs41_free_stateid(server, stateid, cred, is_recovery);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009173 if (IS_ERR(task))
9174 return PTR_ERR(task);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009175 rpc_put_task(task);
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009176 return 0;
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009177}
Trond Myklebust36281ca2012-03-04 18:13:56 -05009178
Jeff Laytonf1cdae82014-05-01 06:28:47 -04009179static void
9180nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009181{
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009182 struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009183
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009184 nfs41_free_stateid(server, &lsp->ls_stateid, cred, false);
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009185 nfs4_free_lock_state(server, lsp);
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009186}
9187
Trond Myklebust36281ca2012-03-04 18:13:56 -05009188static bool nfs41_match_stateid(const nfs4_stateid *s1,
9189 const nfs4_stateid *s2)
9190{
Trond Myklebust93b717f2016-05-16 17:42:43 -04009191 if (s1->type != s2->type)
9192 return false;
9193
Trond Myklebust2d2f24a2012-03-04 18:13:57 -05009194 if (memcmp(s1->other, s2->other, sizeof(s1->other)) != 0)
Trond Myklebust36281ca2012-03-04 18:13:56 -05009195 return false;
9196
Trond Myklebust2d2f24a2012-03-04 18:13:57 -05009197 if (s1->seqid == s2->seqid)
Trond Myklebust36281ca2012-03-04 18:13:56 -05009198 return true;
Trond Myklebust36281ca2012-03-04 18:13:56 -05009199
Anna Schumaker045c5512017-01-11 16:59:48 -05009200 return s1->seqid == 0 || s2->seqid == 0;
Trond Myklebust36281ca2012-03-04 18:13:56 -05009201}
9202
Andy Adamson557134a2009-04-01 09:21:53 -04009203#endif /* CONFIG_NFS_V4_1 */
9204
Trond Myklebust36281ca2012-03-04 18:13:56 -05009205static bool nfs4_match_stateid(const nfs4_stateid *s1,
9206 const nfs4_stateid *s2)
9207{
Trond Myklebustf597c532012-03-04 18:13:56 -05009208 return nfs4_stateid_match(s1, s2);
Trond Myklebust36281ca2012-03-04 18:13:56 -05009209}
9210
9211
Trond Myklebust17280172012-03-11 13:11:00 -04009212static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
Trond Myklebust7eff03a2008-12-23 15:21:43 -05009213 .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
Trond Myklebustb79a4a12008-12-23 15:21:41 -05009214 .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009215 .recover_open = nfs4_open_reclaim,
9216 .recover_lock = nfs4_lock_reclaim,
Andy Adamson591d71c2009-04-01 09:22:47 -04009217 .establish_clid = nfs4_init_clientid,
Chuck Lever05f4c352012-09-14 17:24:32 -04009218 .detect_trunking = nfs40_discover_server_trunking,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009219};
9220
Andy Adamson591d71c2009-04-01 09:22:47 -04009221#if defined(CONFIG_NFS_V4_1)
Trond Myklebust17280172012-03-11 13:11:00 -04009222static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
Andy Adamson591d71c2009-04-01 09:22:47 -04009223 .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
9224 .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
9225 .recover_open = nfs4_open_reclaim,
9226 .recover_lock = nfs4_lock_reclaim,
Andy Adamson4d643d12009-12-04 15:52:24 -05009227 .establish_clid = nfs41_init_clientid,
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009228 .reclaim_complete = nfs41_proc_reclaim_complete,
Chuck Lever05f4c352012-09-14 17:24:32 -04009229 .detect_trunking = nfs41_discover_server_trunking,
Andy Adamson591d71c2009-04-01 09:22:47 -04009230};
9231#endif /* CONFIG_NFS_V4_1 */
9232
Trond Myklebust17280172012-03-11 13:11:00 -04009233static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
Trond Myklebust7eff03a2008-12-23 15:21:43 -05009234 .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
Trond Myklebustb79a4a12008-12-23 15:21:41 -05009235 .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
Trond Myklebust4dfd4f72014-10-17 15:10:25 +03009236 .recover_open = nfs40_open_expired,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009237 .recover_lock = nfs4_lock_expired,
Andy Adamson591d71c2009-04-01 09:22:47 -04009238 .establish_clid = nfs4_init_clientid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009239};
9240
Andy Adamson591d71c2009-04-01 09:22:47 -04009241#if defined(CONFIG_NFS_V4_1)
Trond Myklebust17280172012-03-11 13:11:00 -04009242static const struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
Andy Adamson591d71c2009-04-01 09:22:47 -04009243 .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
9244 .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
Bryan Schumakerf062eb62011-06-02 14:59:10 -04009245 .recover_open = nfs41_open_expired,
9246 .recover_lock = nfs41_lock_expired,
Andy Adamson4d643d12009-12-04 15:52:24 -05009247 .establish_clid = nfs41_init_clientid,
Andy Adamson591d71c2009-04-01 09:22:47 -04009248};
9249#endif /* CONFIG_NFS_V4_1 */
9250
Trond Myklebust17280172012-03-11 13:11:00 -04009251static const struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
Benny Halevy29fba382009-04-01 09:22:44 -04009252 .sched_state_renewal = nfs4_proc_async_renew,
Andy Adamsona7b72102009-04-01 09:22:46 -04009253 .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked,
Benny Halevy8e69514f2009-04-01 09:22:45 -04009254 .renew_lease = nfs4_proc_renew,
Benny Halevy29fba382009-04-01 09:22:44 -04009255};
9256
9257#if defined(CONFIG_NFS_V4_1)
Trond Myklebust17280172012-03-11 13:11:00 -04009258static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
Benny Halevy29fba382009-04-01 09:22:44 -04009259 .sched_state_renewal = nfs41_proc_async_sequence,
Andy Adamsona7b72102009-04-01 09:22:46 -04009260 .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked,
Benny Halevy8e69514f2009-04-01 09:22:45 -04009261 .renew_lease = nfs4_proc_sequence,
Benny Halevy29fba382009-04-01 09:22:44 -04009262};
9263#endif
9264
Chuck Leverec011fe2013-10-17 14:12:39 -04009265static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = {
Chuck Leverb03d7352013-10-17 14:12:50 -04009266 .get_locations = _nfs40_proc_get_locations,
Chuck Lever44c99932013-10-17 14:13:30 -04009267 .fsid_present = _nfs40_proc_fsid_present,
Chuck Leverec011fe2013-10-17 14:12:39 -04009268};
9269
9270#if defined(CONFIG_NFS_V4_1)
9271static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = {
Chuck Leverb03d7352013-10-17 14:12:50 -04009272 .get_locations = _nfs41_proc_get_locations,
Chuck Lever44c99932013-10-17 14:13:30 -04009273 .fsid_present = _nfs41_proc_fsid_present,
Chuck Leverec011fe2013-10-17 14:12:39 -04009274};
9275#endif /* CONFIG_NFS_V4_1 */
9276
Trond Myklebust97dc1352010-06-16 09:52:26 -04009277static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
9278 .minor_version = 0,
Trond Myklebust39c6daa2013-03-15 16:11:57 -04009279 .init_caps = NFS_CAP_READDIRPLUS
9280 | NFS_CAP_ATOMIC_OPEN
Trond Myklebust39c6daa2013-03-15 16:11:57 -04009281 | NFS_CAP_POSIX_LOCK,
Chuck Leverabf79bb2013-08-09 12:49:11 -04009282 .init_client = nfs40_init_client,
9283 .shutdown_client = nfs40_shutdown_client,
Trond Myklebust36281ca2012-03-04 18:13:56 -05009284 .match_stateid = nfs4_match_stateid,
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009285 .find_root_sec = nfs4_find_root_sec,
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009286 .free_lock_state = nfs4_release_lockowner,
Trond Myklebust45870d62016-09-22 13:38:59 -04009287 .test_and_free_expired = nfs40_test_and_free_expired_stateid,
Trond Myklebust63f5f792015-01-23 19:19:25 -05009288 .alloc_seqid = nfs_alloc_seqid,
Chuck Lever9915ea72013-08-09 12:48:27 -04009289 .call_sync_ops = &nfs40_call_sync_ops,
Trond Myklebustc48f4f32010-06-16 09:52:27 -04009290 .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
9291 .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
9292 .state_renewal_ops = &nfs40_state_renewal_ops,
Chuck Leverec011fe2013-10-17 14:12:39 -04009293 .mig_recovery_ops = &nfs40_mig_recovery_ops,
Trond Myklebust97dc1352010-06-16 09:52:26 -04009294};
9295
9296#if defined(CONFIG_NFS_V4_1)
Trond Myklebust63f5f792015-01-23 19:19:25 -05009297static struct nfs_seqid *
9298nfs_alloc_no_seqid(struct nfs_seqid_counter *arg1, gfp_t arg2)
9299{
9300 return NULL;
9301}
9302
Trond Myklebust97dc1352010-06-16 09:52:26 -04009303static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
9304 .minor_version = 1,
Trond Myklebust39c6daa2013-03-15 16:11:57 -04009305 .init_caps = NFS_CAP_READDIRPLUS
9306 | NFS_CAP_ATOMIC_OPEN
Trond Myklebust3b664862013-03-17 15:31:15 -04009307 | NFS_CAP_POSIX_LOCK
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04009308 | NFS_CAP_STATEID_NFSV41
Anna Schumakere9831202014-10-22 15:53:10 -04009309 | NFS_CAP_ATOMIC_OPEN_V1,
Chuck Leverabf79bb2013-08-09 12:49:11 -04009310 .init_client = nfs41_init_client,
9311 .shutdown_client = nfs41_shutdown_client,
Trond Myklebust36281ca2012-03-04 18:13:56 -05009312 .match_stateid = nfs41_match_stateid,
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009313 .find_root_sec = nfs41_find_root_sec,
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009314 .free_lock_state = nfs41_free_lock_state,
Trond Myklebust45870d62016-09-22 13:38:59 -04009315 .test_and_free_expired = nfs41_test_and_free_expired_stateid,
Trond Myklebust63f5f792015-01-23 19:19:25 -05009316 .alloc_seqid = nfs_alloc_no_seqid,
Andy Adamson04fa2c62016-09-09 09:22:29 -04009317 .session_trunk = nfs4_test_session_trunk,
Chuck Lever9915ea72013-08-09 12:48:27 -04009318 .call_sync_ops = &nfs41_call_sync_ops,
Trond Myklebustc48f4f32010-06-16 09:52:27 -04009319 .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
9320 .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
9321 .state_renewal_ops = &nfs41_state_renewal_ops,
Chuck Leverec011fe2013-10-17 14:12:39 -04009322 .mig_recovery_ops = &nfs41_mig_recovery_ops,
Trond Myklebust97dc1352010-06-16 09:52:26 -04009323};
9324#endif
9325
Steve Dickson42c2c422013-05-22 12:50:38 -04009326#if defined(CONFIG_NFS_V4_2)
9327static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
9328 .minor_version = 2,
Bryan Schumaker70173102013-06-19 13:41:43 -04009329 .init_caps = NFS_CAP_READDIRPLUS
9330 | NFS_CAP_ATOMIC_OPEN
Bryan Schumaker70173102013-06-19 13:41:43 -04009331 | NFS_CAP_POSIX_LOCK
9332 | NFS_CAP_STATEID_NFSV41
Anna Schumakere9831202014-10-22 15:53:10 -04009333 | NFS_CAP_ATOMIC_OPEN_V1
Anna Schumakerf4ac1672014-11-25 13:18:15 -05009334 | NFS_CAP_ALLOCATE
Anna Schumaker2e724482013-05-21 16:53:03 -04009335 | NFS_CAP_COPY
Anna Schumaker624bd5b2014-11-25 13:18:16 -05009336 | NFS_CAP_DEALLOCATE
Trond Myklebust6c5a0d82015-06-27 11:45:46 -04009337 | NFS_CAP_SEEK
Peng Taoe5341f32015-09-26 02:24:35 +08009338 | NFS_CAP_LAYOUTSTATS
9339 | NFS_CAP_CLONE,
Chuck Leverabf79bb2013-08-09 12:49:11 -04009340 .init_client = nfs41_init_client,
9341 .shutdown_client = nfs41_shutdown_client,
Steve Dickson42c2c422013-05-22 12:50:38 -04009342 .match_stateid = nfs41_match_stateid,
9343 .find_root_sec = nfs41_find_root_sec,
Bryan Schumaker70173102013-06-19 13:41:43 -04009344 .free_lock_state = nfs41_free_lock_state,
Chuck Lever9915ea72013-08-09 12:48:27 -04009345 .call_sync_ops = &nfs41_call_sync_ops,
Trond Myklebust45870d62016-09-22 13:38:59 -04009346 .test_and_free_expired = nfs41_test_and_free_expired_stateid,
Trond Myklebust63f5f792015-01-23 19:19:25 -05009347 .alloc_seqid = nfs_alloc_no_seqid,
Andy Adamson04fa2c62016-09-09 09:22:29 -04009348 .session_trunk = nfs4_test_session_trunk,
Steve Dickson42c2c422013-05-22 12:50:38 -04009349 .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
9350 .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
9351 .state_renewal_ops = &nfs41_state_renewal_ops,
Kinglong Mee18e3b732015-08-15 21:52:10 +08009352 .mig_recovery_ops = &nfs41_mig_recovery_ops,
Steve Dickson42c2c422013-05-22 12:50:38 -04009353};
9354#endif
9355
Trond Myklebust97dc1352010-06-16 09:52:26 -04009356const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
9357 [0] = &nfs_v4_0_minor_ops,
9358#if defined(CONFIG_NFS_V4_1)
9359 [1] = &nfs_v4_1_minor_ops,
9360#endif
Steve Dickson42c2c422013-05-22 12:50:38 -04009361#if defined(CONFIG_NFS_V4_2)
9362 [2] = &nfs_v4_2_minor_ops,
9363#endif
Trond Myklebust97dc1352010-06-16 09:52:26 -04009364};
9365
Trond Myklebust13997822016-07-24 17:10:52 -04009366static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01009367{
9368 ssize_t error, error2;
9369
9370 error = generic_listxattr(dentry, list, size);
9371 if (error < 0)
9372 return error;
9373 if (list) {
9374 list += error;
9375 size -= error;
9376 }
9377
9378 error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size);
9379 if (error2 < 0)
9380 return error2;
9381 return error + error2;
9382}
9383
Trond Myklebust17f26b12013-08-21 15:48:42 -04009384static const struct inode_operations nfs4_dir_inode_operations = {
Bryan Schumaker73a79702012-07-16 16:39:12 -04009385 .create = nfs_create,
9386 .lookup = nfs_lookup,
9387 .atomic_open = nfs_atomic_open,
9388 .link = nfs_link,
9389 .unlink = nfs_unlink,
9390 .symlink = nfs_symlink,
9391 .mkdir = nfs_mkdir,
9392 .rmdir = nfs_rmdir,
9393 .mknod = nfs_mknod,
9394 .rename = nfs_rename,
9395 .permission = nfs_permission,
9396 .getattr = nfs_getattr,
9397 .setattr = nfs_setattr,
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01009398 .listxattr = nfs4_listxattr,
Bryan Schumaker73a79702012-07-16 16:39:12 -04009399};
9400
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -08009401static const struct inode_operations nfs4_file_inode_operations = {
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00009402 .permission = nfs_permission,
9403 .getattr = nfs_getattr,
9404 .setattr = nfs_setattr,
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01009405 .listxattr = nfs4_listxattr,
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00009406};
9407
David Howells509de812006-08-22 20:06:11 -04009408const struct nfs_rpc_ops nfs_v4_clientops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07009409 .version = 4, /* protocol version */
9410 .dentry_ops = &nfs4_dentry_operations,
9411 .dir_inode_ops = &nfs4_dir_inode_operations,
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00009412 .file_inode_ops = &nfs4_file_inode_operations,
Jeff Layton1788ea62011-11-04 13:31:21 -04009413 .file_ops = &nfs4_file_operations,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009414 .getroot = nfs4_proc_get_root,
Bryan Schumaker281cad42012-04-27 13:27:45 -04009415 .submount = nfs4_submount,
Bryan Schumakerff9099f22012-07-30 16:05:18 -04009416 .try_mount = nfs4_try_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009417 .getattr = nfs4_proc_getattr,
9418 .setattr = nfs4_proc_setattr,
9419 .lookup = nfs4_proc_lookup,
Jeff Layton5b5faaf2017-06-29 06:34:52 -07009420 .lookupp = nfs4_proc_lookupp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009421 .access = nfs4_proc_access,
9422 .readlink = nfs4_proc_readlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009423 .create = nfs4_proc_create,
9424 .remove = nfs4_proc_remove,
9425 .unlink_setup = nfs4_proc_unlink_setup,
Bryan Schumaker34e137c2012-03-19 14:54:41 -04009426 .unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009427 .unlink_done = nfs4_proc_unlink_done,
Jeff Laytond3d41522010-09-17 17:31:57 -04009428 .rename_setup = nfs4_proc_rename_setup,
Bryan Schumakerc6bfa1a2012-03-19 14:54:42 -04009429 .rename_rpc_prepare = nfs4_proc_rename_rpc_prepare,
Jeff Laytond3d41522010-09-17 17:31:57 -04009430 .rename_done = nfs4_proc_rename_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009431 .link = nfs4_proc_link,
9432 .symlink = nfs4_proc_symlink,
9433 .mkdir = nfs4_proc_mkdir,
9434 .rmdir = nfs4_proc_remove,
9435 .readdir = nfs4_proc_readdir,
9436 .mknod = nfs4_proc_mknod,
9437 .statfs = nfs4_proc_statfs,
9438 .fsinfo = nfs4_proc_fsinfo,
9439 .pathconf = nfs4_proc_pathconf,
David Howellse9326dc2006-08-22 20:06:10 -04009440 .set_capabilities = nfs4_server_capabilities,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009441 .decode_dirent = nfs4_decode_dirent,
Anna Schumakera4cdda52014-05-06 09:12:31 -04009442 .pgio_rpc_prepare = nfs4_proc_pgio_rpc_prepare,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009443 .read_setup = nfs4_proc_read_setup,
Trond Myklebustec06c092006-03-20 13:44:27 -05009444 .read_done = nfs4_read_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009445 .write_setup = nfs4_proc_write_setup,
Trond Myklebust788e7a82006-03-20 13:44:27 -05009446 .write_done = nfs4_write_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009447 .commit_setup = nfs4_proc_commit_setup,
Fred Isaman0b7c0152012-04-20 14:47:39 -04009448 .commit_rpc_prepare = nfs4_proc_commit_rpc_prepare,
Trond Myklebust788e7a82006-03-20 13:44:27 -05009449 .commit_done = nfs4_commit_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009450 .lock = nfs4_proc_lock,
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00009451 .clear_acl_cache = nfs4_zap_acl_attr,
Trond Myklebust7fe5c392009-03-19 15:35:50 -04009452 .close_context = nfs4_close_context,
Trond Myklebust2b484292010-09-17 10:56:51 -04009453 .open_context = nfs4_atomic_open,
Bryan Schumaker011e2a72012-06-20 15:53:43 -04009454 .have_delegation = nfs4_have_delegation,
Bryan Schumaker57ec14c2012-06-20 15:53:44 -04009455 .return_delegation = nfs4_inode_return_delegation,
Bryan Schumaker6663ee72012-06-20 15:53:46 -04009456 .alloc_client = nfs4_alloc_client,
Andy Adamson45a52a02011-03-01 01:34:08 +00009457 .init_client = nfs4_init_client,
Bryan Schumakercdb7ece2012-06-20 15:53:45 -04009458 .free_client = nfs4_free_client,
Bryan Schumaker1179acc2012-07-30 16:05:19 -04009459 .create_server = nfs4_create_server,
9460 .clone_server = nfs_clone_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -07009461};
9462
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00009463static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
Andreas Gruenbacher98e9cb52015-12-02 14:44:36 +01009464 .name = XATTR_NAME_NFSV4_ACL,
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00009465 .list = nfs4_xattr_list_nfs4_acl,
9466 .get = nfs4_xattr_get_nfs4_acl,
9467 .set = nfs4_xattr_set_nfs4_acl,
9468};
9469
9470const struct xattr_handler *nfs4_xattr_handlers[] = {
9471 &nfs4_xattr_nfs4_acl_handler,
David Quigleyc9bccef2013-05-22 12:50:45 -04009472#ifdef CONFIG_NFS_V4_SECURITY_LABEL
9473 &nfs4_xattr_nfs4_label_handler,
9474#endif
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00009475 NULL
9476};
9477
Linus Torvalds1da177e2005-04-16 15:20:36 -07009478/*
9479 * Local variables:
9480 * c-basic-offset: 8
9481 * End:
9482 */