blob: f670ff64b31e30f608300f85512e9817598069d8 [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>
Jeff Layton1eb5d982018-01-09 08:21:17 -050057#include <linux/iversion.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Trond Myklebust4ce79712005-06-22 17:16:21 +000059#include "nfs4_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#include "delegation.h"
Trond Myklebust101070c2008-02-19 20:04:23 -050061#include "internal.h"
Chuck Lever006ea732006-03-20 13:44:14 -050062#include "iostat.h"
Andy Adamsonfc931582009-04-01 09:22:31 -040063#include "callback.h"
Andy Adamsonb1f69b72010-10-20 00:18:03 -040064#include "pnfs.h"
Chuck Leverf0920752012-05-21 22:45:41 -040065#include "netns.h"
Anna Schumaker40c64c22015-04-15 13:00:05 -040066#include "nfs4idmap.h"
Trond Myklebust73e39aa2012-11-26 12:49:34 -050067#include "nfs4session.h"
David Howellsde242c02012-12-20 21:52:38 +000068#include "fscache.h"
Frank van der Linden012a2112020-06-23 22:39:03 +000069#include "nfs42.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Trond Myklebustc6d01c62013-08-09 11:51:26 -040071#include "nfs4trace.h"
72
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define NFSDBG_FACILITY NFSDBG_PROC
74
Trond Myklebust30846df2018-04-07 13:44:28 -040075#define NFS4_BITMASK_SZ 3
76
Trond Myklebust2066fe82006-09-15 08:30:46 -040077#define NFS4_POLL_RETRY_MIN (HZ/10)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078#define NFS4_POLL_RETRY_MAX (15*HZ)
79
Tigran Mkrtchyana1d1c4f2016-05-12 11:16:38 +020080/* file attributes which can be mapped to nfs attributes */
81#define NFS4_VALID_ATTRS (ATTR_MODE \
82 | ATTR_UID \
83 | ATTR_GID \
84 | ATTR_SIZE \
85 | ATTR_ATIME \
86 | ATTR_MTIME \
87 | ATTR_CTIME \
88 | ATTR_ATIME_SET \
89 | ATTR_MTIME_SET)
90
Trond Myklebustcdd4e682006-01-03 09:55:12 +010091struct nfs4_opendata;
Alexandros Batsakisb2579572009-12-14 21:27:57 -080092static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070093static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
Chuck Lever81934dd2012-03-01 17:01:57 -050094static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
Trond Myklebusta841b542018-04-07 13:50:59 -040095static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label, struct inode *inode);
NeilBrowna52458b2018-12-03 11:30:31 +110096static int nfs4_do_setattr(struct inode *inode, const struct cred *cred,
Trond Myklebust0ab64e02010-04-16 16:22:51 -040097 struct nfs_fattr *fattr, struct iattr *sattr,
NeilBrown29b59f92016-10-13 15:26:47 +110098 struct nfs_open_context *ctx, struct nfs4_label *ilabel,
David Quigley1775fd32013-05-22 12:50:42 -040099 struct nfs4_label *olabel);
Bryan Schumakerf062eb62011-06-02 14:59:10 -0400100#ifdef CONFIG_NFS_V4_1
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400101static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
NeilBrowna52458b2018-12-03 11:30:31 +1100102 const struct cred *cred,
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400103 struct nfs4_slot *slot,
104 bool is_privileged);
Trond Myklebustab7cb0d2013-05-20 11:20:27 -0400105static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *,
NeilBrowna52458b2018-12-03 11:30:31 +1100106 const struct cred *);
Trond Myklebustf0b0bf82016-09-22 13:39:04 -0400107static int nfs41_free_stateid(struct nfs_server *, const nfs4_stateid *,
NeilBrowna52458b2018-12-03 11:30:31 +1100108 const struct cred *, bool);
Bryan Schumakerf062eb62011-06-02 14:59:10 -0400109#endif
David Quigleyaa9c2662013-05-22 12:50:44 -0400110
111#ifdef CONFIG_NFS_V4_SECURITY_LABEL
112static inline struct nfs4_label *
113nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
114 struct iattr *sattr, struct nfs4_label *label)
115{
116 int err;
117
118 if (label == NULL)
119 return NULL;
120
121 if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL) == 0)
122 return NULL;
123
David Quigleyaa9c2662013-05-22 12:50:44 -0400124 err = security_dentry_init_security(dentry, sattr->ia_mode,
125 &dentry->d_name, (void **)&label->label, &label->len);
126 if (err == 0)
127 return label;
128
129 return NULL;
130}
131static inline void
132nfs4_label_release_security(struct nfs4_label *label)
133{
134 if (label)
135 security_release_secctx(label->label, label->len);
136}
137static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
138{
139 if (label)
140 return server->attr_bitmask;
141
142 return server->attr_bitmask_nl;
143}
144#else
145static inline struct nfs4_label *
146nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
147 struct iattr *sattr, struct nfs4_label *l)
148{ return NULL; }
149static inline void
150nfs4_label_release_security(struct nfs4_label *label)
151{ return; }
152static inline u32 *
153nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
154{ return server->attr_bitmask; }
155#endif
156
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157/* Prevent leaks of NFSv4 errors into userland */
WANG Cong46f72f52008-12-30 16:35:55 -0500158static int nfs4_map_errors(int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159{
Trond Myklebust52567b02009-10-23 14:46:42 -0400160 if (err >= -1000)
161 return err;
162 switch (err) {
163 case -NFS4ERR_RESOURCE:
Weston Andros Adamson30005122013-02-28 20:30:10 -0500164 case -NFS4ERR_LAYOUTTRYLATER:
165 case -NFS4ERR_RECALLCONFLICT:
Trond Myklebust52567b02009-10-23 14:46:42 -0400166 return -EREMOTEIO;
Bryan Schumaker7ebb9312011-03-24 17:12:30 +0000167 case -NFS4ERR_WRONGSEC:
Weston Andros Adamson88975382013-08-13 16:37:38 -0400168 case -NFS4ERR_WRONG_CRED:
Bryan Schumaker7ebb9312011-03-24 17:12:30 +0000169 return -EPERM;
Trond Myklebust3ddeb7c2011-02-22 15:44:31 -0800170 case -NFS4ERR_BADOWNER:
171 case -NFS4ERR_BADNAME:
172 return -EINVAL;
Trond Myklebustfb13bfa2012-05-28 11:36:28 -0400173 case -NFS4ERR_SHARE_DENIED:
174 return -EACCES;
Steve Dicksonf25efd82012-06-06 14:12:07 -0400175 case -NFS4ERR_MINOR_VERS_MISMATCH:
176 return -EPROTONOSUPPORT;
Trond Myklebust6e3cf242013-03-23 15:22:45 -0400177 case -NFS4ERR_FILE_OPEN:
178 return -EBUSY;
Trond Myklebust52567b02009-10-23 14:46:42 -0400179 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 dprintk("%s could not handle NFSv4 error %d\n",
Harvey Harrison3110ff82008-05-02 13:42:44 -0700181 __func__, -err);
Trond Myklebust52567b02009-10-23 14:46:42 -0400182 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 }
Trond Myklebust52567b02009-10-23 14:46:42 -0400184 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185}
186
187/*
188 * This is our standard bitmap for GETATTR requests.
189 */
Trond Myklebust1549210f2012-06-05 09:16:47 -0400190const u32 nfs4_fattr_bitmap[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191 FATTR4_WORD0_TYPE
192 | FATTR4_WORD0_CHANGE
193 | FATTR4_WORD0_SIZE
194 | FATTR4_WORD0_FSID
195 | FATTR4_WORD0_FILEID,
196 FATTR4_WORD1_MODE
197 | FATTR4_WORD1_NUMLINKS
198 | FATTR4_WORD1_OWNER
199 | FATTR4_WORD1_OWNER_GROUP
200 | FATTR4_WORD1_RAWDEV
201 | FATTR4_WORD1_SPACE_USED
202 | FATTR4_WORD1_TIME_ACCESS
203 | FATTR4_WORD1_TIME_METADATA
Anna Schumakerea96d1e2015-04-03 14:35:59 -0400204 | FATTR4_WORD1_TIME_MODIFY
205 | FATTR4_WORD1_MOUNTED_ON_FILEID,
David Quigleyaa9c2662013-05-22 12:50:44 -0400206#ifdef CONFIG_NFS_V4_SECURITY_LABEL
207 FATTR4_WORD2_SECURITY_LABEL
208#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209};
210
Trond Myklebust1549210f2012-06-05 09:16:47 -0400211static const u32 nfs4_pnfs_open_bitmap[3] = {
212 FATTR4_WORD0_TYPE
213 | FATTR4_WORD0_CHANGE
214 | FATTR4_WORD0_SIZE
215 | FATTR4_WORD0_FSID
216 | FATTR4_WORD0_FILEID,
217 FATTR4_WORD1_MODE
218 | FATTR4_WORD1_NUMLINKS
219 | FATTR4_WORD1_OWNER
220 | FATTR4_WORD1_OWNER_GROUP
221 | FATTR4_WORD1_RAWDEV
222 | FATTR4_WORD1_SPACE_USED
223 | FATTR4_WORD1_TIME_ACCESS
224 | FATTR4_WORD1_TIME_METADATA
225 | FATTR4_WORD1_TIME_MODIFY,
226 FATTR4_WORD2_MDSTHRESHOLD
Trond Myklebust95864c92015-12-26 15:06:03 -0500227#ifdef CONFIG_NFS_V4_SECURITY_LABEL
228 | FATTR4_WORD2_SECURITY_LABEL
229#endif
Trond Myklebust1549210f2012-06-05 09:16:47 -0400230};
231
Andy Adamsone23008e2012-10-02 21:07:32 -0400232static const u32 nfs4_open_noattr_bitmap[3] = {
233 FATTR4_WORD0_TYPE
Andy Adamsone23008e2012-10-02 21:07:32 -0400234 | FATTR4_WORD0_FILEID,
235};
236
David Quigleya09df2c2013-05-22 12:50:41 -0400237const u32 nfs4_statfs_bitmap[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 FATTR4_WORD0_FILES_AVAIL
239 | FATTR4_WORD0_FILES_FREE
240 | FATTR4_WORD0_FILES_TOTAL,
241 FATTR4_WORD1_SPACE_AVAIL
242 | FATTR4_WORD1_SPACE_FREE
243 | FATTR4_WORD1_SPACE_TOTAL
244};
245
David Quigleya09df2c2013-05-22 12:50:41 -0400246const u32 nfs4_pathconf_bitmap[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247 FATTR4_WORD0_MAXLINK
248 | FATTR4_WORD0_MAXNAME,
249 0
250};
251
Fred Isamandae100c2011-07-30 20:52:37 -0400252const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 | FATTR4_WORD0_MAXREAD
254 | FATTR4_WORD0_MAXWRITE
255 | FATTR4_WORD0_LEASE_TIME,
Ricardo Labiaga55b6e772010-10-12 16:30:06 -0700256 FATTR4_WORD1_TIME_DELTA
Fred Isamandae100c2011-07-30 20:52:37 -0400257 | FATTR4_WORD1_FS_LAYOUT_TYPES,
258 FATTR4_WORD2_LAYOUT_BLKSIZE
Peng Tao2a92ee92015-09-26 02:24:37 +0800259 | FATTR4_WORD2_CLONE_BLKSIZE
Frank van der Lindenb78ef842020-06-23 22:38:55 +0000260 | FATTR4_WORD2_XATTR_SUPPORT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261};
262
David Quigleya09df2c2013-05-22 12:50:41 -0400263const u32 nfs4_fs_locations_bitmap[3] = {
Chuck Leverc05cefc2017-11-05 15:45:22 -0500264 FATTR4_WORD0_CHANGE
Manoj Naik830b8e32006-06-09 09:34:25 -0400265 | FATTR4_WORD0_SIZE
266 | FATTR4_WORD0_FSID
267 | FATTR4_WORD0_FILEID
268 | FATTR4_WORD0_FS_LOCATIONS,
Chuck Leverc05cefc2017-11-05 15:45:22 -0500269 FATTR4_WORD1_OWNER
Manoj Naik830b8e32006-06-09 09:34:25 -0400270 | 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
Trond Myklebust30846df2018-04-07 13:44:28 -0400279static void nfs4_bitmap_copy_adjust(__u32 *dst, const __u32 *src,
280 struct inode *inode)
281{
282 unsigned long cache_validity;
283
284 memcpy(dst, src, NFS4_BITMASK_SZ*sizeof(*dst));
285 if (!inode || !nfs4_have_delegation(inode, FMODE_READ))
286 return;
287
288 cache_validity = READ_ONCE(NFS_I(inode)->cache_validity);
289 if (!(cache_validity & NFS_INO_REVAL_FORCED))
290 cache_validity &= ~(NFS_INO_INVALID_CHANGE
291 | NFS_INO_INVALID_SIZE);
292
293 if (!(cache_validity & NFS_INO_INVALID_SIZE))
294 dst[0] &= ~FATTR4_WORD0_SIZE;
295
296 if (!(cache_validity & NFS_INO_INVALID_CHANGE))
297 dst[0] &= ~FATTR4_WORD0_CHANGE;
298}
299
300static void nfs4_bitmap_copy_adjust_setattr(__u32 *dst,
301 const __u32 *src, struct inode *inode)
302{
303 nfs4_bitmap_copy_adjust(dst, src, inode);
304}
305
Al Virobc4785c2006-10-19 23:28:51 -0700306static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 struct nfs4_readdir_arg *readdir)
308{
Anna Schumaker18fe6a22017-06-16 12:06:59 -0400309 unsigned int attrs = FATTR4_WORD0_FILEID | FATTR4_WORD0_TYPE;
Al Viro0dbb4c62006-10-19 23:28:49 -0700310 __be32 *start, *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312 if (cookie > 2) {
Adrian Bunkb7ef1952005-06-22 17:16:28 +0000313 readdir->cookie = cookie;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));
315 return;
316 }
317
318 readdir->cookie = 0;
319 memset(&readdir->verifier, 0, sizeof(readdir->verifier));
320 if (cookie == 2)
321 return;
322
323 /*
324 * NFSv4 servers do not return entries for '.' and '..'
325 * Therefore, we fake these entries here. We let '.'
326 * have cookie 0 and '..' have cookie 1. Note that
327 * when talking to the server, we always send cookie 0
328 * instead of 1 or 2.
329 */
Cong Wang2b86ce22011-11-25 23:14:33 +0800330 start = p = kmap_atomic(*readdir->pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 if (cookie == 0) {
333 *p++ = xdr_one; /* next */
334 *p++ = xdr_zero; /* cookie, first word */
335 *p++ = xdr_one; /* cookie, second word */
336 *p++ = xdr_one; /* entry len */
337 memcpy(p, ".\0\0\0", 4); /* entry */
338 p++;
339 *p++ = xdr_one; /* bitmap length */
Anna Schumaker18fe6a22017-06-16 12:06:59 -0400340 *p++ = htonl(attrs); /* bitmap */
341 *p++ = htonl(12); /* attribute buffer length */
342 *p++ = htonl(NF4DIR);
David Howells2b0143b2015-03-17 22:25:59 +0000343 p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344 }
345
346 *p++ = xdr_one; /* next */
347 *p++ = xdr_zero; /* cookie, first word */
348 *p++ = xdr_two; /* cookie, second word */
349 *p++ = xdr_two; /* entry len */
350 memcpy(p, "..\0\0", 4); /* entry */
351 p++;
352 *p++ = xdr_one; /* bitmap length */
Anna Schumaker18fe6a22017-06-16 12:06:59 -0400353 *p++ = htonl(attrs); /* bitmap */
354 *p++ = htonl(12); /* attribute buffer length */
355 *p++ = htonl(NF4DIR);
David Howells2b0143b2015-03-17 22:25:59 +0000356 p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry->d_parent)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
358 readdir->pgbase = (char *)p - (char *)start;
359 readdir->count -= readdir->pgbase;
Cong Wang2b86ce22011-11-25 23:14:33 +0800360 kunmap_atomic(start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361}
362
Trond Myklebust26d36302016-09-22 13:39:05 -0400363static void nfs4_test_and_free_stateid(struct nfs_server *server,
364 nfs4_stateid *stateid,
NeilBrowna52458b2018-12-03 11:30:31 +1100365 const struct cred *cred)
Trond Myklebust26d36302016-09-22 13:39:05 -0400366{
367 const struct nfs4_minor_version_ops *ops = server->nfs_client->cl_mvops;
368
369 ops->test_and_free_expired(server, stateid, cred);
370}
371
372static void __nfs4_free_revoked_stateid(struct nfs_server *server,
373 nfs4_stateid *stateid,
NeilBrowna52458b2018-12-03 11:30:31 +1100374 const struct cred *cred)
Trond Myklebust26d36302016-09-22 13:39:05 -0400375{
376 stateid->type = NFS4_REVOKED_STATEID_TYPE;
377 nfs4_test_and_free_stateid(server, stateid, cred);
378}
379
380static void nfs4_free_revoked_stateid(struct nfs_server *server,
381 const nfs4_stateid *stateid,
NeilBrowna52458b2018-12-03 11:30:31 +1100382 const struct cred *cred)
Trond Myklebust26d36302016-09-22 13:39:05 -0400383{
384 nfs4_stateid tmp;
385
386 nfs4_stateid_copy(&tmp, stateid);
387 __nfs4_free_revoked_stateid(server, &tmp, cred);
388}
389
NeilBrown8478eaa2014-09-18 16:09:27 +1000390static long nfs4_update_delay(long *timeout)
391{
392 long ret;
393 if (!timeout)
394 return NFS4_POLL_RETRY_MAX;
395 if (*timeout <= 0)
396 *timeout = NFS4_POLL_RETRY_MIN;
397 if (*timeout > NFS4_POLL_RETRY_MAX)
398 *timeout = NFS4_POLL_RETRY_MAX;
399 ret = *timeout;
400 *timeout <<= 1;
401 return ret;
402}
403
Trond Myklebust0688e642019-04-07 13:59:09 -0400404static int nfs4_delay_killable(long *timeout)
Trond Myklebust65de8722008-12-23 15:21:44 -0500405{
Trond Myklebust65de8722008-12-23 15:21:44 -0500406 might_sleep();
407
NeilBrown8478eaa2014-09-18 16:09:27 +1000408 freezable_schedule_timeout_killable_unsafe(
409 nfs4_update_delay(timeout));
Trond Myklebust0688e642019-04-07 13:59:09 -0400410 if (!__fatal_signal_pending(current))
411 return 0;
412 return -EINTR;
413}
414
415static int nfs4_delay_interruptible(long *timeout)
416{
417 might_sleep();
418
419 freezable_schedule_timeout_interruptible(nfs4_update_delay(timeout));
420 if (!signal_pending(current))
421 return 0;
422 return __fatal_signal_pending(current) ? -EINTR :-ERESTARTSYS;
423}
424
425static int nfs4_delay(long *timeout, bool interruptible)
426{
427 if (interruptible)
428 return nfs4_delay_interruptible(timeout);
429 return nfs4_delay_killable(timeout);
Trond Myklebust65de8722008-12-23 15:21:44 -0500430}
431
Trond Myklebust50c80002019-07-11 19:02:18 -0400432static const nfs4_stateid *
433nfs4_recoverable_stateid(const nfs4_stateid *stateid)
434{
435 if (!stateid)
436 return NULL;
437 switch (stateid->type) {
438 case NFS4_OPEN_STATEID_TYPE:
439 case NFS4_LOCK_STATEID_TYPE:
440 case NFS4_DELEGATION_STATEID_TYPE:
441 return stateid;
442 default:
443 break;
444 }
445 return NULL;
446}
447
Trond Myklebust65de8722008-12-23 15:21:44 -0500448/* This is the error handling routine for processes that are allowed
449 * to sleep.
450 */
Trond Myklebustb3c2aa02015-09-20 14:32:45 -0400451static int nfs4_do_handle_exception(struct nfs_server *server,
452 int errorcode, struct nfs4_exception *exception)
Trond Myklebust65de8722008-12-23 15:21:44 -0500453{
454 struct nfs_client *clp = server->nfs_client;
Trond Myklebust9e33bed2008-12-23 15:21:46 -0500455 struct nfs4_state *state = exception->state;
Trond Myklebust50c80002019-07-11 19:02:18 -0400456 const nfs4_stateid *stateid;
Trond Myklebust3114ea72012-03-07 16:39:06 -0500457 struct inode *inode = exception->inode;
Trond Myklebust65de8722008-12-23 15:21:44 -0500458 int ret = errorcode;
459
Trond Myklebustb3c2aa02015-09-20 14:32:45 -0400460 exception->delay = 0;
461 exception->recovering = 0;
Trond Myklebust65de8722008-12-23 15:21:44 -0500462 exception->retry = 0;
Trond Myklebust272289a2016-09-22 13:39:15 -0400463
Trond Myklebust50c80002019-07-11 19:02:18 -0400464 stateid = nfs4_recoverable_stateid(exception->stateid);
Trond Myklebust272289a2016-09-22 13:39:15 -0400465 if (stateid == NULL && state != NULL)
Trond Myklebust50c80002019-07-11 19:02:18 -0400466 stateid = nfs4_recoverable_stateid(&state->stateid);
Trond Myklebust272289a2016-09-22 13:39:15 -0400467
Trond Myklebust65de8722008-12-23 15:21:44 -0500468 switch(errorcode) {
469 case 0:
470 return 0;
Trond Myklebustcf61eb22018-05-29 22:06:08 -0400471 case -NFS4ERR_BADHANDLE:
472 case -ESTALE:
473 if (inode != NULL && S_ISREG(inode->i_mode))
474 pnfs_destroy_layout(NFS_I(inode));
475 break;
Trond Myklebust5ba12442015-06-16 11:26:35 -0400476 case -NFS4ERR_DELEG_REVOKED:
477 case -NFS4ERR_ADMIN_REVOKED:
Trond Myklebust272289a2016-09-22 13:39:15 -0400478 case -NFS4ERR_EXPIRED:
Trond Myklebust5ba12442015-06-16 11:26:35 -0400479 case -NFS4ERR_BAD_STATEID:
Olga Kornievskaiafefa1a82019-06-14 14:22:12 -0400480 case -NFS4ERR_PARTNER_NO_AUTH:
Trond Myklebust272289a2016-09-22 13:39:15 -0400481 if (inode != NULL && stateid != NULL) {
482 nfs_inode_find_state_and_recover(inode,
483 stateid);
484 goto wait_on_recovery;
485 }
Gustavo A. R. Silva01e03bd2018-07-31 21:18:44 -0500486 /* Fall through */
Trond Myklebust272289a2016-09-22 13:39:15 -0400487 case -NFS4ERR_OPENMODE:
Trond Myklebust8487c472016-06-26 08:44:35 -0400488 if (inode) {
489 int err;
490
491 err = nfs_async_inode_return_delegation(inode,
492 stateid);
493 if (err == 0)
494 goto wait_on_recovery;
495 if (stateid != NULL && stateid->type == NFS4_DELEGATION_STATEID_TYPE) {
496 exception->retry = 1;
497 break;
498 }
499 }
Trond Myklebust3114ea72012-03-07 16:39:06 -0500500 if (state == NULL)
501 break;
Trond Myklebust5d422302013-03-14 16:57:48 -0400502 ret = nfs4_schedule_stateid_recovery(server, state);
503 if (ret < 0)
504 break;
Trond Myklebust3114ea72012-03-07 16:39:06 -0500505 goto wait_on_recovery;
Trond Myklebust65de8722008-12-23 15:21:44 -0500506 case -NFS4ERR_STALE_STATEID:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -0500507 case -NFS4ERR_STALE_CLIENTID:
Trond Myklebust0400a6b2011-03-09 16:00:53 -0500508 nfs4_schedule_lease_recovery(clp);
509 goto wait_on_recovery;
Chuck Lever519ae252013-10-17 14:13:19 -0400510 case -NFS4ERR_MOVED:
511 ret = nfs4_schedule_migration_recovery(server);
512 if (ret < 0)
513 break;
514 goto wait_on_recovery;
Chuck Lever8ef2f8d2013-10-17 14:13:41 -0400515 case -NFS4ERR_LEASE_MOVED:
516 nfs4_schedule_lease_moved_recovery(clp);
517 goto wait_on_recovery;
Trond Myklebust03391692010-01-26 15:42:38 -0500518#if defined(CONFIG_NFS_V4_1)
Andy Adamson4745e312009-04-01 09:22:42 -0400519 case -NFS4ERR_BADSESSION:
520 case -NFS4ERR_BADSLOT:
521 case -NFS4ERR_BAD_HIGH_SLOT:
522 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
523 case -NFS4ERR_DEADSESSION:
524 case -NFS4ERR_SEQ_FALSE_RETRY:
525 case -NFS4ERR_SEQ_MISORDERED:
Trond Myklebust5c441542019-11-13 08:34:00 +0100526 /* Handled in nfs41_sequence_process() */
Bryan Schumaker399f11c2012-10-30 16:06:35 -0400527 goto wait_on_recovery;
Trond Myklebust03391692010-01-26 15:42:38 -0500528#endif /* defined(CONFIG_NFS_V4_1) */
Trond Myklebust65de8722008-12-23 15:21:44 -0500529 case -NFS4ERR_FILE_OPEN:
NeilBrown44ed3552009-12-03 15:58:56 -0500530 if (exception->timeout > HZ) {
531 /* We have retried a decent amount, time to
532 * fail
533 */
534 ret = -EBUSY;
535 break;
536 }
Gustavo A. R. Silva01e03bd2018-07-31 21:18:44 -0500537 /* Fall through */
Trond Myklebust65de8722008-12-23 15:21:44 -0500538 case -NFS4ERR_DELAY:
Trond Myklebust2598ed32015-09-20 16:10:18 -0400539 nfs_inc_server_stats(server, NFSIOS_DELAY);
Gustavo A. R. Silva01e03bd2018-07-31 21:18:44 -0500540 /* Fall through */
Trond Myklebust2598ed32015-09-20 16:10:18 -0400541 case -NFS4ERR_GRACE:
Trond Myklebuste85d7ee2016-07-14 18:46:24 -0400542 case -NFS4ERR_LAYOUTTRYLATER:
Jeff Layton183d9e72016-05-17 12:28:47 -0400543 case -NFS4ERR_RECALLCONFLICT:
Trond Myklebustb3c2aa02015-09-20 14:32:45 -0400544 exception->delay = 1;
545 return 0;
546
Andy Adamsona8a4ae32011-05-03 13:43:03 -0400547 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebust65de8722008-12-23 15:21:44 -0500548 case -NFS4ERR_OLD_STATEID:
549 exception->retry = 1;
Trond Myklebustb064eca22011-02-22 15:44:32 -0800550 break;
551 case -NFS4ERR_BADOWNER:
552 /* The following works around a Linux server bug! */
553 case -NFS4ERR_BADNAME:
554 if (server->caps & NFS_CAP_UIDGID_NOMAP) {
555 server->caps &= ~NFS_CAP_UIDGID_NOMAP;
556 exception->retry = 1;
557 printk(KERN_WARNING "NFS: v4 server %s "
558 "does not accept raw "
559 "uid/gids. "
560 "Reenabling the idmapper.\n",
561 server->nfs_client->cl_hostname);
562 }
Trond Myklebust65de8722008-12-23 15:21:44 -0500563 }
564 /* We failed to handle the error */
565 return nfs4_map_errors(ret);
Trond Myklebust0400a6b2011-03-09 16:00:53 -0500566wait_on_recovery:
Trond Myklebustb3c2aa02015-09-20 14:32:45 -0400567 exception->recovering = 1;
568 return 0;
569}
570
571/* This is the error handling routine for processes that are allowed
572 * to sleep.
573 */
574int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
575{
576 struct nfs_client *clp = server->nfs_client;
577 int ret;
578
579 ret = nfs4_do_handle_exception(server, errorcode, exception);
580 if (exception->delay) {
Trond Myklebust0688e642019-04-07 13:59:09 -0400581 ret = nfs4_delay(&exception->timeout,
582 exception->interruptible);
Trond Myklebustb3c2aa02015-09-20 14:32:45 -0400583 goto out_retry;
584 }
585 if (exception->recovering) {
586 ret = nfs4_wait_clnt_recover(clp);
587 if (test_bit(NFS_MIG_FAILED, &server->mig_status))
588 return -EIO;
589 goto out_retry;
590 }
591 return ret;
592out_retry:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -0500593 if (ret == 0)
594 exception->retry = 1;
595 return ret;
Trond Myklebust65de8722008-12-23 15:21:44 -0500596}
597
Trond Myklebust037fc982015-09-20 15:51:00 -0400598static int
599nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
600 int errorcode, struct nfs4_exception *exception)
601{
602 struct nfs_client *clp = server->nfs_client;
603 int ret;
604
605 ret = nfs4_do_handle_exception(server, errorcode, exception);
606 if (exception->delay) {
607 rpc_delay(task, nfs4_update_delay(&exception->timeout));
608 goto out_retry;
609 }
610 if (exception->recovering) {
611 rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
612 if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
613 rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
614 goto out_retry;
615 }
616 if (test_bit(NFS_MIG_FAILED, &server->mig_status))
617 ret = -EIO;
618 return ret;
619out_retry:
Bill Baker0f90be12018-06-19 16:24:58 -0500620 if (ret == 0) {
Trond Myklebust037fc982015-09-20 15:51:00 -0400621 exception->retry = 1;
Bill Baker0f90be12018-06-19 16:24:58 -0500622 /*
623 * For NFS4ERR_MOVED, the client transport will need to
624 * be recomputed after migration recovery has completed.
625 */
626 if (errorcode == -NFS4ERR_MOVED)
627 rpc_task_release_transport(task);
628 }
Trond Myklebust037fc982015-09-20 15:51:00 -0400629 return ret;
630}
631
Olga Kornievskaia0f913a52018-07-09 15:13:33 -0400632int
Trond Myklebust037fc982015-09-20 15:51:00 -0400633nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server,
634 struct nfs4_state *state, long *timeout)
635{
636 struct nfs4_exception exception = {
637 .state = state,
638 };
639
640 if (task->tk_status >= 0)
641 return 0;
642 if (timeout)
643 exception.timeout = *timeout;
644 task->tk_status = nfs4_async_handle_exception(task, server,
645 task->tk_status,
646 &exception);
647 if (exception.delay && timeout)
648 *timeout = exception.timeout;
649 if (exception.retry)
650 return -EAGAIN;
651 return 0;
652}
653
Weston Andros Adamsona5250de2013-09-03 15:18:49 -0400654/*
655 * Return 'true' if 'clp' is using an rpc_client that is integrity protected
656 * or 'false' otherwise.
657 */
658static bool _nfs4_is_integrity_protected(struct nfs_client *clp)
659{
660 rpc_authflavor_t flavor = clp->cl_rpcclient->cl_auth->au_flavor;
Anna Schumakereeea5362017-01-11 16:01:21 -0500661 return (flavor == RPC_AUTH_GSS_KRB5I) || (flavor == RPC_AUTH_GSS_KRB5P);
Weston Andros Adamsona5250de2013-09-03 15:18:49 -0400662}
Trond Myklebust65de8722008-12-23 15:21:44 -0500663
Trond Myklebust452e9352010-07-31 14:29:06 -0400664static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 spin_lock(&clp->cl_lock);
667 if (time_before(clp->cl_last_renewal,timestamp))
668 clp->cl_last_renewal = timestamp;
669 spin_unlock(&clp->cl_lock);
670}
671
Trond Myklebust452e9352010-07-31 14:29:06 -0400672static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
673{
Trond Myklebustbe824162015-07-05 14:50:46 -0400674 struct nfs_client *clp = server->nfs_client;
675
676 if (!nfs4_has_session(clp))
677 do_renew_lease(clp, timestamp);
Trond Myklebust452e9352010-07-31 14:29:06 -0400678}
679
Chuck Lever2a3eb2b2013-08-09 12:48:00 -0400680struct nfs4_call_sync_data {
681 const struct nfs_server *seq_server;
682 struct nfs4_sequence_args *seq_args;
683 struct nfs4_sequence_res *seq_res;
684};
685
Trond Myklebustbe3a5d22015-06-23 19:51:55 +0800686void nfs4_init_sequence(struct nfs4_sequence_args *args,
Anna Schumakerfba83f32018-05-04 16:22:50 -0400687 struct nfs4_sequence_res *res, int cache_reply,
688 int privileged)
Chuck Levera9c92d62013-08-09 12:48:18 -0400689{
690 args->sa_slot = NULL;
691 args->sa_cache_this = cache_reply;
Anna Schumakerfba83f32018-05-04 16:22:50 -0400692 args->sa_privileged = privileged;
Chuck Levera9c92d62013-08-09 12:48:18 -0400693
694 res->sr_slot = NULL;
695}
696
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400697static void nfs40_sequence_free_slot(struct nfs4_sequence_res *res)
Chuck Lever3bd23842013-08-09 12:49:19 -0400698{
699 struct nfs4_slot *slot = res->sr_slot;
700 struct nfs4_slot_table *tbl;
701
Chuck Lever3bd23842013-08-09 12:49:19 -0400702 tbl = slot->table;
703 spin_lock(&tbl->slot_tbl_lock);
704 if (!nfs41_wake_and_assign_slot(tbl, slot))
705 nfs4_free_slot(tbl, slot);
706 spin_unlock(&tbl->slot_tbl_lock);
707
708 res->sr_slot = NULL;
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400709}
710
711static int nfs40_sequence_done(struct rpc_task *task,
712 struct nfs4_sequence_res *res)
713{
714 if (res->sr_slot != NULL)
715 nfs40_sequence_free_slot(res);
Chuck Lever3bd23842013-08-09 12:49:19 -0400716 return 1;
717}
718
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400719#if defined(CONFIG_NFS_V4_1)
720
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400721static void nfs41_release_slot(struct nfs4_slot *slot)
Andy Adamson13615872009-04-01 09:22:17 -0400722{
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500723 struct nfs4_session *session;
Andy Adamson13615872009-04-01 09:22:17 -0400724 struct nfs4_slot_table *tbl;
Trond Myklebustc10e4492012-11-26 16:16:54 -0500725 bool send_new_highest_used_slotid = false;
Andy Adamson13615872009-04-01 09:22:17 -0400726
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400727 if (!slot)
728 return;
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500729 tbl = slot->table;
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500730 session = tbl->session;
Andy Adamsonea028ac2009-12-04 15:55:38 -0500731
Trond Myklebust07e8dcb2016-08-28 10:28:25 -0400732 /* Bump the slot sequence number */
733 if (slot->seq_done)
734 slot->seq_nr++;
735 slot->seq_done = 0;
736
Trond Myklebust35dc1d72009-12-05 19:32:19 -0500737 spin_lock(&tbl->slot_tbl_lock);
Trond Myklebustc10e4492012-11-26 16:16:54 -0500738 /* Be nice to the server: try to ensure that the last transmitted
739 * value for highest_user_slotid <= target_highest_slotid
740 */
741 if (tbl->highest_used_slotid > tbl->target_highest_slotid)
742 send_new_highest_used_slotid = true;
743
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500744 if (nfs41_wake_and_assign_slot(tbl, slot)) {
Trond Myklebustb75ad4c2012-11-29 17:27:47 -0500745 send_new_highest_used_slotid = false;
746 goto out_unlock;
747 }
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500748 nfs4_free_slot(tbl, slot);
Trond Myklebustc10e4492012-11-26 16:16:54 -0500749
750 if (tbl->highest_used_slotid != NFS4_NO_SLOT)
751 send_new_highest_used_slotid = false;
Trond Myklebustb75ad4c2012-11-29 17:27:47 -0500752out_unlock:
Trond Myklebust35dc1d72009-12-05 19:32:19 -0500753 spin_unlock(&tbl->slot_tbl_lock);
Trond Myklebustc10e4492012-11-26 16:16:54 -0500754 if (send_new_highest_used_slotid)
Anna Schumaker3f10a6a2015-07-13 14:01:31 -0400755 nfs41_notify_server(session->clp);
Trond Myklebust045d2a62016-08-28 13:25:43 -0400756 if (waitqueue_active(&tbl->slot_waitq))
757 wake_up_all(&tbl->slot_waitq);
Andy Adamson13615872009-04-01 09:22:17 -0400758}
759
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400760static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
761{
762 nfs41_release_slot(res->sr_slot);
763 res->sr_slot = NULL;
764}
765
Trond Myklebust3453d572018-06-20 17:53:34 -0400766static void nfs4_slot_sequence_record_sent(struct nfs4_slot *slot,
767 u32 seqnr)
768{
769 if ((s32)(seqnr - slot->seq_nr_highest_sent) > 0)
770 slot->seq_nr_highest_sent = seqnr;
771}
772static void nfs4_slot_sequence_acked(struct nfs4_slot *slot,
773 u32 seqnr)
774{
775 slot->seq_nr_highest_sent = seqnr;
776 slot->seq_nr_last_acked = seqnr;
777}
778
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400779static int nfs41_sequence_process(struct rpc_task *task,
780 struct nfs4_sequence_res *res)
Andy Adamsonb0df8062009-04-01 09:22:18 -0400781{
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500782 struct nfs4_session *session;
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500783 struct nfs4_slot *slot = res->sr_slot;
Trond Myklebust14516c32010-07-31 14:29:06 -0400784 struct nfs_client *clp;
Trond Myklebust5c441542019-11-13 08:34:00 +0100785 int status;
Trond Myklebust85563072012-12-11 10:31:12 -0500786 int ret = 1;
Andy Adamsonb0df8062009-04-01 09:22:18 -0400787
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500788 if (slot == NULL)
789 goto out_noaction;
Bryan Schumaker468f8612011-04-18 15:57:32 -0400790 /* don't increment the sequence number if the task wasn't sent */
Trond Myklebustc71c46f2019-03-01 11:40:05 -0500791 if (!RPC_WAS_SENT(task) || slot->seq_done)
Andy Adamsonb0df8062009-04-01 09:22:18 -0400792 goto out;
793
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500794 session = slot->table->session;
Trond Myklebust933602e2012-11-16 12:12:38 -0500795
Trond Myklebust2f92ae32013-08-14 17:58:28 -0400796 trace_nfs4_sequence_done(session, res);
Trond Myklebust5c441542019-11-13 08:34:00 +0100797
798 status = res->sr_status;
799 if (task->tk_status == -NFS4ERR_DEADSESSION)
800 status = -NFS4ERR_DEADSESSION;
801
Andy Adamson691daf32009-12-04 15:55:39 -0500802 /* Check the SEQUENCE operation status */
Trond Myklebust5c441542019-11-13 08:34:00 +0100803 switch (status) {
Trond Myklebust14516c32010-07-31 14:29:06 -0400804 case 0:
Trond Myklebust3453d572018-06-20 17:53:34 -0400805 /* Mark this sequence number as having been acked */
806 nfs4_slot_sequence_acked(slot, slot->seq_nr);
Andy Adamsonb0df8062009-04-01 09:22:18 -0400807 /* Update the slot's sequence and clientid lease timer */
Trond Myklebust07e8dcb2016-08-28 10:28:25 -0400808 slot->seq_done = 1;
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500809 clp = session->clp;
Trond Myklebust8e63b6a2012-12-15 15:21:52 -0500810 do_renew_lease(clp, res->sr_timestamp);
Alexandros Batsakis0629e372009-12-05 13:46:14 -0500811 /* Check sequence flags */
Trond Myklebust0a014a42016-09-22 13:38:51 -0400812 nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags,
813 !!slot->privileged);
Trond Myklebust464ee9f2012-11-20 12:49:27 -0500814 nfs41_update_target_slotid(slot->table, slot, res);
Trond Myklebust14516c32010-07-31 14:29:06 -0400815 break;
Trond Myklebustac20d162012-12-15 15:36:07 -0500816 case 1:
817 /*
818 * sr_status remains 1 if an RPC level error occurred.
819 * The server may or may not have processed the sequence
820 * operation..
Trond Myklebustac20d162012-12-15 15:36:07 -0500821 */
Trond Myklebust3453d572018-06-20 17:53:34 -0400822 nfs4_slot_sequence_record_sent(slot, slot->seq_nr);
823 slot->seq_done = 1;
Trond Myklebustac20d162012-12-15 15:36:07 -0500824 goto out;
Trond Myklebust14516c32010-07-31 14:29:06 -0400825 case -NFS4ERR_DELAY:
826 /* The server detected a resend of the RPC call and
827 * returned NFS4ERR_DELAY as per Section 2.10.6.2
828 * of RFC5661.
829 */
Trond Myklebustdf2fabf2012-11-16 12:45:06 -0500830 dprintk("%s: slot=%u seq=%u: Operation in progress\n",
Benny Halevydfb4f3092010-09-24 09:17:01 -0400831 __func__,
Trond Myklebustdf2fabf2012-11-16 12:45:06 -0500832 slot->slot_nr,
Trond Myklebust933602e2012-11-16 12:12:38 -0500833 slot->seq_nr);
Trond Myklebust3453d572018-06-20 17:53:34 -0400834 nfs4_slot_sequence_acked(slot, slot->seq_nr);
Trond Myklebust14516c32010-07-31 14:29:06 -0400835 goto out_retry;
Trond Myklebustf9312a52018-06-09 19:10:31 -0400836 case -NFS4ERR_RETRY_UNCACHED_REP:
837 case -NFS4ERR_SEQ_FALSE_RETRY:
838 /*
839 * The server thinks we tried to replay a request.
840 * Retry the call after bumping the sequence ID.
841 */
Trond Myklebust3453d572018-06-20 17:53:34 -0400842 nfs4_slot_sequence_acked(slot, slot->seq_nr);
Trond Myklebustf9312a52018-06-09 19:10:31 -0400843 goto retry_new_seq;
Trond Myklebust85563072012-12-11 10:31:12 -0500844 case -NFS4ERR_BADSLOT:
845 /*
846 * The slot id we used was probably retired. Try again
847 * using a different slot id.
848 */
Trond Myklebust99589102018-06-09 12:50:50 -0400849 if (slot->slot_nr < slot->table->target_highest_slotid)
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400850 goto session_recover;
Trond Myklebuste8794442012-12-15 13:56:18 -0500851 goto retry_nowait;
852 case -NFS4ERR_SEQ_MISORDERED:
Trond Myklebust3453d572018-06-20 17:53:34 -0400853 nfs4_slot_sequence_record_sent(slot, slot->seq_nr);
Trond Myklebuste8794442012-12-15 13:56:18 -0500854 /*
Trond Myklebust3453d572018-06-20 17:53:34 -0400855 * Were one or more calls using this slot interrupted?
856 * If the server never received the request, then our
857 * transmitted slot sequence number may be too high.
Trond Myklebustac20d162012-12-15 15:36:07 -0500858 */
Trond Myklebust3453d572018-06-20 17:53:34 -0400859 if ((s32)(slot->seq_nr - slot->seq_nr_last_acked) > 1) {
860 slot->seq_nr--;
Trond Myklebust8e63b6a2012-12-15 15:21:52 -0500861 goto retry_nowait;
862 }
Trond Myklebust3453d572018-06-20 17:53:34 -0400863 /*
864 * RFC5661:
865 * A retry might be sent while the original request is
866 * still in progress on the replier. The replier SHOULD
867 * deal with the issue by returning NFS4ERR_DELAY as the
868 * reply to SEQUENCE or CB_SEQUENCE operation, but
869 * implementations MAY return NFS4ERR_SEQ_MISORDERED.
870 *
871 * Restart the search after a delay.
872 */
873 slot->seq_nr = slot->seq_nr_highest_sent;
874 goto out_retry;
Trond Myklebust5c441542019-11-13 08:34:00 +0100875 case -NFS4ERR_BADSESSION:
876 case -NFS4ERR_DEADSESSION:
877 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
878 goto session_recover;
Trond Myklebust14516c32010-07-31 14:29:06 -0400879 default:
880 /* Just update the slot sequence no. */
Trond Myklebust07e8dcb2016-08-28 10:28:25 -0400881 slot->seq_done = 1;
Andy Adamsonb0df8062009-04-01 09:22:18 -0400882 }
883out:
884 /* The session may be reset by one of the error handlers. */
885 dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
Trond Myklebusta13ce7c2014-01-29 12:24:03 -0500886out_noaction:
Trond Myklebust85563072012-12-11 10:31:12 -0500887 return ret;
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400888session_recover:
Trond Myklebust5c441542019-11-13 08:34:00 +0100889 nfs4_schedule_session_recovery(session, status);
890 dprintk("%s ERROR: %d Reset session\n", __func__, status);
891 nfs41_sequence_free_slot(res);
892 goto out;
Trond Myklebust3be0f80b2017-10-19 15:46:45 -0400893retry_new_seq:
894 ++slot->seq_nr;
Trond Myklebuste8794442012-12-15 13:56:18 -0500895retry_nowait:
896 if (rpc_restart_call_prepare(task)) {
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400897 nfs41_sequence_free_slot(res);
Trond Myklebuste8794442012-12-15 13:56:18 -0500898 task->tk_status = 0;
899 ret = 0;
900 }
901 goto out;
Trond Myklebust14516c32010-07-31 14:29:06 -0400902out_retry:
Trond Myklebustd05dd4e2010-07-31 14:29:07 -0400903 if (!rpc_restart_call(task))
Trond Myklebust14516c32010-07-31 14:29:06 -0400904 goto out;
905 rpc_delay(task, NFS4_POLL_RETRY_MAX);
906 return 0;
Andy Adamsonb0df8062009-04-01 09:22:18 -0400907}
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400908
909int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
910{
911 if (!nfs41_sequence_process(task, res))
912 return 0;
913 if (res->sr_slot != NULL)
914 nfs41_sequence_free_slot(res);
915 return 1;
916
917}
Andy Adamsonf9c96fc2014-01-29 11:34:38 -0500918EXPORT_SYMBOL_GPL(nfs41_sequence_done);
Andy Adamsonb0df8062009-04-01 09:22:18 -0400919
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400920static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
921{
922 if (res->sr_slot == NULL)
923 return 1;
924 if (res->sr_slot->table->session != NULL)
925 return nfs41_sequence_process(task, res);
926 return nfs40_sequence_done(task, res);
927}
928
929static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
930{
931 if (res->sr_slot != NULL) {
932 if (res->sr_slot->table->session != NULL)
933 nfs41_sequence_free_slot(res);
934 else
935 nfs40_sequence_free_slot(res);
936 }
937}
938
Peng Tao2c4b1312014-06-11 05:24:16 +0800939int nfs4_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
Trond Myklebustdf896452010-06-16 09:52:26 -0400940{
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500941 if (res->sr_slot == NULL)
Trond Myklebust14516c32010-07-31 14:29:06 -0400942 return 1;
Chuck Lever3bd23842013-08-09 12:49:19 -0400943 if (!res->sr_slot->table->session)
944 return nfs40_sequence_done(task, res);
Trond Myklebust14516c32010-07-31 14:29:06 -0400945 return nfs41_sequence_done(task, res);
Trond Myklebustdf896452010-06-16 09:52:26 -0400946}
Peng Tao2c4b1312014-06-11 05:24:16 +0800947EXPORT_SYMBOL_GPL(nfs4_sequence_done);
Trond Myklebustdf896452010-06-16 09:52:26 -0400948
Andy Adamsonce5039c2009-04-01 09:22:13 -0400949static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
950{
Chuck Lever2a3eb2b2013-08-09 12:48:00 -0400951 struct nfs4_call_sync_data *data = calldata;
Andy Adamsonce5039c2009-04-01 09:22:13 -0400952
Trond Myklebust035168ab2010-06-16 09:52:26 -0400953 dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
954
Anna Schumaker7981c8a2017-01-10 11:39:53 -0500955 nfs4_setup_sequence(data->seq_server->nfs_client,
956 data->seq_args, data->seq_res, task);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400957}
958
Andy Adamson69ab40c2009-04-01 09:22:19 -0400959static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
960{
Chuck Lever2a3eb2b2013-08-09 12:48:00 -0400961 struct nfs4_call_sync_data *data = calldata;
Andy Adamson69ab40c2009-04-01 09:22:19 -0400962
Trond Myklebust14516c32010-07-31 14:29:06 -0400963 nfs41_sequence_done(task, data->seq_res);
Andy Adamson69ab40c2009-04-01 09:22:19 -0400964}
965
Trond Myklebust17280172012-03-11 13:11:00 -0400966static const struct rpc_call_ops nfs41_call_sync_ops = {
Andy Adamsonce5039c2009-04-01 09:22:13 -0400967 .rpc_call_prepare = nfs41_call_sync_prepare,
Andy Adamson69ab40c2009-04-01 09:22:19 -0400968 .rpc_call_done = nfs41_call_sync_done,
Andy Adamsonce5039c2009-04-01 09:22:13 -0400969};
970
Chuck Lever3bd23842013-08-09 12:49:19 -0400971#else /* !CONFIG_NFS_V4_1 */
972
Trond Myklebust2e80dbe2016-08-28 11:50:26 -0400973static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
974{
975 return nfs40_sequence_done(task, res);
976}
977
978static void nfs4_sequence_free_slot(struct nfs4_sequence_res *res)
979{
980 if (res->sr_slot != NULL)
981 nfs40_sequence_free_slot(res);
982}
983
Peng Tao2c4b1312014-06-11 05:24:16 +0800984int nfs4_sequence_done(struct rpc_task *task,
985 struct nfs4_sequence_res *res)
Trond Myklebustdf896452010-06-16 09:52:26 -0400986{
Chuck Lever3bd23842013-08-09 12:49:19 -0400987 return nfs40_sequence_done(task, res);
Trond Myklebustdf896452010-06-16 09:52:26 -0400988}
Peng Tao2c4b1312014-06-11 05:24:16 +0800989EXPORT_SYMBOL_GPL(nfs4_sequence_done);
Chuck Lever3bd23842013-08-09 12:49:19 -0400990
991#endif /* !CONFIG_NFS_V4_1 */
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400992
Trond Myklebustc1dffe02019-03-01 12:13:34 -0500993static void nfs41_sequence_res_init(struct nfs4_sequence_res *res)
994{
995 res->sr_timestamp = jiffies;
996 res->sr_status_flags = 0;
997 res->sr_status = 1;
998}
999
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04001000static
1001void nfs4_sequence_attach_slot(struct nfs4_sequence_args *args,
1002 struct nfs4_sequence_res *res,
1003 struct nfs4_slot *slot)
1004{
1005 if (!slot)
1006 return;
1007 slot->privileged = args->sa_privileged ? 1 : 0;
1008 args->sa_slot = slot;
1009
1010 res->sr_slot = slot;
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04001011}
1012
1013int nfs4_setup_sequence(struct nfs_client *client,
Anna Schumaker7981c8a2017-01-10 11:39:53 -05001014 struct nfs4_sequence_args *args,
1015 struct nfs4_sequence_res *res,
1016 struct rpc_task *task)
1017{
Anna Schumaker7981c8a2017-01-10 11:39:53 -05001018 struct nfs4_session *session = nfs4_get_session(client);
Anna Schumaker76ee0352017-01-10 16:49:31 -05001019 struct nfs4_slot_table *tbl = client->cl_slot_tbl;
Anna Schumaker3d358082017-01-11 10:54:04 -05001020 struct nfs4_slot *slot;
Anna Schumaker7981c8a2017-01-10 11:39:53 -05001021
Anna Schumaker9dd9107f2017-01-10 12:01:46 -05001022 /* slot already allocated? */
1023 if (res->sr_slot != NULL)
1024 goto out_start;
1025
Trond Myklebust6b2e6852019-04-07 13:58:49 -04001026 if (session)
Anna Schumaker76ee0352017-01-10 16:49:31 -05001027 tbl = &session->fc_slot_table;
Anna Schumaker76ee0352017-01-10 16:49:31 -05001028
Trond Myklebust3453d572018-06-20 17:53:34 -04001029 spin_lock(&tbl->slot_tbl_lock);
1030 /* The state manager will wait until the slot table is empty */
1031 if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
1032 goto out_sleep;
Anna Schumaker6994cdd2017-01-10 16:13:27 -05001033
Trond Myklebust3453d572018-06-20 17:53:34 -04001034 slot = nfs4_alloc_slot(tbl);
1035 if (IS_ERR(slot)) {
Trond Myklebust3453d572018-06-20 17:53:34 -04001036 if (slot == ERR_PTR(-ENOMEM))
Trond Myklebust6b2e6852019-04-07 13:58:49 -04001037 goto out_sleep_timeout;
Trond Myklebust3453d572018-06-20 17:53:34 -04001038 goto out_sleep;
Anna Schumaker3d358082017-01-11 10:54:04 -05001039 }
Trond Myklebust3453d572018-06-20 17:53:34 -04001040 spin_unlock(&tbl->slot_tbl_lock);
Anna Schumaker7981c8a2017-01-10 11:39:53 -05001041
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04001042 nfs4_sequence_attach_slot(args, res, slot);
Anna Schumaker3d358082017-01-11 10:54:04 -05001043
Anna Schumakerad05cc02017-01-11 13:37:06 -05001044 trace_nfs4_setup_sequence(session, args);
Anna Schumaker9dd9107f2017-01-10 12:01:46 -05001045out_start:
Trond Myklebustc1dffe02019-03-01 12:13:34 -05001046 nfs41_sequence_res_init(res);
Anna Schumaker9dd9107f2017-01-10 12:01:46 -05001047 rpc_call_start(task);
1048 return 0;
Trond Myklebust6b2e6852019-04-07 13:58:49 -04001049out_sleep_timeout:
1050 /* Try again in 1/4 second */
1051 if (args->sa_privileged)
1052 rpc_sleep_on_priority_timeout(&tbl->slot_tbl_waitq, task,
1053 jiffies + (HZ >> 2), RPC_PRIORITY_PRIVILEGED);
1054 else
1055 rpc_sleep_on_timeout(&tbl->slot_tbl_waitq, task,
1056 NULL, jiffies + (HZ >> 2));
1057 spin_unlock(&tbl->slot_tbl_lock);
1058 return -EAGAIN;
Anna Schumaker0dcee8b2017-01-10 16:29:54 -05001059out_sleep:
1060 if (args->sa_privileged)
1061 rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
Trond Myklebust8357a9b2019-04-07 13:58:48 -04001062 RPC_PRIORITY_PRIVILEGED);
Anna Schumaker0dcee8b2017-01-10 16:29:54 -05001063 else
1064 rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
1065 spin_unlock(&tbl->slot_tbl_lock);
1066 return -EAGAIN;
Anna Schumaker7981c8a2017-01-10 11:39:53 -05001067}
1068EXPORT_SYMBOL_GPL(nfs4_setup_sequence);
1069
Chuck Lever9915ea72013-08-09 12:48:27 -04001070static void nfs40_call_sync_prepare(struct rpc_task *task, void *calldata)
1071{
1072 struct nfs4_call_sync_data *data = calldata;
Anna Schumaker42e1cca2017-01-09 15:48:22 -05001073 nfs4_setup_sequence(data->seq_server->nfs_client,
Chuck Lever9915ea72013-08-09 12:48:27 -04001074 data->seq_args, data->seq_res, task);
1075}
1076
1077static void nfs40_call_sync_done(struct rpc_task *task, void *calldata)
1078{
1079 struct nfs4_call_sync_data *data = calldata;
1080 nfs4_sequence_done(task, data->seq_res);
1081}
1082
1083static const struct rpc_call_ops nfs40_call_sync_ops = {
1084 .rpc_call_prepare = nfs40_call_sync_prepare,
1085 .rpc_call_done = nfs40_call_sync_done,
1086};
1087
Anna Schumaker48c05852019-08-14 15:27:00 -04001088static int nfs4_call_sync_custom(struct rpc_task_setup *task_setup)
1089{
1090 int ret;
1091 struct rpc_task *task;
1092
1093 task = rpc_run_task(task_setup);
1094 if (IS_ERR(task))
1095 return PTR_ERR(task);
1096
1097 ret = task->tk_status;
1098 rpc_put_task(task);
1099 return ret;
1100}
1101
Trond Myklebustc74dfe92020-01-06 15:39:37 -05001102static int nfs4_do_call_sync(struct rpc_clnt *clnt,
1103 struct nfs_server *server,
1104 struct rpc_message *msg,
1105 struct nfs4_sequence_args *args,
1106 struct nfs4_sequence_res *res,
1107 unsigned short task_flags)
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001108{
Chuck Lever9915ea72013-08-09 12:48:27 -04001109 struct nfs_client *clp = server->nfs_client;
1110 struct nfs4_call_sync_data data = {
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001111 .seq_server = server,
Trond Myklebustad389da2007-06-05 12:30:00 -04001112 .seq_args = args,
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001113 .seq_res = res,
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001114 };
1115 struct rpc_task_setup task_setup = {
Trond Myklebustad389da2007-06-05 12:30:00 -04001116 .rpc_client = clnt,
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001117 .rpc_message = msg,
Chuck Lever9915ea72013-08-09 12:48:27 -04001118 .callback_ops = clp->cl_mvops->call_sync_ops,
Trond Myklebustc74dfe92020-01-06 15:39:37 -05001119 .callback_data = &data,
1120 .flags = task_flags,
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001121 };
1122
Anna Schumaker48c05852019-08-14 15:27:00 -04001123 return nfs4_call_sync_custom(&task_setup);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001124}
1125
Trond Myklebustc74dfe92020-01-06 15:39:37 -05001126static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
1127 struct nfs_server *server,
1128 struct rpc_message *msg,
1129 struct nfs4_sequence_args *args,
1130 struct nfs4_sequence_res *res)
1131{
1132 return nfs4_do_call_sync(clnt, server, msg, args, res, 0);
1133}
1134
1135
Bryan Schumaker7c513052011-03-24 17:12:24 +00001136int nfs4_call_sync(struct rpc_clnt *clnt,
1137 struct nfs_server *server,
Bryan Schumakere73b83f2011-03-24 17:12:23 +00001138 struct rpc_message *msg,
1139 struct nfs4_sequence_args *args,
1140 struct nfs4_sequence_res *res,
1141 int cache_reply)
1142{
Anna Schumakerfba83f32018-05-04 16:22:50 -04001143 nfs4_init_sequence(args, res, cache_reply, 0);
Chuck Lever9915ea72013-08-09 12:48:27 -04001144 return nfs4_call_sync_sequence(clnt, server, msg, args, res);
Bryan Schumakere73b83f2011-03-24 17:12:23 +00001145}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
Trond Myklebust3c591172018-07-31 15:54:10 -04001147static void
1148nfs4_inc_nlink_locked(struct inode *inode)
1149{
1150 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
1151 inc_nlink(inode);
1152}
1153
1154static void
1155nfs4_dec_nlink_locked(struct inode *inode)
1156{
1157 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_OTHER;
1158 drop_nlink(inode);
1159}
1160
1161static void
Frank van der Linden1b523ca2020-06-23 22:38:59 +00001162nfs4_update_changeattr_locked(struct inode *inode,
1163 struct nfs4_change_info *cinfo,
Trond Myklebust5636ec42018-07-31 15:54:11 -04001164 unsigned long timestamp, unsigned long cache_validity)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165{
Frank van der Linden1b523ca2020-06-23 22:38:59 +00001166 struct nfs_inode *nfsi = NFS_I(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167
Trond Myklebust16e14372018-03-20 16:53:31 -04001168 nfsi->cache_validity |= NFS_INO_INVALID_CTIME
1169 | NFS_INO_INVALID_MTIME
Trond Myklebust5636ec42018-07-31 15:54:11 -04001170 | cache_validity;
Frank van der Linden1b523ca2020-06-23 22:38:59 +00001171
1172 if (cinfo->atomic && cinfo->before == inode_peek_iversion_raw(inode)) {
Trond Myklebuste603a4c2016-12-16 16:55:55 -05001173 nfsi->cache_validity &= ~NFS_INO_REVAL_PAGECACHE;
1174 nfsi->attrtimeo_timestamp = jiffies;
1175 } else {
Frank van der Linden1b523ca2020-06-23 22:38:59 +00001176 if (S_ISDIR(inode->i_mode)) {
1177 nfsi->cache_validity |= NFS_INO_INVALID_DATA;
1178 nfs_force_lookup_revalidate(inode);
1179 } else {
1180 if (!NFS_PROTO(inode)->have_delegation(inode,
1181 FMODE_READ))
1182 nfsi->cache_validity |= NFS_INO_REVAL_PAGECACHE;
1183 }
1184
1185 if (cinfo->before != inode_peek_iversion_raw(inode))
Trond Myklebuste603a4c2016-12-16 16:55:55 -05001186 nfsi->cache_validity |= NFS_INO_INVALID_ACCESS |
Frank van der Linden0f44da52020-06-23 22:39:00 +00001187 NFS_INO_INVALID_ACL |
1188 NFS_INO_INVALID_XATTR;
Trond Myklebuste603a4c2016-12-16 16:55:55 -05001189 }
Frank van der Linden1b523ca2020-06-23 22:38:59 +00001190 inode_set_iversion_raw(inode, cinfo->after);
Trond Myklebustd3129ef2017-01-11 22:07:28 -05001191 nfsi->read_cache_jiffies = timestamp;
Trond Myklebust3235b402015-02-26 19:52:06 -05001192 nfsi->attr_gencount = nfs_inc_attr_generation_counter();
Trond Myklebustc8d07152018-07-31 15:54:12 -04001193 nfsi->cache_validity &= ~NFS_INO_INVALID_CHANGE;
Frank van der Linden1b523ca2020-06-23 22:38:59 +00001194
1195 if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
1196 nfs_fscache_invalidate(inode);
Trond Myklebust3c591172018-07-31 15:54:10 -04001197}
1198
Frank van der Linden1b523ca2020-06-23 22:38:59 +00001199void
1200nfs4_update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo,
Trond Myklebust5636ec42018-07-31 15:54:11 -04001201 unsigned long timestamp, unsigned long cache_validity)
Trond Myklebust3c591172018-07-31 15:54:10 -04001202{
1203 spin_lock(&dir->i_lock);
Frank van der Linden1b523ca2020-06-23 22:38:59 +00001204 nfs4_update_changeattr_locked(dir, cinfo, timestamp, cache_validity);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 spin_unlock(&dir->i_lock);
1206}
1207
Trond Myklebust8fd1ab72017-11-06 15:28:03 -05001208struct nfs4_open_createattrs {
1209 struct nfs4_label *label;
1210 struct iattr *sattr;
1211 const __u32 verf[2];
1212};
1213
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001214static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
1215 int err, struct nfs4_exception *exception)
1216{
1217 if (err != -EINVAL)
1218 return false;
1219 if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
1220 return false;
1221 server->caps &= ~NFS_CAP_ATOMIC_OPEN_V1;
1222 exception->retry = 1;
1223 return true;
1224}
1225
Trond Myklebust1bf85d82019-06-27 06:30:48 -04001226static fmode_t _nfs4_ctx_to_accessmode(const struct nfs_open_context *ctx)
1227{
1228 return ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
1229}
1230
1231static fmode_t _nfs4_ctx_to_openmode(const struct nfs_open_context *ctx)
1232{
1233 fmode_t ret = ctx->mode & (FMODE_READ|FMODE_WRITE);
1234
1235 return (ctx->mode & FMODE_EXEC) ? FMODE_READ | ret : ret;
1236}
1237
Trond Myklebust6ae37332015-01-30 14:21:14 -05001238static u32
1239nfs4_map_atomic_open_share(struct nfs_server *server,
1240 fmode_t fmode, int openflags)
1241{
1242 u32 res = 0;
1243
1244 switch (fmode & (FMODE_READ | FMODE_WRITE)) {
1245 case FMODE_READ:
1246 res = NFS4_SHARE_ACCESS_READ;
1247 break;
1248 case FMODE_WRITE:
1249 res = NFS4_SHARE_ACCESS_WRITE;
1250 break;
1251 case FMODE_READ|FMODE_WRITE:
1252 res = NFS4_SHARE_ACCESS_BOTH;
1253 }
1254 if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
1255 goto out;
1256 /* Want no delegation if we're using O_DIRECT */
1257 if (openflags & O_DIRECT)
1258 res |= NFS4_SHARE_WANT_NO_DELEG;
1259out:
1260 return res;
1261}
1262
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001263static enum open_claim_type4
1264nfs4_map_atomic_open_claim(struct nfs_server *server,
1265 enum open_claim_type4 claim)
1266{
1267 if (server->caps & NFS_CAP_ATOMIC_OPEN_V1)
1268 return claim;
1269 switch (claim) {
1270 default:
1271 return claim;
1272 case NFS4_OPEN_CLAIM_FH:
1273 return NFS4_OPEN_CLAIM_NULL;
1274 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
1275 return NFS4_OPEN_CLAIM_DELEGATE_CUR;
1276 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
1277 return NFS4_OPEN_CLAIM_DELEGATE_PREV;
1278 }
1279}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281static void nfs4_init_opendata_res(struct nfs4_opendata *p)
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001282{
1283 p->o_res.f_attr = &p->f_attr;
David Quigley1775fd32013-05-22 12:50:42 -04001284 p->o_res.f_label = p->f_label;
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001285 p->o_res.seqid = p->o_arg.seqid;
1286 p->c_res.seqid = p->c_arg.seqid;
1287 p->o_res.server = p->o_arg.server;
Andy Adamson5f657532012-10-03 02:39:34 -04001288 p->o_res.access_request = p->o_arg.access;
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001289 nfs_fattr_init(&p->f_attr);
Trond Myklebust6926afd2012-01-07 13:22:46 -05001290 nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001291}
1292
Al Viro82a2c1b2011-06-22 18:30:55 -04001293static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001294 struct nfs4_state_owner *sp, fmode_t fmode, int flags,
Trond Myklebust8fd1ab72017-11-06 15:28:03 -05001295 const struct nfs4_open_createattrs *c,
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001296 enum open_claim_type4 claim,
Trond Myklebust8535b2b2010-05-13 12:51:01 -04001297 gfp_t gfp_mask)
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001298{
Al Viro82a2c1b2011-06-22 18:30:55 -04001299 struct dentry *parent = dget_parent(dentry);
David Howells2b0143b2015-03-17 22:25:59 +00001300 struct inode *dir = d_inode(parent);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001301 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebust63f5f792015-01-23 19:19:25 -05001302 struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
Trond Myklebust8fd1ab72017-11-06 15:28:03 -05001303 struct nfs4_label *label = (c != NULL) ? c->label : NULL;
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001304 struct nfs4_opendata *p;
1305
Trond Myklebust8535b2b2010-05-13 12:51:01 -04001306 p = kzalloc(sizeof(*p), gfp_mask);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001307 if (p == NULL)
1308 goto err;
David Quigley14c43f72013-05-22 12:50:43 -04001309
1310 p->f_label = nfs4_label_alloc(server, gfp_mask);
1311 if (IS_ERR(p->f_label))
1312 goto err_free_p;
1313
Kinglong Meea49c2692015-07-27 15:31:38 +08001314 p->a_label = nfs4_label_alloc(server, gfp_mask);
1315 if (IS_ERR(p->a_label))
1316 goto err_free_f;
1317
Trond Myklebust63f5f792015-01-23 19:19:25 -05001318 alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
1319 p->o_arg.seqid = alloc_seqid(&sp->so_seqid, gfp_mask);
Trond Myklebustbadc76d2015-01-23 18:48:00 -05001320 if (IS_ERR(p->o_arg.seqid))
David Quigley14c43f72013-05-22 12:50:43 -04001321 goto err_free_label;
Al Viro82a2c1b2011-06-22 18:30:55 -04001322 nfs_sb_active(dentry->d_sb);
1323 p->dentry = dget(dentry);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001324 p->dir = parent;
1325 p->owner = sp;
1326 atomic_inc(&sp->so_count);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001327 p->o_arg.open_flags = flags;
1328 p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
Trond Myklebust536585c2016-11-10 15:40:34 -05001329 p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
Trond Myklebust6ae37332015-01-30 14:21:14 -05001330 p->o_arg.share_access = nfs4_map_atomic_open_share(server,
1331 fmode, flags);
Benjamin Coddington90910512019-06-07 06:37:30 -04001332 if (flags & O_CREAT) {
1333 p->o_arg.umask = current_umask();
1334 p->o_arg.label = nfs4_label_copy(p->a_label, label);
1335 if (c->sattr != NULL && c->sattr->ia_valid != 0) {
1336 p->o_arg.u.attrs = &p->attrs;
1337 memcpy(&p->attrs, c->sattr, sizeof(p->attrs));
1338
1339 memcpy(p->o_arg.u.verifier.data, c->verf,
1340 sizeof(p->o_arg.u.verifier.data));
1341 }
1342 }
Weston Andros Adamsonae2bb032012-10-02 14:49:52 -07001343 /* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS
1344 * will return permission denied for all bits until close */
1345 if (!(flags & O_EXCL)) {
1346 /* ask server to check for all possible rights as results
1347 * are cached */
Trond Myklebust536585c2016-11-10 15:40:34 -05001348 switch (p->o_arg.claim) {
1349 default:
1350 break;
1351 case NFS4_OPEN_CLAIM_NULL:
1352 case NFS4_OPEN_CLAIM_FH:
1353 p->o_arg.access = NFS4_ACCESS_READ |
1354 NFS4_ACCESS_MODIFY |
1355 NFS4_ACCESS_EXTEND |
1356 NFS4_ACCESS_EXECUTE;
Frank van der Linden72832a22020-06-23 22:38:58 +00001357#ifdef CONFIG_NFS_V4_2
1358 if (server->caps & NFS_CAP_XATTR)
1359 p->o_arg.access |= NFS4_ACCESS_XAREAD |
1360 NFS4_ACCESS_XAWRITE |
1361 NFS4_ACCESS_XALIST;
1362#endif
Trond Myklebust536585c2016-11-10 15:40:34 -05001363 }
Weston Andros Adamsonae2bb032012-10-02 14:49:52 -07001364 }
David Howells7539bba2006-08-22 20:06:09 -04001365 p->o_arg.clientid = server->nfs_client->cl_clientid;
Trond Myklebust95b72eb2012-04-20 19:24:51 -04001366 p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
1367 p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
Al Viro82a2c1b2011-06-22 18:30:55 -04001368 p->o_arg.name = &dentry->d_name;
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001369 p->o_arg.server = server;
David Quigleyaa9c2662013-05-22 12:50:44 -04001370 p->o_arg.bitmask = nfs4_bitmask(server, label);
Trond Myklebust1549210f2012-06-05 09:16:47 -04001371 p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001372 switch (p->o_arg.claim) {
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001373 case NFS4_OPEN_CLAIM_NULL:
1374 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
1375 case NFS4_OPEN_CLAIM_DELEGATE_PREV:
1376 p->o_arg.fh = NFS_FH(dir);
1377 break;
1378 case NFS4_OPEN_CLAIM_PREVIOUS:
1379 case NFS4_OPEN_CLAIM_FH:
1380 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
1381 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
David Howells2b0143b2015-03-17 22:25:59 +00001382 p->o_arg.fh = NFS_FH(d_inode(dentry));
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001383 }
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001384 p->c_arg.fh = &p->o_res.fh;
1385 p->c_arg.stateid = &p->o_res.stateid;
1386 p->c_arg.seqid = p->o_arg.seqid;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001387 nfs4_init_opendata_res(p);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001388 kref_init(&p->kref);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001389 return p;
David Quigley14c43f72013-05-22 12:50:43 -04001390
1391err_free_label:
Kinglong Meea49c2692015-07-27 15:31:38 +08001392 nfs4_label_free(p->a_label);
1393err_free_f:
David Quigley14c43f72013-05-22 12:50:43 -04001394 nfs4_label_free(p->f_label);
1395err_free_p:
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001396 kfree(p);
1397err:
1398 dput(parent);
1399 return NULL;
1400}
1401
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001402static void nfs4_opendata_free(struct kref *kref)
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001403{
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001404 struct nfs4_opendata *p = container_of(kref,
1405 struct nfs4_opendata, kref);
Al Viro82a2c1b2011-06-22 18:30:55 -04001406 struct super_block *sb = p->dentry->d_sb;
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001407
Fred Isaman30ae2412016-10-18 13:39:51 -04001408 nfs4_lgopen_release(p->lgp);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001409 nfs_free_seqid(p->o_arg.seqid);
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04001410 nfs4_sequence_free_slot(&p->o_res.seq_res);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001411 if (p->state != NULL)
1412 nfs4_put_open_state(p->state);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001413 nfs4_put_state_owner(p->owner);
David Quigley14c43f72013-05-22 12:50:43 -04001414
Kinglong Meea49c2692015-07-27 15:31:38 +08001415 nfs4_label_free(p->a_label);
David Quigley14c43f72013-05-22 12:50:43 -04001416 nfs4_label_free(p->f_label);
1417
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001418 dput(p->dir);
Al Viro82a2c1b2011-06-22 18:30:55 -04001419 dput(p->dentry);
1420 nfs_sb_deactive(sb);
Trond Myklebust6926afd2012-01-07 13:22:46 -05001421 nfs_fattr_free_names(&p->f_attr);
Trond Myklebuste911b812014-03-26 13:24:37 -07001422 kfree(p->f_attr.mdsthreshold);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001423 kfree(p);
1424}
1425
1426static void nfs4_opendata_put(struct nfs4_opendata *p)
1427{
1428 if (p != NULL)
1429 kref_put(&p->kref, nfs4_opendata_free);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001430}
1431
Trond Myklebust24311f82015-09-20 10:50:17 -04001432static bool nfs4_mode_match_open_stateid(struct nfs4_state *state,
1433 fmode_t fmode)
1434{
1435 switch(fmode & (FMODE_READ|FMODE_WRITE)) {
1436 case FMODE_READ|FMODE_WRITE:
1437 return state->n_rdwr != 0;
1438 case FMODE_WRITE:
1439 return state->n_wronly != 0;
1440 case FMODE_READ:
1441 return state->n_rdonly != 0;
1442 }
1443 WARN_ON_ONCE(1);
1444 return false;
1445}
1446
Trond Myklebustbe189f72018-09-27 17:12:33 -04001447static int can_open_cached(struct nfs4_state *state, fmode_t mode,
1448 int open_mode, enum open_claim_type4 claim)
Trond Myklebust6ee41262007-07-08 14:11:36 -04001449{
1450 int ret = 0;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001451
Trond Myklebust536e43d2012-01-17 22:04:26 -05001452 if (open_mode & (O_EXCL|O_TRUNC))
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001453 goto out;
Trond Myklebustbe189f72018-09-27 17:12:33 -04001454 switch (claim) {
1455 case NFS4_OPEN_CLAIM_NULL:
1456 case NFS4_OPEN_CLAIM_FH:
1457 goto out;
1458 default:
1459 break;
1460 }
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001461 switch (mode & (FMODE_READ|FMODE_WRITE)) {
Trond Myklebust6ee41262007-07-08 14:11:36 -04001462 case FMODE_READ:
Trond Myklebust88069f72009-12-08 08:33:16 -05001463 ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0
1464 && state->n_rdonly != 0;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001465 break;
1466 case FMODE_WRITE:
Trond Myklebust88069f72009-12-08 08:33:16 -05001467 ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0
1468 && state->n_wronly != 0;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001469 break;
1470 case FMODE_READ|FMODE_WRITE:
Trond Myklebust88069f72009-12-08 08:33:16 -05001471 ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0
1472 && state->n_rdwr != 0;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001473 }
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001474out:
Trond Myklebust6ee41262007-07-08 14:11:36 -04001475 return ret;
1476}
1477
Trond Myklebust2a606182015-08-19 22:30:00 -05001478static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode,
1479 enum open_claim_type4 claim)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001480{
Trond Myklebust652f89f2011-12-09 19:05:58 -05001481 if (delegation == NULL)
1482 return 0;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001483 if ((delegation->type & fmode) != fmode)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001484 return 0;
Trond Myklebust2a606182015-08-19 22:30:00 -05001485 switch (claim) {
1486 case NFS4_OPEN_CLAIM_NULL:
1487 case NFS4_OPEN_CLAIM_FH:
1488 break;
1489 case NFS4_OPEN_CLAIM_PREVIOUS:
1490 if (!test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
1491 break;
Gustavo A. R. Silva01e03bd2018-07-31 21:18:44 -05001492 /* Fall through */
Trond Myklebust2a606182015-08-19 22:30:00 -05001493 default:
1494 return 0;
1495 }
Trond Myklebustb7391f42008-12-23 15:21:52 -05001496 nfs_mark_delegation_referenced(delegation);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001497 return 1;
1498}
1499
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001500static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
Trond Myklebuste7616922006-01-03 09:55:13 +01001501{
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001502 switch (fmode) {
Trond Myklebuste7616922006-01-03 09:55:13 +01001503 case FMODE_WRITE:
1504 state->n_wronly++;
1505 break;
1506 case FMODE_READ:
1507 state->n_rdonly++;
1508 break;
1509 case FMODE_READ|FMODE_WRITE:
1510 state->n_rdwr++;
1511 }
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001512 nfs4_state_set_mode_locked(state, state->state | fmode);
Trond Myklebuste7616922006-01-03 09:55:13 +01001513}
1514
Trond Myklebust8a64c4e2016-09-22 13:39:21 -04001515#ifdef CONFIG_NFS_V4_1
1516static bool nfs_open_stateid_recover_openmode(struct nfs4_state *state)
1517{
1518 if (state->n_rdonly && !test_bit(NFS_O_RDONLY_STATE, &state->flags))
1519 return true;
1520 if (state->n_wronly && !test_bit(NFS_O_WRONLY_STATE, &state->flags))
1521 return true;
1522 if (state->n_rdwr && !test_bit(NFS_O_RDWR_STATE, &state->flags))
1523 return true;
1524 return false;
1525}
1526#endif /* CONFIG_NFS_V4_1 */
1527
Trond Myklebustc9399f22017-11-06 15:28:01 -05001528static void nfs_state_log_update_open_stateid(struct nfs4_state *state)
1529{
1530 if (test_and_clear_bit(NFS_STATE_CHANGE_WAIT, &state->flags))
1531 wake_up_all(&state->waitq);
1532}
1533
1534static void nfs_state_log_out_of_order_open_stateid(struct nfs4_state *state,
1535 const nfs4_stateid *stateid)
1536{
1537 u32 state_seqid = be32_to_cpu(state->open_stateid.seqid);
1538 u32 stateid_seqid = be32_to_cpu(stateid->seqid);
1539
1540 if (stateid_seqid == state_seqid + 1U ||
1541 (stateid_seqid == 1U && state_seqid == 0xffffffffU))
1542 nfs_state_log_update_open_stateid(state);
1543 else
1544 set_bit(NFS_STATE_CHANGE_WAIT, &state->flags);
1545}
1546
Trond Myklebust4f14c192014-02-12 19:15:06 -05001547static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state)
Trond Myklebust003707c2007-07-05 18:07:55 -04001548{
Trond Myklebust4f14c192014-02-12 19:15:06 -05001549 struct nfs_client *clp = state->owner->so_server->nfs_client;
1550 bool need_recover = false;
1551
1552 if (test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags) && state->n_rdonly)
1553 need_recover = true;
1554 if (test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags) && state->n_wronly)
1555 need_recover = true;
1556 if (test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags) && state->n_rdwr)
1557 need_recover = true;
1558 if (need_recover)
1559 nfs4_state_mark_reclaim_nograce(clp, state);
1560}
1561
Trond Myklebustc9399f22017-11-06 15:28:01 -05001562/*
1563 * Check for whether or not the caller may update the open stateid
1564 * to the value passed in by stateid.
1565 *
1566 * Note: This function relies heavily on the server implementing
1567 * RFC7530 Section 9.1.4.2, and RFC5661 Section 8.2.2
1568 * correctly.
1569 * i.e. The stateid seqids have to be initialised to 1, and
1570 * are then incremented on every state transition.
1571 */
Trond Myklebuste999e802014-02-10 18:20:47 -05001572static bool nfs_need_update_open_stateid(struct nfs4_state *state,
Trond Myklebustc9399f22017-11-06 15:28:01 -05001573 const nfs4_stateid *stateid)
Trond Myklebuste999e802014-02-10 18:20:47 -05001574{
Trond Myklebustc9399f22017-11-06 15:28:01 -05001575 if (test_bit(NFS_OPEN_STATE, &state->flags) == 0 ||
1576 !nfs4_stateid_match_other(stateid, &state->open_stateid)) {
1577 if (stateid->seqid == cpu_to_be32(1))
1578 nfs_state_log_update_open_stateid(state);
1579 else
1580 set_bit(NFS_STATE_CHANGE_WAIT, &state->flags);
Trond Myklebuste999e802014-02-10 18:20:47 -05001581 return true;
Trond Myklebust4f14c192014-02-12 19:15:06 -05001582 }
Trond Myklebustc9399f22017-11-06 15:28:01 -05001583
1584 if (nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
1585 nfs_state_log_out_of_order_open_stateid(state, stateid);
Trond Myklebuste999e802014-02-10 18:20:47 -05001586 return true;
Trond Myklebustc9399f22017-11-06 15:28:01 -05001587 }
Trond Myklebuste999e802014-02-10 18:20:47 -05001588 return false;
1589}
1590
Trond Myklebustf95549c2015-01-23 18:06:09 -05001591static void nfs_resync_open_stateid_locked(struct nfs4_state *state)
1592{
Trond Myklebust3c38cbe2015-07-22 13:46:13 -04001593 if (!(state->n_wronly || state->n_rdonly || state->n_rdwr))
1594 return;
Trond Myklebustf95549c2015-01-23 18:06:09 -05001595 if (state->n_wronly)
1596 set_bit(NFS_O_WRONLY_STATE, &state->flags);
1597 if (state->n_rdonly)
1598 set_bit(NFS_O_RDONLY_STATE, &state->flags);
1599 if (state->n_rdwr)
1600 set_bit(NFS_O_RDWR_STATE, &state->flags);
Trond Myklebust3c38cbe2015-07-22 13:46:13 -04001601 set_bit(NFS_OPEN_STATE, &state->flags);
Trond Myklebustf95549c2015-01-23 18:06:09 -05001602}
1603
Trond Myklebust226056c2014-02-11 10:41:07 -05001604static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
1605 nfs4_stateid *stateid, fmode_t fmode)
1606{
1607 clear_bit(NFS_O_RDWR_STATE, &state->flags);
1608 switch (fmode & (FMODE_READ|FMODE_WRITE)) {
1609 case FMODE_WRITE:
1610 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1611 break;
1612 case FMODE_READ:
1613 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1614 break;
1615 case 0:
1616 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1617 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1618 clear_bit(NFS_OPEN_STATE, &state->flags);
1619 }
1620 if (stateid == NULL)
1621 return;
Trond Myklebust3e7dfb12016-11-14 11:19:55 -05001622 /* Handle OPEN+OPEN_DOWNGRADE races */
1623 if (nfs4_stateid_match_other(stateid, &state->open_stateid) &&
1624 !nfs4_stateid_is_newer(stateid, &state->open_stateid)) {
Trond Myklebustf95549c2015-01-23 18:06:09 -05001625 nfs_resync_open_stateid_locked(state);
Trond Myklebustc9399f22017-11-06 15:28:01 -05001626 goto out;
Trond Myklebustf95549c2015-01-23 18:06:09 -05001627 }
Trond Myklebust003707c2007-07-05 18:07:55 -04001628 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
Trond Myklebustf597c532012-03-04 18:13:56 -05001629 nfs4_stateid_copy(&state->stateid, stateid);
1630 nfs4_stateid_copy(&state->open_stateid, stateid);
Trond Myklebustad9e02d2017-11-06 15:28:02 -05001631 trace_nfs4_open_stateid_update(state->inode, stateid, 0);
Trond Myklebustc9399f22017-11-06 15:28:01 -05001632out:
1633 nfs_state_log_update_open_stateid(state);
Trond Myklebust226056c2014-02-11 10:41:07 -05001634}
1635
Trond Myklebust4a1e2fe2015-08-30 18:37:59 -07001636static void nfs_clear_open_stateid(struct nfs4_state *state,
1637 nfs4_stateid *arg_stateid,
1638 nfs4_stateid *stateid, fmode_t fmode)
Trond Myklebust226056c2014-02-11 10:41:07 -05001639{
1640 write_seqlock(&state->seqlock);
Trond Myklebust3e7dfb12016-11-14 11:19:55 -05001641 /* Ignore, if the CLOSE argment doesn't match the current stateid */
1642 if (nfs4_state_match_open_stateid_other(state, arg_stateid))
1643 nfs_clear_open_stateid_locked(state, stateid, fmode);
Trond Myklebust226056c2014-02-11 10:41:07 -05001644 write_sequnlock(&state->seqlock);
Trond Myklebust4f14c192014-02-12 19:15:06 -05001645 if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
1646 nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
Trond Myklebust226056c2014-02-11 10:41:07 -05001647}
1648
Trond Myklebust1393d962016-09-22 13:39:13 -04001649static void nfs_set_open_stateid_locked(struct nfs4_state *state,
Trond Myklebustc9399f22017-11-06 15:28:01 -05001650 const nfs4_stateid *stateid, nfs4_stateid *freeme)
Trond Myklebuste9acf212019-01-22 14:01:16 -05001651 __must_hold(&state->owner->so_lock)
1652 __must_hold(&state->seqlock)
1653 __must_hold(RCU)
1654
Trond Myklebust003707c2007-07-05 18:07:55 -04001655{
Trond Myklebustc9399f22017-11-06 15:28:01 -05001656 DEFINE_WAIT(wait);
1657 int status = 0;
1658 for (;;) {
1659
1660 if (!nfs_need_update_open_stateid(state, stateid))
1661 return;
1662 if (!test_bit(NFS_STATE_CHANGE_WAIT, &state->flags))
Trond Myklebust003707c2007-07-05 18:07:55 -04001663 break;
Trond Myklebustc9399f22017-11-06 15:28:01 -05001664 if (status)
Trond Myklebust003707c2007-07-05 18:07:55 -04001665 break;
Trond Myklebustc9399f22017-11-06 15:28:01 -05001666 /* Rely on seqids for serialisation with NFSv4.0 */
1667 if (!nfs4_has_session(NFS_SERVER(state->inode)->nfs_client))
1668 break;
1669
1670 prepare_to_wait(&state->waitq, &wait, TASK_KILLABLE);
1671 /*
1672 * Ensure we process the state changes in the same order
1673 * in which the server processed them by delaying the
1674 * update of the stateid until we are in sequence.
1675 */
1676 write_sequnlock(&state->seqlock);
1677 spin_unlock(&state->owner->so_lock);
1678 rcu_read_unlock();
Trond Myklebustad9e02d2017-11-06 15:28:02 -05001679 trace_nfs4_open_stateid_update_wait(state->inode, stateid, 0);
Trond Myklebustc9399f22017-11-06 15:28:01 -05001680 if (!signal_pending(current)) {
1681 if (schedule_timeout(5*HZ) == 0)
1682 status = -EAGAIN;
1683 else
1684 status = 0;
1685 } else
1686 status = -EINTR;
1687 finish_wait(&state->waitq, &wait);
1688 rcu_read_lock();
1689 spin_lock(&state->owner->so_lock);
1690 write_seqlock(&state->seqlock);
Trond Myklebust003707c2007-07-05 18:07:55 -04001691 }
Trond Myklebustc9399f22017-11-06 15:28:01 -05001692
Trond Myklebuste1fff5d2017-11-07 13:10:46 -05001693 if (test_bit(NFS_OPEN_STATE, &state->flags) &&
1694 !nfs4_stateid_match_other(stateid, &state->open_stateid)) {
Trond Myklebustc9399f22017-11-06 15:28:01 -05001695 nfs4_stateid_copy(freeme, &state->open_stateid);
1696 nfs_test_and_clear_all_open_stateid(state);
1697 }
1698
Trond Myklebuste999e802014-02-10 18:20:47 -05001699 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
1700 nfs4_stateid_copy(&state->stateid, stateid);
1701 nfs4_stateid_copy(&state->open_stateid, stateid);
Trond Myklebustad9e02d2017-11-06 15:28:02 -05001702 trace_nfs4_open_stateid_update(state->inode, stateid, status);
Trond Myklebustc9399f22017-11-06 15:28:01 -05001703 nfs_state_log_update_open_stateid(state);
Trond Myklebust003707c2007-07-05 18:07:55 -04001704}
1705
Trond Myklebustc9399f22017-11-06 15:28:01 -05001706static void nfs_state_set_open_stateid(struct nfs4_state *state,
Trond Myklebust1393d962016-09-22 13:39:13 -04001707 const nfs4_stateid *open_stateid,
Trond Myklebust1393d962016-09-22 13:39:13 -04001708 fmode_t fmode,
1709 nfs4_stateid *freeme)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001710{
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001711 /*
1712 * Protect the call to nfs4_state_set_mode_locked and
1713 * serialise the stateid update
1714 */
1715 write_seqlock(&state->seqlock);
Trond Myklebustc9399f22017-11-06 15:28:01 -05001716 nfs_set_open_stateid_locked(state, open_stateid, freeme);
1717 switch (fmode) {
1718 case FMODE_READ:
1719 set_bit(NFS_O_RDONLY_STATE, &state->flags);
1720 break;
1721 case FMODE_WRITE:
1722 set_bit(NFS_O_WRONLY_STATE, &state->flags);
1723 break;
1724 case FMODE_READ|FMODE_WRITE:
1725 set_bit(NFS_O_RDWR_STATE, &state->flags);
Trond Myklebust003707c2007-07-05 18:07:55 -04001726 }
Trond Myklebustc9399f22017-11-06 15:28:01 -05001727 set_bit(NFS_OPEN_STATE, &state->flags);
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001728 write_sequnlock(&state->seqlock);
Trond Myklebustc9399f22017-11-06 15:28:01 -05001729}
1730
Trond Myklebust27a30cf2019-07-22 18:32:59 +01001731static void nfs_state_clear_open_state_flags(struct nfs4_state *state)
1732{
1733 clear_bit(NFS_O_RDWR_STATE, &state->flags);
1734 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
1735 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
1736 clear_bit(NFS_OPEN_STATE, &state->flags);
1737}
1738
Trond Myklebustc9399f22017-11-06 15:28:01 -05001739static void nfs_state_set_delegation(struct nfs4_state *state,
1740 const nfs4_stateid *deleg_stateid,
1741 fmode_t fmode)
1742{
1743 /*
1744 * Protect the call to nfs4_state_set_mode_locked and
1745 * serialise the stateid update
1746 */
1747 write_seqlock(&state->seqlock);
1748 nfs4_stateid_copy(&state->stateid, deleg_stateid);
1749 set_bit(NFS_DELEGATED_STATE, &state->flags);
1750 write_sequnlock(&state->seqlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751}
1752
Trond Myklebust9f0c5122018-09-05 14:07:15 -04001753static void nfs_state_clear_delegation(struct nfs4_state *state)
1754{
1755 write_seqlock(&state->seqlock);
1756 nfs4_stateid_copy(&state->stateid, &state->open_stateid);
1757 clear_bit(NFS_DELEGATED_STATE, &state->flags);
1758 write_sequnlock(&state->seqlock);
1759}
1760
Olga Kornievskaiaec4b0922019-10-08 16:33:53 -04001761int update_open_stateid(struct nfs4_state *state,
Trond Myklebust1393d962016-09-22 13:39:13 -04001762 const nfs4_stateid *open_stateid,
1763 const nfs4_stateid *delegation,
1764 fmode_t fmode)
Trond Myklebust34310432008-12-23 15:21:38 -05001765{
Trond Myklebust1393d962016-09-22 13:39:13 -04001766 struct nfs_server *server = NFS_SERVER(state->inode);
1767 struct nfs_client *clp = server->nfs_client;
Trond Myklebust34310432008-12-23 15:21:38 -05001768 struct nfs_inode *nfsi = NFS_I(state->inode);
1769 struct nfs_delegation *deleg_cur;
Arnd Bergmann83aa3e02016-10-18 17:21:30 +02001770 nfs4_stateid freeme = { };
Trond Myklebust34310432008-12-23 15:21:38 -05001771 int ret = 0;
1772
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001773 fmode &= (FMODE_READ|FMODE_WRITE);
Trond Myklebust34310432008-12-23 15:21:38 -05001774
1775 rcu_read_lock();
Trond Myklebustc9399f22017-11-06 15:28:01 -05001776 spin_lock(&state->owner->so_lock);
1777 if (open_stateid != NULL) {
1778 nfs_state_set_open_stateid(state, open_stateid, fmode, &freeme);
1779 ret = 1;
1780 }
1781
Trond Myklebust333ac782019-10-22 12:12:17 -04001782 deleg_cur = nfs4_get_valid_delegation(state->inode);
Trond Myklebust34310432008-12-23 15:21:38 -05001783 if (deleg_cur == NULL)
1784 goto no_delegation;
1785
1786 spin_lock(&deleg_cur->lock);
Trond Myklebust17f26b12013-08-21 15:48:42 -04001787 if (rcu_dereference(nfsi->delegation) != deleg_cur ||
Trond Myklebustd25be542013-02-05 11:43:28 -05001788 test_bit(NFS_DELEGATION_RETURNING, &deleg_cur->flags) ||
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001789 (deleg_cur->type & fmode) != fmode)
Trond Myklebust34310432008-12-23 15:21:38 -05001790 goto no_delegation_unlock;
1791
1792 if (delegation == NULL)
1793 delegation = &deleg_cur->stateid;
Trond Myklebust333ac782019-10-22 12:12:17 -04001794 else if (!nfs4_stateid_match_other(&deleg_cur->stateid, delegation))
Trond Myklebust34310432008-12-23 15:21:38 -05001795 goto no_delegation_unlock;
1796
Trond Myklebustb7391f42008-12-23 15:21:52 -05001797 nfs_mark_delegation_referenced(deleg_cur);
Trond Myklebustc9399f22017-11-06 15:28:01 -05001798 nfs_state_set_delegation(state, &deleg_cur->stateid, fmode);
Trond Myklebust34310432008-12-23 15:21:38 -05001799 ret = 1;
1800no_delegation_unlock:
1801 spin_unlock(&deleg_cur->lock);
1802no_delegation:
Trond Myklebustc9399f22017-11-06 15:28:01 -05001803 if (ret)
1804 update_open_stateflags(state, fmode);
1805 spin_unlock(&state->owner->so_lock);
Trond Myklebust34310432008-12-23 15:21:38 -05001806 rcu_read_unlock();
1807
Trond Myklebust4f14c192014-02-12 19:15:06 -05001808 if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
Trond Myklebust1393d962016-09-22 13:39:13 -04001809 nfs4_schedule_state_manager(clp);
1810 if (freeme.type != 0)
1811 nfs4_test_and_free_stateid(server, &freeme,
1812 state->owner->so_cred);
Trond Myklebust34310432008-12-23 15:21:38 -05001813
1814 return ret;
1815}
1816
Trond Myklebust39071e62015-01-24 15:07:56 -05001817static bool nfs4_update_lock_stateid(struct nfs4_lock_state *lsp,
1818 const nfs4_stateid *stateid)
1819{
1820 struct nfs4_state *state = lsp->ls_state;
1821 bool ret = false;
1822
1823 spin_lock(&state->state_lock);
1824 if (!nfs4_stateid_match_other(stateid, &lsp->ls_stateid))
1825 goto out_noupdate;
1826 if (!nfs4_stateid_is_newer(stateid, &lsp->ls_stateid))
1827 goto out_noupdate;
1828 nfs4_stateid_copy(&lsp->ls_stateid, stateid);
1829 ret = true;
1830out_noupdate:
1831 spin_unlock(&state->state_lock);
1832 return ret;
1833}
Trond Myklebust34310432008-12-23 15:21:38 -05001834
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001835static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001836{
1837 struct nfs_delegation *delegation;
1838
Trond Myklebustf5086242018-03-20 16:43:13 -04001839 fmode &= FMODE_READ|FMODE_WRITE;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001840 rcu_read_lock();
Trond Myklebust40e6aa12019-10-27 13:38:45 -04001841 delegation = nfs4_get_valid_delegation(inode);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001842 if (delegation == NULL || (delegation->type & fmode) == fmode) {
Trond Myklebustaac00a82007-07-05 19:02:21 -04001843 rcu_read_unlock();
1844 return;
1845 }
1846 rcu_read_unlock();
Bryan Schumaker57ec14c2012-06-20 15:53:44 -04001847 nfs4_inode_return_delegation(inode);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001848}
1849
Trond Myklebust6ee41262007-07-08 14:11:36 -04001850static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001851{
1852 struct nfs4_state *state = opendata->state;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001853 struct nfs_delegation *delegation;
Trond Myklebustf448bad2013-05-29 15:36:40 -04001854 int open_mode = opendata->o_arg.open_flags;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001855 fmode_t fmode = opendata->o_arg.fmode;
Trond Myklebust2a606182015-08-19 22:30:00 -05001856 enum open_claim_type4 claim = opendata->o_arg.claim;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001857 nfs4_stateid stateid;
1858 int ret = -EAGAIN;
1859
Trond Myklebustaac00a82007-07-05 19:02:21 -04001860 for (;;) {
Anna Schumaker61beef72014-09-03 14:15:40 -04001861 spin_lock(&state->owner->so_lock);
Trond Myklebustbe189f72018-09-27 17:12:33 -04001862 if (can_open_cached(state, fmode, open_mode, claim)) {
Anna Schumaker61beef72014-09-03 14:15:40 -04001863 update_open_stateflags(state, fmode);
Trond Myklebust6ee41262007-07-08 14:11:36 -04001864 spin_unlock(&state->owner->so_lock);
Anna Schumaker61beef72014-09-03 14:15:40 -04001865 goto out_return_state;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001866 }
Anna Schumaker61beef72014-09-03 14:15:40 -04001867 spin_unlock(&state->owner->so_lock);
Trond Myklebust34310432008-12-23 15:21:38 -05001868 rcu_read_lock();
Trond Myklebustbe3df3d2019-10-31 18:40:32 -04001869 delegation = nfs4_get_valid_delegation(state->inode);
Trond Myklebust2a606182015-08-19 22:30:00 -05001870 if (!can_open_delegated(delegation, fmode, claim)) {
Trond Myklebust34310432008-12-23 15:21:38 -05001871 rcu_read_unlock();
Trond Myklebust6ee41262007-07-08 14:11:36 -04001872 break;
Trond Myklebust34310432008-12-23 15:21:38 -05001873 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04001874 /* Save the delegation */
Trond Myklebustf597c532012-03-04 18:13:56 -05001875 nfs4_stateid_copy(&stateid, &delegation->stateid);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001876 rcu_read_unlock();
Trond Myklebustfa332942013-04-09 12:56:52 -04001877 nfs_release_seqid(opendata->o_arg.seqid);
Trond Myklebustbdeca1b2013-04-23 14:52:44 -04001878 if (!opendata->is_recover) {
1879 ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
1880 if (ret != 0)
1881 goto out;
1882 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04001883 ret = -EAGAIN;
Trond Myklebust34310432008-12-23 15:21:38 -05001884
1885 /* Try to update the stateid using the delegation */
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001886 if (update_open_stateid(state, NULL, &stateid, fmode))
Trond Myklebust34310432008-12-23 15:21:38 -05001887 goto out_return_state;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001888 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04001889out:
1890 return ERR_PTR(ret);
1891out_return_state:
Trond Myklebustace9fad2018-09-02 19:19:07 -04001892 refcount_inc(&state->count);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001893 return state;
1894}
1895
Andy Adamsone23008e2012-10-02 21:07:32 -04001896static void
1897nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
1898{
1899 struct nfs_client *clp = NFS_SERVER(state->inode)->nfs_client;
1900 struct nfs_delegation *delegation;
1901 int delegation_flags = 0;
1902
1903 rcu_read_lock();
1904 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
1905 if (delegation)
1906 delegation_flags = delegation->flags;
1907 rcu_read_unlock();
Trond Myklebust72d79ff2015-10-02 11:44:54 -04001908 switch (data->o_arg.claim) {
1909 default:
1910 break;
1911 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
1912 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
Andy Adamsone23008e2012-10-02 21:07:32 -04001913 pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
1914 "returning a delegation for "
1915 "OPEN(CLAIM_DELEGATE_CUR)\n",
1916 clp->cl_hostname);
Trond Myklebust72d79ff2015-10-02 11:44:54 -04001917 return;
1918 }
1919 if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
Andy Adamsone23008e2012-10-02 21:07:32 -04001920 nfs_inode_set_delegation(state->inode,
Trond Myklebust35156bf2018-03-20 17:03:13 -04001921 data->owner->so_cred,
1922 data->o_res.delegation_type,
1923 &data->o_res.delegation,
1924 data->o_res.pagemod_limit);
Andy Adamsone23008e2012-10-02 21:07:32 -04001925 else
1926 nfs_inode_reclaim_delegation(state->inode,
Trond Myklebust35156bf2018-03-20 17:03:13 -04001927 data->owner->so_cred,
1928 data->o_res.delegation_type,
1929 &data->o_res.delegation,
1930 data->o_res.pagemod_limit);
Jeff Layton8b199e52018-07-05 05:48:14 -04001931
1932 if (data->o_res.do_recall)
1933 nfs_async_inode_return_delegation(state->inode,
1934 &data->o_res.delegation);
Andy Adamsone23008e2012-10-02 21:07:32 -04001935}
1936
1937/*
1938 * Check the inode attributes against the CLAIM_PREVIOUS returned attributes
1939 * and update the nfs4_state.
1940 */
1941static struct nfs4_state *
1942_nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
1943{
1944 struct inode *inode = data->state->inode;
1945 struct nfs4_state *state = data->state;
1946 int ret;
1947
Weston Andros Adamsond2bfda22013-10-21 13:10:13 -04001948 if (!data->rpc_done) {
Anna Schumaker37a84842017-01-11 16:08:35 -05001949 if (data->rpc_status)
1950 return ERR_PTR(data->rpc_status);
Weston Andros Adamsond2bfda22013-10-21 13:10:13 -04001951 /* cached opens have already been processed */
1952 goto update;
Andy Adamsone23008e2012-10-02 21:07:32 -04001953 }
1954
Andy Adamsone23008e2012-10-02 21:07:32 -04001955 ret = nfs_refresh_inode(inode, &data->f_attr);
1956 if (ret)
Anna Schumaker37a84842017-01-11 16:08:35 -05001957 return ERR_PTR(ret);
Andy Adamsone23008e2012-10-02 21:07:32 -04001958
1959 if (data->o_res.delegation_type != 0)
1960 nfs4_opendata_check_deleg(data, state);
Weston Andros Adamsond2bfda22013-10-21 13:10:13 -04001961update:
Trond Myklebuste3c8dc72019-07-29 18:25:00 +01001962 if (!update_open_stateid(state, &data->o_res.stateid,
1963 NULL, data->o_arg.fmode))
1964 return ERR_PTR(-EAGAIN);
Trond Myklebustace9fad2018-09-02 19:19:07 -04001965 refcount_inc(&state->count);
Andy Adamsone23008e2012-10-02 21:07:32 -04001966
1967 return state;
Andy Adamsone23008e2012-10-02 21:07:32 -04001968}
1969
Trond Myklebust4e2fcac2017-08-08 09:06:18 -04001970static struct inode *
1971nfs4_opendata_get_inode(struct nfs4_opendata *data)
1972{
1973 struct inode *inode;
1974
1975 switch (data->o_arg.claim) {
1976 case NFS4_OPEN_CLAIM_NULL:
1977 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
1978 case NFS4_OPEN_CLAIM_DELEGATE_PREV:
1979 if (!(data->f_attr.valid & NFS_ATTR_FATTR))
1980 return ERR_PTR(-EAGAIN);
1981 inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh,
1982 &data->f_attr, data->f_label);
1983 break;
1984 default:
1985 inode = d_inode(data->dentry);
1986 ihold(inode);
1987 nfs_refresh_inode(inode, &data->f_attr);
1988 }
1989 return inode;
1990}
1991
Andy Adamsone23008e2012-10-02 21:07:32 -04001992static struct nfs4_state *
Trond Myklebust75e8c482017-08-08 10:38:07 -04001993nfs4_opendata_find_nfs4_state(struct nfs4_opendata *data)
1994{
1995 struct nfs4_state *state;
1996 struct inode *inode;
1997
1998 inode = nfs4_opendata_get_inode(data);
1999 if (IS_ERR(inode))
2000 return ERR_CAST(inode);
2001 if (data->state != NULL && data->state->inode == inode) {
2002 state = data->state;
Trond Myklebustace9fad2018-09-02 19:19:07 -04002003 refcount_inc(&state->count);
Trond Myklebust75e8c482017-08-08 10:38:07 -04002004 } else
2005 state = nfs4_get_open_state(inode, data->owner);
2006 iput(inode);
2007 if (state == NULL)
2008 state = ERR_PTR(-ENOMEM);
2009 return state;
2010}
2011
Andy Adamsone23008e2012-10-02 21:07:32 -04002012static struct nfs4_state *
2013_nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002014{
Trond Myklebust75e8c482017-08-08 10:38:07 -04002015 struct nfs4_state *state;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002016
Trond Myklebustaac00a82007-07-05 19:02:21 -04002017 if (!data->rpc_done) {
Trond Myklebust6ee41262007-07-08 14:11:36 -04002018 state = nfs4_try_open_cached(data);
Olga Kornievskaia9759b0f2015-11-24 13:29:42 -05002019 trace_nfs4_cached_open(data->state);
Trond Myklebustaac00a82007-07-05 19:02:21 -04002020 goto out;
2021 }
2022
Trond Myklebust75e8c482017-08-08 10:38:07 -04002023 state = nfs4_opendata_find_nfs4_state(data);
2024 if (IS_ERR(state))
2025 goto out;
2026
Andy Adamsone23008e2012-10-02 21:07:32 -04002027 if (data->o_res.delegation_type != 0)
2028 nfs4_opendata_check_deleg(data, state);
Trond Myklebuste3c8dc72019-07-29 18:25:00 +01002029 if (!update_open_stateid(state, &data->o_res.stateid,
2030 NULL, data->o_arg.fmode)) {
2031 nfs4_put_open_state(state);
2032 state = ERR_PTR(-EAGAIN);
2033 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04002034out:
Trond Myklebust7aa262b52013-02-28 16:19:59 -08002035 nfs_release_seqid(data->o_arg.seqid);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002036 return state;
2037}
2038
Andy Adamsone23008e2012-10-02 21:07:32 -04002039static struct nfs4_state *
2040nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
2041{
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04002042 struct nfs4_state *ret;
2043
Andy Adamsone23008e2012-10-02 21:07:32 -04002044 if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04002045 ret =_nfs4_opendata_reclaim_to_nfs4_state(data);
2046 else
2047 ret = _nfs4_opendata_to_nfs4_state(data);
2048 nfs4_sequence_free_slot(&data->o_res.seq_res);
2049 return ret;
Andy Adamsone23008e2012-10-02 21:07:32 -04002050}
2051
Trond Myklebust0de43972018-09-02 15:57:01 -04002052static struct nfs_open_context *
2053nfs4_state_find_open_context_mode(struct nfs4_state *state, fmode_t mode)
Trond Myklebust864472e2006-01-03 09:55:15 +01002054{
2055 struct nfs_inode *nfsi = NFS_I(state->inode);
2056 struct nfs_open_context *ctx;
2057
Trond Myklebust0de43972018-09-02 15:57:01 -04002058 rcu_read_lock();
2059 list_for_each_entry_rcu(ctx, &nfsi->open_files, list) {
Trond Myklebust864472e2006-01-03 09:55:15 +01002060 if (ctx->state != state)
2061 continue;
Trond Myklebust0de43972018-09-02 15:57:01 -04002062 if ((ctx->mode & mode) != mode)
2063 continue;
2064 if (!get_nfs_open_context(ctx))
2065 continue;
2066 rcu_read_unlock();
Trond Myklebust864472e2006-01-03 09:55:15 +01002067 return ctx;
2068 }
Trond Myklebust0de43972018-09-02 15:57:01 -04002069 rcu_read_unlock();
Trond Myklebust864472e2006-01-03 09:55:15 +01002070 return ERR_PTR(-ENOENT);
2071}
2072
Trond Myklebust0de43972018-09-02 15:57:01 -04002073static struct nfs_open_context *
2074nfs4_state_find_open_context(struct nfs4_state *state)
2075{
2076 struct nfs_open_context *ctx;
2077
2078 ctx = nfs4_state_find_open_context_mode(state, FMODE_READ|FMODE_WRITE);
2079 if (!IS_ERR(ctx))
2080 return ctx;
2081 ctx = nfs4_state_find_open_context_mode(state, FMODE_WRITE);
2082 if (!IS_ERR(ctx))
2083 return ctx;
2084 return nfs4_state_find_open_context_mode(state, FMODE_READ);
2085}
2086
Trond Myklebust4a1c0892013-03-15 14:57:33 -04002087static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx,
2088 struct nfs4_state *state, enum open_claim_type4 claim)
Trond Myklebust6f220ed2007-07-17 21:50:45 -04002089{
2090 struct nfs4_opendata *opendata;
2091
Trond Myklebust4a1c0892013-03-15 14:57:33 -04002092 opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0,
Trond Myklebust8fd1ab72017-11-06 15:28:03 -05002093 NULL, claim, GFP_NOFS);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04002094 if (opendata == NULL)
2095 return ERR_PTR(-ENOMEM);
2096 opendata->state = state;
Trond Myklebustace9fad2018-09-02 19:19:07 -04002097 refcount_inc(&state->count);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04002098 return opendata;
2099}
2100
Trond Myklebust24311f82015-09-20 10:50:17 -04002101static int nfs4_open_recover_helper(struct nfs4_opendata *opendata,
2102 fmode_t fmode)
Trond Myklebust864472e2006-01-03 09:55:15 +01002103{
Trond Myklebust2ced46c2007-07-03 23:48:13 -04002104 struct nfs4_state *newstate;
Trond Myklebust864472e2006-01-03 09:55:15 +01002105 int ret;
2106
Trond Myklebust24311f82015-09-20 10:50:17 -04002107 if (!nfs4_mode_match_open_stateid(opendata->state, fmode))
NeilBrown39f897f2015-06-29 14:28:54 +10002108 return 0;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05002109 opendata->o_arg.open_flags = 0;
2110 opendata->o_arg.fmode = fmode;
Trond Myklebustbe36e182015-02-27 17:04:17 -05002111 opendata->o_arg.share_access = nfs4_map_atomic_open_share(
2112 NFS_SB(opendata->dentry->d_sb),
2113 fmode, 0);
Trond Myklebust2ced46c2007-07-03 23:48:13 -04002114 memset(&opendata->o_res, 0, sizeof(opendata->o_res));
2115 memset(&opendata->c_res, 0, sizeof(opendata->c_res));
2116 nfs4_init_opendata_res(opendata);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002117 ret = _nfs4_recover_proc_open(opendata);
Trond Myklebust864472e2006-01-03 09:55:15 +01002118 if (ret != 0)
2119 return ret;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04002120 newstate = nfs4_opendata_to_nfs4_state(opendata);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04002121 if (IS_ERR(newstate))
2122 return PTR_ERR(newstate);
Trond Myklebust24311f82015-09-20 10:50:17 -04002123 if (newstate != opendata->state)
2124 ret = -ESTALE;
Al Viro643168c2011-06-22 18:20:23 -04002125 nfs4_close_state(newstate, fmode);
Trond Myklebust24311f82015-09-20 10:50:17 -04002126 return ret;
Trond Myklebust864472e2006-01-03 09:55:15 +01002127}
2128
2129static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state)
2130{
Trond Myklebust864472e2006-01-03 09:55:15 +01002131 int ret;
2132
2133 /* memory barrier prior to reading state->n_* */
2134 smp_rmb();
Trond Myklebust24311f82015-09-20 10:50:17 -04002135 ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
2136 if (ret != 0)
2137 return ret;
2138 ret = nfs4_open_recover_helper(opendata, FMODE_WRITE);
2139 if (ret != 0)
2140 return ret;
2141 ret = nfs4_open_recover_helper(opendata, FMODE_READ);
2142 if (ret != 0)
2143 return ret;
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04002144 /*
2145 * We may have performed cached opens for all three recoveries.
2146 * Check if we need to update the current stateid.
2147 */
2148 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
Trond Myklebustf597c532012-03-04 18:13:56 -05002149 !nfs4_stateid_match(&state->stateid, &state->open_stateid)) {
Trond Myklebust8bda4e42007-07-09 10:45:42 -04002150 write_seqlock(&state->seqlock);
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04002151 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
Trond Myklebustf597c532012-03-04 18:13:56 -05002152 nfs4_stateid_copy(&state->stateid, &state->open_stateid);
Trond Myklebust8bda4e42007-07-09 10:45:42 -04002153 write_sequnlock(&state->seqlock);
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04002154 }
Trond Myklebust864472e2006-01-03 09:55:15 +01002155 return 0;
2156}
2157
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158/*
2159 * OPEN_RECLAIM:
2160 * reclaim state on the server after a reboot.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161 */
Trond Myklebust539cd032007-06-05 11:46:42 -04002162static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163{
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04002164 struct nfs_delegation *delegation;
Trond Myklebust864472e2006-01-03 09:55:15 +01002165 struct nfs4_opendata *opendata;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05002166 fmode_t delegation_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 int status;
2168
Trond Myklebust4a1c0892013-03-15 14:57:33 -04002169 opendata = nfs4_open_recoverdata_alloc(ctx, state,
2170 NFS4_OPEN_CLAIM_PREVIOUS);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04002171 if (IS_ERR(opendata))
2172 return PTR_ERR(opendata);
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04002173 rcu_read_lock();
2174 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
Trond Myklebust15c831b2008-12-23 15:21:39 -05002175 if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0)
Trond Myklebust65bbf6b2007-08-27 09:57:46 -04002176 delegation_type = delegation->type;
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04002177 rcu_read_unlock();
Trond Myklebust864472e2006-01-03 09:55:15 +01002178 opendata->o_arg.u.delegation_type = delegation_type;
2179 status = nfs4_open_recover(opendata, state);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002180 nfs4_opendata_put(opendata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 return status;
2182}
2183
Trond Myklebust539cd032007-06-05 11:46:42 -04002184static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185{
2186 struct nfs_server *server = NFS_SERVER(state->inode);
2187 struct nfs4_exception exception = { };
2188 int err;
2189 do {
Trond Myklebust539cd032007-06-05 11:46:42 -04002190 err = _nfs4_do_open_reclaim(ctx, state);
Trond Myklebust42113a72013-08-12 16:19:27 -04002191 trace_nfs4_open_reclaim(ctx, 0, err);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002192 if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
2193 continue;
Trond Myklebust168667c2010-10-19 19:47:49 -04002194 if (err != -NFS4ERR_DELAY)
Trond Myklebust202b50d2005-06-22 17:16:29 +00002195 break;
2196 nfs4_handle_exception(server, err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197 } while (exception.retry);
2198 return err;
2199}
2200
Trond Myklebust864472e2006-01-03 09:55:15 +01002201static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
2202{
2203 struct nfs_open_context *ctx;
2204 int ret;
2205
2206 ctx = nfs4_state_find_open_context(state);
2207 if (IS_ERR(ctx))
Trond Myklebust91876b12013-03-28 14:01:33 -04002208 return -EAGAIN;
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002209 clear_bit(NFS_DELEGATED_STATE, &state->flags);
2210 nfs_state_clear_open_state_flags(state);
Trond Myklebust539cd032007-06-05 11:46:42 -04002211 ret = nfs4_do_open_reclaim(ctx, state);
Trond Myklebust864472e2006-01-03 09:55:15 +01002212 put_nfs_open_context(ctx);
2213 return ret;
2214}
2215
NeilBrowndce26302017-12-13 09:57:09 +11002216static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, struct file_lock *fl, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002217{
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002218 switch (err) {
2219 default:
2220 printk(KERN_ERR "NFS: %s: unhandled error "
2221 "%d.\n", __func__, err);
2222 case 0:
2223 case -ENOENT:
Trond Myklebust8eee52a2015-06-04 13:51:13 -04002224 case -EAGAIN:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002225 case -ESTALE:
Trond Myklebust67e7b522019-08-07 07:31:27 -04002226 case -ETIMEDOUT:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002227 break;
2228 case -NFS4ERR_BADSESSION:
2229 case -NFS4ERR_BADSLOT:
2230 case -NFS4ERR_BAD_HIGH_SLOT:
2231 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
2232 case -NFS4ERR_DEADSESSION:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002233 return -EAGAIN;
2234 case -NFS4ERR_STALE_CLIENTID:
2235 case -NFS4ERR_STALE_STATEID:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002236 /* Don't recall a delegation if it was lost */
2237 nfs4_schedule_lease_recovery(server->nfs_client);
2238 return -EAGAIN;
Chuck Lever352297b2013-10-17 14:13:24 -04002239 case -NFS4ERR_MOVED:
2240 nfs4_schedule_migration_recovery(server);
2241 return -EAGAIN;
Chuck Lever8ef2f8d2013-10-17 14:13:41 -04002242 case -NFS4ERR_LEASE_MOVED:
2243 nfs4_schedule_lease_moved_recovery(server->nfs_client);
2244 return -EAGAIN;
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002245 case -NFS4ERR_DELEG_REVOKED:
2246 case -NFS4ERR_ADMIN_REVOKED:
Trond Myklebust404ea3562016-09-22 13:39:08 -04002247 case -NFS4ERR_EXPIRED:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002248 case -NFS4ERR_BAD_STATEID:
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04002249 case -NFS4ERR_OPENMODE:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002250 nfs_inode_find_state_and_recover(state->inode,
2251 stateid);
2252 nfs4_schedule_stateid_recovery(server, state);
Trond Myklebust869f9df2014-11-10 18:43:56 -05002253 return -EAGAIN;
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002254 case -NFS4ERR_DELAY:
2255 case -NFS4ERR_GRACE:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002256 ssleep(1);
2257 return -EAGAIN;
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04002258 case -ENOMEM:
2259 case -NFS4ERR_DENIED:
NeilBrowndce26302017-12-13 09:57:09 +11002260 if (fl) {
2261 struct nfs4_lock_state *lsp = fl->fl_u.nfs4_fl.owner;
2262 if (lsp)
2263 set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
2264 }
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04002265 return 0;
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04002266 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002267 return err;
2268}
2269
Trond Myklebust24311f82015-09-20 10:50:17 -04002270int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
Trond Myklebust5eb8d182019-07-19 14:08:37 -04002271 struct nfs4_state *state, const nfs4_stateid *stateid)
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04002272{
2273 struct nfs_server *server = NFS_SERVER(state->inode);
2274 struct nfs4_opendata *opendata;
Trond Myklebust24311f82015-09-20 10:50:17 -04002275 int err = 0;
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04002276
2277 opendata = nfs4_open_recoverdata_alloc(ctx, state,
2278 NFS4_OPEN_CLAIM_DELEG_CUR_FH);
2279 if (IS_ERR(opendata))
2280 return PTR_ERR(opendata);
2281 nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
Trond Myklebust5eb8d182019-07-19 14:08:37 -04002282 if (!test_bit(NFS_O_RDWR_STATE, &state->flags)) {
Trond Myklebust24311f82015-09-20 10:50:17 -04002283 err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
2284 if (err)
Trond Myklebust5eb8d182019-07-19 14:08:37 -04002285 goto out;
2286 }
2287 if (!test_bit(NFS_O_WRONLY_STATE, &state->flags)) {
Trond Myklebust24311f82015-09-20 10:50:17 -04002288 err = nfs4_open_recover_helper(opendata, FMODE_WRITE);
2289 if (err)
Trond Myklebust5eb8d182019-07-19 14:08:37 -04002290 goto out;
Trond Myklebust24311f82015-09-20 10:50:17 -04002291 }
Trond Myklebust5eb8d182019-07-19 14:08:37 -04002292 if (!test_bit(NFS_O_RDONLY_STATE, &state->flags)) {
2293 err = nfs4_open_recover_helper(opendata, FMODE_READ);
2294 if (err)
2295 goto out;
2296 }
2297 nfs_state_clear_delegation(state);
2298out:
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04002299 nfs4_opendata_put(opendata);
NeilBrowndce26302017-12-13 09:57:09 +11002300 return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err);
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04002301}
2302
Chuck Leverbe05c862013-08-09 12:49:47 -04002303static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata)
2304{
2305 struct nfs4_opendata *data = calldata;
2306
Anna Schumaker7981c8a2017-01-10 11:39:53 -05002307 nfs4_setup_sequence(data->o_arg.server->nfs_client,
2308 &data->c_arg.seq_args, &data->c_res.seq_res, task);
Chuck Leverbe05c862013-08-09 12:49:47 -04002309}
2310
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002311static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
2312{
2313 struct nfs4_opendata *data = calldata;
2314
Trond Myklebust17ead6c2014-02-01 14:53:23 -05002315 nfs40_sequence_done(task, &data->c_res.seq_res);
Chuck Leverbe05c862013-08-09 12:49:47 -04002316
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002317 data->rpc_status = task->tk_status;
Trond Myklebust26e976a2006-01-03 09:55:21 +01002318 if (data->rpc_status == 0) {
Trond Myklebustf597c532012-03-04 18:13:56 -05002319 nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
Trond Myklebustbb226292008-01-02 15:19:18 -05002320 nfs_confirm_seqid(&data->owner->so_seqid, 0);
Trond Myklebust26e976a2006-01-03 09:55:21 +01002321 renew_lease(data->o_res.server, data->timestamp);
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002322 data->rpc_done = true;
Trond Myklebust26e976a2006-01-03 09:55:21 +01002323 }
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002324}
2325
2326static void nfs4_open_confirm_release(void *calldata)
2327{
2328 struct nfs4_opendata *data = calldata;
2329 struct nfs4_state *state = NULL;
2330
2331 /* If this request hasn't been cancelled, do nothing */
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002332 if (!data->cancelled)
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002333 goto out_free;
2334 /* In case of error, no cleanup! */
Trond Myklebust3e309912007-07-07 13:19:59 -04002335 if (!data->rpc_done)
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002336 goto out_free;
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002337 state = nfs4_opendata_to_nfs4_state(data);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04002338 if (!IS_ERR(state))
Al Viro643168c2011-06-22 18:20:23 -04002339 nfs4_close_state(state, data->o_arg.fmode);
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002340out_free:
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002341 nfs4_opendata_put(data);
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002342}
2343
2344static const struct rpc_call_ops nfs4_open_confirm_ops = {
Chuck Leverbe05c862013-08-09 12:49:47 -04002345 .rpc_call_prepare = nfs4_open_confirm_prepare,
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002346 .rpc_call_done = nfs4_open_confirm_done,
2347 .rpc_release = nfs4_open_confirm_release,
2348};
2349
2350/*
2351 * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata
2352 */
2353static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
2354{
David Howells2b0143b2015-03-17 22:25:59 +00002355 struct nfs_server *server = NFS_SERVER(d_inode(data->dir));
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002356 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04002357 struct rpc_message msg = {
2358 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM],
2359 .rpc_argp = &data->c_arg,
2360 .rpc_resp = &data->c_res,
2361 .rpc_cred = data->owner->so_cred,
2362 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04002363 struct rpc_task_setup task_setup_data = {
2364 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04002365 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002366 .callback_ops = &nfs4_open_confirm_ops,
2367 .callback_data = data,
Trond Myklebust101070c2008-02-19 20:04:23 -05002368 .workqueue = nfsiod_workqueue,
Trond Myklebust61296502020-02-07 19:38:12 -05002369 .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002370 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 int status;
2372
Anna Schumakerfba83f32018-05-04 16:22:50 -04002373 nfs4_init_sequence(&data->c_arg.seq_args, &data->c_res.seq_res, 1,
2374 data->is_recover);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002375 kref_get(&data->kref);
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002376 data->rpc_done = false;
Trond Myklebust3e309912007-07-07 13:19:59 -04002377 data->rpc_status = 0;
Trond Myklebust5138fde2007-07-14 15:40:01 -04002378 data->timestamp = jiffies;
Trond Myklebustc970aa82007-07-14 15:39:59 -04002379 task = rpc_run_task(&task_setup_data);
Trond Myklebust7a1218a2006-03-20 18:11:10 -05002380 if (IS_ERR(task))
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002381 return PTR_ERR(task);
Anna Schumaker820bf852017-01-11 15:01:43 -05002382 status = rpc_wait_for_completion_task(task);
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002383 if (status != 0) {
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002384 data->cancelled = true;
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002385 smp_wmb();
2386 } else
2387 status = data->rpc_status;
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05002388 rpc_put_task(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002389 return status;
2390}
2391
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002392static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002393{
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002394 struct nfs4_opendata *data = calldata;
2395 struct nfs4_state_owner *sp = data->owner;
Trond Myklebust549b19c2013-04-16 18:42:34 -04002396 struct nfs_client *clp = sp->so_server->nfs_client;
Trond Myklebust2a606182015-08-19 22:30:00 -05002397 enum open_claim_type4 claim = data->o_arg.claim;
Trond Myklebust5138fde2007-07-14 15:40:01 -04002398
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002399 if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05002400 goto out_wait;
Trond Myklebustaac00a82007-07-05 19:02:21 -04002401 /*
2402 * Check if we still need to send an OPEN call, or if we can use
2403 * a delegation instead.
2404 */
2405 if (data->state != NULL) {
2406 struct nfs_delegation *delegation;
2407
Trond Myklebustbe189f72018-09-27 17:12:33 -04002408 if (can_open_cached(data->state, data->o_arg.fmode,
2409 data->o_arg.open_flags, claim))
Trond Myklebust6ee41262007-07-08 14:11:36 -04002410 goto out_no_action;
Trond Myklebustaac00a82007-07-05 19:02:21 -04002411 rcu_read_lock();
Trond Myklebustbe3df3d2019-10-31 18:40:32 -04002412 delegation = nfs4_get_valid_delegation(data->state->inode);
Trond Myklebust2a606182015-08-19 22:30:00 -05002413 if (can_open_delegated(delegation, data->o_arg.fmode, claim))
Trond Myklebust652f89f2011-12-09 19:05:58 -05002414 goto unlock_no_action;
Trond Myklebustaac00a82007-07-05 19:02:21 -04002415 rcu_read_unlock();
2416 }
Trond Myklebust95b72eb2012-04-20 19:24:51 -04002417 /* Update client id. */
Trond Myklebust549b19c2013-04-16 18:42:34 -04002418 data->o_arg.clientid = clp->cl_clientid;
Trond Myklebust2a606182015-08-19 22:30:00 -05002419 switch (claim) {
2420 default:
2421 break;
Trond Myklebust8188df12013-04-23 14:31:19 -04002422 case NFS4_OPEN_CLAIM_PREVIOUS:
2423 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
2424 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
Andy Adamsone23008e2012-10-02 21:07:32 -04002425 data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
Gustavo A. R. Silva01e03bd2018-07-31 21:18:44 -05002426 /* Fall through */
Trond Myklebust8188df12013-04-23 14:31:19 -04002427 case NFS4_OPEN_CLAIM_FH:
2428 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
Trond Myklebust6f220ed2007-07-17 21:50:45 -04002429 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01002430 data->timestamp = jiffies;
Anna Schumaker42e1cca2017-01-09 15:48:22 -05002431 if (nfs4_setup_sequence(data->o_arg.server->nfs_client,
Andy Adamsond8985282009-04-01 09:22:21 -04002432 &data->o_arg.seq_args,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04002433 &data->o_res.seq_res,
2434 task) != 0)
2435 nfs_release_seqid(data->o_arg.seqid);
Trond Myklebust549b19c2013-04-16 18:42:34 -04002436
2437 /* Set the create mode (note dependency on the session type) */
2438 data->o_arg.createmode = NFS4_CREATE_UNCHECKED;
2439 if (data->o_arg.open_flags & O_EXCL) {
2440 data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE;
2441 if (nfs4_has_persistent_session(clp))
2442 data->o_arg.createmode = NFS4_CREATE_GUARDED;
2443 else if (clp->cl_mvops->minor_version > 0)
2444 data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE4_1;
2445 }
Trond Myklebust6ee41262007-07-08 14:11:36 -04002446 return;
Trond Myklebust652f89f2011-12-09 19:05:58 -05002447unlock_no_action:
Olga Kornievskaia9759b0f2015-11-24 13:29:42 -05002448 trace_nfs4_cached_open(data->state);
Trond Myklebust652f89f2011-12-09 19:05:58 -05002449 rcu_read_unlock();
Trond Myklebust6ee41262007-07-08 14:11:36 -04002450out_no_action:
2451 task->tk_action = NULL;
Trond Myklebustc8da19b2013-02-11 19:01:21 -05002452out_wait:
Trond Myklebustb75ad4c2012-11-29 17:27:47 -05002453 nfs4_sequence_done(task, &data->o_res.seq_res);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002454}
2455
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002456static void nfs4_open_done(struct rpc_task *task, void *calldata)
2457{
2458 struct nfs4_opendata *data = calldata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002460 data->rpc_status = task->tk_status;
Andy Adamsond8985282009-04-01 09:22:21 -04002461
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04002462 if (!nfs4_sequence_process(task, &data->o_res.seq_res))
Trond Myklebust14516c32010-07-31 14:29:06 -04002463 return;
Andy Adamsond8985282009-04-01 09:22:21 -04002464
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002465 if (task->tk_status == 0) {
Trond Myklebust807d66d82012-10-02 17:09:00 -07002466 if (data->o_res.f_attr->valid & NFS_ATTR_FATTR_TYPE) {
2467 switch (data->o_res.f_attr->mode & S_IFMT) {
Trond Myklebust6f926b52005-10-18 14:20:18 -07002468 case S_IFREG:
2469 break;
2470 case S_IFLNK:
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002471 data->rpc_status = -ELOOP;
Trond Myklebust6f926b52005-10-18 14:20:18 -07002472 break;
2473 case S_IFDIR:
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002474 data->rpc_status = -EISDIR;
Trond Myklebust6f926b52005-10-18 14:20:18 -07002475 break;
2476 default:
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002477 data->rpc_status = -ENOTDIR;
Trond Myklebust807d66d82012-10-02 17:09:00 -07002478 }
Trond Myklebust6f926b52005-10-18 14:20:18 -07002479 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01002480 renew_lease(data->o_res.server, data->timestamp);
Trond Myklebust0f9f95e2007-07-08 16:19:56 -04002481 if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
2482 nfs_confirm_seqid(&data->owner->so_seqid, 0);
Trond Myklebust6f926b52005-10-18 14:20:18 -07002483 }
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002484 data->rpc_done = true;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002485}
Trond Myklebust6f926b52005-10-18 14:20:18 -07002486
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002487static void nfs4_open_release(void *calldata)
2488{
2489 struct nfs4_opendata *data = calldata;
2490 struct nfs4_state *state = NULL;
2491
2492 /* If this request hasn't been cancelled, do nothing */
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002493 if (!data->cancelled)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002494 goto out_free;
2495 /* In case of error, no cleanup! */
Trond Myklebust3e309912007-07-07 13:19:59 -04002496 if (data->rpc_status != 0 || !data->rpc_done)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002497 goto out_free;
2498 /* In case we need an open_confirm, no cleanup! */
2499 if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)
2500 goto out_free;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002501 state = nfs4_opendata_to_nfs4_state(data);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04002502 if (!IS_ERR(state))
Al Viro643168c2011-06-22 18:20:23 -04002503 nfs4_close_state(state, data->o_arg.fmode);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002504out_free:
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002505 nfs4_opendata_put(data);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002506}
2507
2508static const struct rpc_call_ops nfs4_open_ops = {
2509 .rpc_call_prepare = nfs4_open_prepare,
2510 .rpc_call_done = nfs4_open_done,
2511 .rpc_release = nfs4_open_release,
2512};
2513
Fred Isaman3b65a302016-09-19 10:06:49 -04002514static int nfs4_run_open_task(struct nfs4_opendata *data,
2515 struct nfs_open_context *ctx)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002516{
David Howells2b0143b2015-03-17 22:25:59 +00002517 struct inode *dir = d_inode(data->dir);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002518 struct nfs_server *server = NFS_SERVER(dir);
2519 struct nfs_openargs *o_arg = &data->o_arg;
2520 struct nfs_openres *o_res = &data->o_res;
2521 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04002522 struct rpc_message msg = {
2523 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN],
2524 .rpc_argp = o_arg,
2525 .rpc_resp = o_res,
2526 .rpc_cred = data->owner->so_cred,
2527 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04002528 struct rpc_task_setup task_setup_data = {
2529 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04002530 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002531 .callback_ops = &nfs4_open_ops,
2532 .callback_data = data,
Trond Myklebust101070c2008-02-19 20:04:23 -05002533 .workqueue = nfsiod_workqueue,
Trond Myklebust61296502020-02-07 19:38:12 -05002534 .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002535 };
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002536 int status;
2537
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002538 kref_get(&data->kref);
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002539 data->rpc_done = false;
Trond Myklebust3e309912007-07-07 13:19:59 -04002540 data->rpc_status = 0;
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002541 data->cancelled = false;
2542 data->is_recover = false;
Fred Isaman3b65a302016-09-19 10:06:49 -04002543 if (!ctx) {
2544 nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1, 1);
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002545 data->is_recover = true;
Trond Myklebust67e7b522019-08-07 07:31:27 -04002546 task_setup_data.flags |= RPC_TASK_TIMEOUT;
Fred Isaman2409a972016-10-06 12:11:21 -04002547 } else {
Fred Isaman3b65a302016-09-19 10:06:49 -04002548 nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1, 0);
Fred Isaman2409a972016-10-06 12:11:21 -04002549 pnfs_lgopen_prepare(data, ctx);
2550 }
Trond Myklebustc970aa82007-07-14 15:39:59 -04002551 task = rpc_run_task(&task_setup_data);
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002552 if (IS_ERR(task))
2553 return PTR_ERR(task);
Anna Schumaker820bf852017-01-11 15:01:43 -05002554 status = rpc_wait_for_completion_task(task);
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002555 if (status != 0) {
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002556 data->cancelled = true;
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002557 smp_wmb();
2558 } else
2559 status = data->rpc_status;
2560 rpc_put_task(task);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002561
2562 return status;
2563}
2564
2565static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
2566{
David Howells2b0143b2015-03-17 22:25:59 +00002567 struct inode *dir = d_inode(data->dir);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002568 struct nfs_openres *o_res = &data->o_res;
Anna Schumakerd9b67e12017-01-11 15:04:25 -05002569 int status;
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002570
Fred Isaman3b65a302016-09-19 10:06:49 -04002571 status = nfs4_run_open_task(data, NULL);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002572 if (status != 0 || !data->rpc_done)
2573 return status;
2574
Trond Myklebust6926afd2012-01-07 13:22:46 -05002575 nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr);
2576
Anna Schumakerd7e98252017-01-11 16:13:29 -05002577 if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM)
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002578 status = _nfs4_proc_open_confirm(data);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002579
2580 return status;
2581}
2582
Trond Myklebustf3792d62014-07-10 08:54:32 -04002583/*
2584 * Additional permission checks in order to distinguish between an
2585 * open for read, and an open for execute. This works around the
2586 * fact that NFSv4 OPEN treats read and execute permissions as being
2587 * the same.
2588 * Note that in the non-execute case, we want to turn off permission
2589 * checking if we just created a new file (POSIX open() semantics).
2590 */
NeilBrowna52458b2018-12-03 11:30:31 +11002591static int nfs4_opendata_access(const struct cred *cred,
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002592 struct nfs4_opendata *opendata,
Weston Andros Adamsonf8d9a892013-01-03 16:42:29 -05002593 struct nfs4_state *state, fmode_t fmode,
2594 int openflags)
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002595{
2596 struct nfs_access_entry cache;
Anna Schumaker1e6f2092017-07-25 16:10:47 -04002597 u32 mask, flags;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002598
2599 /* access call failed or for some reason the server doesn't
2600 * support any access modes -- defer access call until later */
2601 if (opendata->o_res.access_supported == 0)
2602 return 0;
2603
2604 mask = 0;
Trond Myklebustf3792d62014-07-10 08:54:32 -04002605 /*
2606 * Use openflags to check for exec, because fmode won't
2607 * always have FMODE_EXEC set when file open for exec.
2608 */
Weston Andros Adamsonf8d9a892013-01-03 16:42:29 -05002609 if (openflags & __FMODE_EXEC) {
2610 /* ONLY check for exec rights */
Anna Schumaker1e6f2092017-07-25 16:10:47 -04002611 if (S_ISDIR(state->inode->i_mode))
2612 mask = NFS4_ACCESS_LOOKUP;
2613 else
2614 mask = NFS4_ACCESS_EXECUTE;
Trond Myklebustf3792d62014-07-10 08:54:32 -04002615 } else if ((fmode & FMODE_READ) && !opendata->file_created)
Anna Schumaker1e6f2092017-07-25 16:10:47 -04002616 mask = NFS4_ACCESS_READ;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002617
2618 cache.cred = cred;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002619 nfs_access_set_mask(&cache, opendata->o_res.access_result);
2620 nfs_access_add_cache(state->inode, &cache);
2621
Anna Schumaker1e6f2092017-07-25 16:10:47 -04002622 flags = NFS4_ACCESS_READ | NFS4_ACCESS_EXECUTE | NFS4_ACCESS_LOOKUP;
2623 if ((mask & ~cache.mask & flags) == 0)
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002624 return 0;
2625
Weston Andros Adamson998f40b2012-11-02 18:00:56 -04002626 return -EACCES;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002627}
2628
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002629/*
2630 * Note: On error, nfs4_proc_open will free the struct nfs4_opendata
2631 */
Fred Isaman3b65a302016-09-19 10:06:49 -04002632static int _nfs4_proc_open(struct nfs4_opendata *data,
2633 struct nfs_open_context *ctx)
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002634{
David Howells2b0143b2015-03-17 22:25:59 +00002635 struct inode *dir = d_inode(data->dir);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08002636 struct nfs_server *server = NFS_SERVER(dir);
2637 struct nfs_openargs *o_arg = &data->o_arg;
2638 struct nfs_openres *o_res = &data->o_res;
2639 int status;
2640
Fred Isaman3b65a302016-09-19 10:06:49 -04002641 status = nfs4_run_open_task(data, ctx);
Trond Myklebust08ef7bd2011-10-18 16:11:49 -07002642 if (!data->rpc_done)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002643 return status;
Trond Myklebust08ef7bd2011-10-18 16:11:49 -07002644 if (status != 0) {
2645 if (status == -NFS4ERR_BADNAME &&
2646 !(o_arg->open_flags & O_CREAT))
2647 return -ENOENT;
2648 return status;
2649 }
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002650
Trond Myklebust6926afd2012-01-07 13:22:46 -05002651 nfs_fattr_map_and_free_names(server, &data->f_attr);
2652
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002653 if (o_arg->open_flags & O_CREAT) {
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002654 if (o_arg->open_flags & O_EXCL)
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002655 data->file_created = true;
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002656 else if (o_res->cinfo.before != o_res->cinfo.after)
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04002657 data->file_created = true;
Jeff Layton1eb5d982018-01-09 08:21:17 -05002658 if (data->file_created ||
2659 inode_peek_iversion_raw(dir) != o_res->cinfo.after)
Frank van der Linden1b523ca2020-06-23 22:38:59 +00002660 nfs4_update_changeattr(dir, &o_res->cinfo,
2661 o_res->f_attr->time_start,
2662 NFS_INO_INVALID_DATA);
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04002663 }
Trond Myklebust0df5dd42010-04-11 16:48:44 -04002664 if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
2665 server->caps &= ~NFS_CAP_POSIX_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666 if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
Trond Myklebustcdd4e682006-01-03 09:55:12 +01002667 status = _nfs4_proc_open_confirm(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 if (status != 0)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002669 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670 }
Trond Myklebust56e0d712017-04-15 19:20:01 -04002671 if (!(o_res->f_attr->valid & NFS_ATTR_FATTR)) {
2672 nfs4_sequence_free_slot(&o_res->seq_res);
Trond Myklebusta841b542018-04-07 13:50:59 -04002673 nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr,
2674 o_res->f_label, NULL);
Trond Myklebust56e0d712017-04-15 19:20:01 -04002675 }
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002676 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677}
2678
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679/*
2680 * OPEN_EXPIRED:
2681 * reclaim state on the server after a network partition.
2682 * Assumes caller holds the appropriate lock
2683 */
Trond Myklebust539cd032007-06-05 11:46:42 -04002684static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685{
Trond Myklebuste56e0b782006-01-03 09:55:08 +01002686 struct nfs4_opendata *opendata;
Trond Myklebust864472e2006-01-03 09:55:15 +01002687 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688
Trond Myklebust4a1c0892013-03-15 14:57:33 -04002689 opendata = nfs4_open_recoverdata_alloc(ctx, state,
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002690 NFS4_OPEN_CLAIM_FH);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04002691 if (IS_ERR(opendata))
2692 return PTR_ERR(opendata);
Trond Myklebust864472e2006-01-03 09:55:15 +01002693 ret = nfs4_open_recover(opendata, state);
Trond Myklebust35d05772008-04-05 15:54:17 -04002694 if (ret == -ESTALE)
Al Viro3d4ff432011-06-22 18:40:12 -04002695 d_drop(ctx->dentry);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002696 nfs4_opendata_put(opendata);
Trond Myklebust864472e2006-01-03 09:55:15 +01002697 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698}
2699
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05002700static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
Trond Myklebust202b50d2005-06-22 17:16:29 +00002701{
Trond Myklebust539cd032007-06-05 11:46:42 -04002702 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust202b50d2005-06-22 17:16:29 +00002703 struct nfs4_exception exception = { };
2704 int err;
2705
2706 do {
Trond Myklebust539cd032007-06-05 11:46:42 -04002707 err = _nfs4_open_expired(ctx, state);
Trond Myklebust42113a72013-08-12 16:19:27 -04002708 trace_nfs4_open_expired(ctx, 0, err);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002709 if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
2710 continue;
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05002711 switch (err) {
2712 default:
2713 goto out;
2714 case -NFS4ERR_GRACE:
2715 case -NFS4ERR_DELAY:
2716 nfs4_handle_exception(server, err, &exception);
2717 err = 0;
2718 }
Trond Myklebust202b50d2005-06-22 17:16:29 +00002719 } while (exception.retry);
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05002720out:
Trond Myklebust202b50d2005-06-22 17:16:29 +00002721 return err;
2722}
2723
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
2725{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 struct nfs_open_context *ctx;
Trond Myklebust864472e2006-01-03 09:55:15 +01002727 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002728
Trond Myklebust864472e2006-01-03 09:55:15 +01002729 ctx = nfs4_state_find_open_context(state);
2730 if (IS_ERR(ctx))
Trond Myklebust91876b12013-03-28 14:01:33 -04002731 return -EAGAIN;
Trond Myklebust539cd032007-06-05 11:46:42 -04002732 ret = nfs4_do_open_expired(ctx, state);
Trond Myklebust864472e2006-01-03 09:55:15 +01002733 put_nfs_open_context(ctx);
2734 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002735}
2736
Trond Myklebust41020b62016-09-22 13:38:58 -04002737static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state,
2738 const nfs4_stateid *stateid)
Trond Myklebust4dfd4f72014-10-17 15:10:25 +03002739{
Trond Myklebust41020b62016-09-22 13:38:58 -04002740 nfs_remove_bad_delegation(state->inode, stateid);
Trond Myklebust9f0c5122018-09-05 14:07:15 -04002741 nfs_state_clear_delegation(state);
Trond Myklebust4dfd4f72014-10-17 15:10:25 +03002742}
2743
2744static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
2745{
2746 if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL)
Trond Myklebust41020b62016-09-22 13:38:58 -04002747 nfs_finish_clear_delegation_stateid(state, NULL);
Trond Myklebust4dfd4f72014-10-17 15:10:25 +03002748}
2749
2750static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
2751{
2752 /* NFSv4.0 doesn't allow for delegation recovery on open expire */
2753 nfs40_clear_delegation_stateid(state);
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002754 nfs_state_clear_open_state_flags(state);
Trond Myklebust4dfd4f72014-10-17 15:10:25 +03002755 return nfs4_open_expired(sp, state);
2756}
2757
Trond Myklebust45870d62016-09-22 13:38:59 -04002758static int nfs40_test_and_free_expired_stateid(struct nfs_server *server,
2759 nfs4_stateid *stateid,
NeilBrowna52458b2018-12-03 11:30:31 +11002760 const struct cred *cred)
Trond Myklebust45870d62016-09-22 13:38:59 -04002761{
2762 return -NFS4ERR_BAD_STATEID;
2763}
2764
Bryan Schumakerf062eb62011-06-02 14:59:10 -04002765#if defined(CONFIG_NFS_V4_1)
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002766static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
2767 nfs4_stateid *stateid,
NeilBrowna52458b2018-12-03 11:30:31 +11002768 const struct cred *cred)
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002769{
2770 int status;
2771
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002772 switch (stateid->type) {
2773 default:
2774 break;
2775 case NFS4_INVALID_STATEID_TYPE:
2776 case NFS4_SPECIAL_STATEID_TYPE:
2777 return -NFS4ERR_BAD_STATEID;
2778 case NFS4_REVOKED_STATEID_TYPE:
2779 goto out_free;
2780 }
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002781
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002782 status = nfs41_test_stateid(server, stateid, cred);
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002783 switch (status) {
2784 case -NFS4ERR_EXPIRED:
2785 case -NFS4ERR_ADMIN_REVOKED:
2786 case -NFS4ERR_DELEG_REVOKED:
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002787 break;
2788 default:
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002789 return status;
2790 }
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002791out_free:
2792 /* Ack the revoked state to the server */
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04002793 nfs41_free_stateid(server, stateid, cred, true);
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002794 return -NFS4ERR_EXPIRED;
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002795}
2796
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002797static int nfs41_check_delegation_stateid(struct nfs4_state *state)
Bryan Schumakerf062eb62011-06-02 14:59:10 -04002798{
Bryan Schumakerf062eb62011-06-02 14:59:10 -04002799 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002800 nfs4_stateid stateid;
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002801 struct nfs_delegation *delegation;
NeilBrowna52458b2018-12-03 11:30:31 +11002802 const struct cred *cred = NULL;
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002803 int status, ret = NFS_OK;
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002804
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002805 /* Get the delegation credential for use by test/free_stateid */
2806 rcu_read_lock();
2807 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002808 if (delegation == NULL) {
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002809 rcu_read_unlock();
Trond Myklebust9f0c5122018-09-05 14:07:15 -04002810 nfs_state_clear_delegation(state);
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002811 return NFS_OK;
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002812 }
2813
Trond Myklebustfc51b1c2020-04-02 15:27:09 -04002814 spin_lock(&delegation->lock);
Trond Myklebust0c116ca2014-11-12 14:44:49 -05002815 nfs4_stateid_copy(&stateid, &delegation->stateid);
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002816
Trond Myklebust994b15b2018-09-05 14:07:14 -04002817 if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
2818 &delegation->flags)) {
Trond Myklebustfc51b1c2020-04-02 15:27:09 -04002819 spin_unlock(&delegation->lock);
Trond Myklebust994b15b2018-09-05 14:07:14 -04002820 rcu_read_unlock();
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002821 return NFS_OK;
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002822 }
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002823
NeilBrowna52458b2018-12-03 11:30:31 +11002824 if (delegation->cred)
2825 cred = get_cred(delegation->cred);
Trond Myklebustfc51b1c2020-04-02 15:27:09 -04002826 spin_unlock(&delegation->lock);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002827 rcu_read_unlock();
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002828 status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002829 trace_nfs4_test_delegation_stateid(state, NULL, status);
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002830 if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
Trond Myklebust41020b62016-09-22 13:38:58 -04002831 nfs_finish_clear_delegation_stateid(state, &stateid);
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002832 else
2833 ret = status;
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002834
Trond Myklebust8c39a392019-07-19 13:48:44 -04002835 put_cred(cred);
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002836 return ret;
2837}
2838
2839static void nfs41_delegation_recover_stateid(struct nfs4_state *state)
2840{
2841 nfs4_stateid tmp;
2842
2843 if (test_bit(NFS_DELEGATED_STATE, &state->flags) &&
2844 nfs4_copy_delegation_stateid(state->inode, state->state,
2845 &tmp, NULL) &&
2846 nfs4_stateid_match_other(&state->stateid, &tmp))
2847 nfs_state_set_delegation(state, &tmp, state->state);
2848 else
2849 nfs_state_clear_delegation(state);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002850}
2851
2852/**
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002853 * nfs41_check_expired_locks - possibly free a lock stateid
2854 *
2855 * @state: NFSv4 state for an inode
2856 *
2857 * Returns NFS_OK if recovery for this stateid is now finished.
2858 * Otherwise a negative NFS4ERR value is returned.
2859 */
2860static int nfs41_check_expired_locks(struct nfs4_state *state)
2861{
2862 int status, ret = NFS_OK;
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002863 struct nfs4_lock_state *lsp, *prev = NULL;
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002864 struct nfs_server *server = NFS_SERVER(state->inode);
2865
2866 if (!test_bit(LK_STATE_IN_USE, &state->flags))
2867 goto out;
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002868
2869 spin_lock(&state->state_lock);
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002870 list_for_each_entry(lsp, &state->lock_states, ls_locks) {
2871 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
NeilBrowna52458b2018-12-03 11:30:31 +11002872 const struct cred *cred = lsp->ls_state->owner->so_cred;
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002873
Elena Reshetova194bc1f2017-10-20 12:53:36 +03002874 refcount_inc(&lsp->ls_count);
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002875 spin_unlock(&state->state_lock);
2876
2877 nfs4_put_lock_state(prev);
2878 prev = lsp;
2879
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002880 status = nfs41_test_and_free_expired_stateid(server,
2881 &lsp->ls_stateid,
2882 cred);
2883 trace_nfs4_test_lock_stateid(state, lsp, status);
2884 if (status == -NFS4ERR_EXPIRED ||
2885 status == -NFS4ERR_BAD_STATEID) {
2886 clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
Trond Myklebust67dd4832016-09-22 13:39:17 -04002887 lsp->ls_stateid.type = NFS4_INVALID_STATEID_TYPE;
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002888 if (!recover_lost_locks)
2889 set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
2890 } else if (status != NFS_OK) {
2891 ret = status;
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002892 nfs4_put_lock_state(prev);
2893 goto out;
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002894 }
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002895 spin_lock(&state->state_lock);
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002896 }
Benjamin Coddingtond75a6a02016-11-18 21:11:39 -05002897 }
2898 spin_unlock(&state->state_lock);
2899 nfs4_put_lock_state(prev);
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002900out:
2901 return ret;
2902}
2903
2904/**
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002905 * nfs41_check_open_stateid - possibly free an open stateid
2906 *
2907 * @state: NFSv4 state for an inode
2908 *
2909 * Returns NFS_OK if recovery for this stateid is now finished.
2910 * Otherwise a negative NFS4ERR value is returned.
2911 */
2912static int nfs41_check_open_stateid(struct nfs4_state *state)
2913{
2914 struct nfs_server *server = NFS_SERVER(state->inode);
Bryan Schumakerfcb6d9c2012-09-26 15:25:53 -04002915 nfs4_stateid *stateid = &state->open_stateid;
NeilBrowna52458b2018-12-03 11:30:31 +11002916 const struct cred *cred = state->owner->so_cred;
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002917 int status;
2918
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002919 if (test_bit(NFS_OPEN_STATE, &state->flags) == 0)
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002920 return -NFS4ERR_BAD_STATEID;
Trond Myklebust4586f6e2016-09-22 13:38:57 -04002921 status = nfs41_test_and_free_expired_stateid(server, stateid, cred);
Trond Myklebust08cb47f2013-08-20 21:59:40 -04002922 trace_nfs4_test_open_stateid(state, NULL, status);
Trond Myklebustf7a62ad2016-09-22 13:39:02 -04002923 if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) {
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002924 nfs_state_clear_open_state_flags(state);
Trond Myklebust67dd4832016-09-22 13:39:17 -04002925 stateid->type = NFS4_INVALID_STATEID_TYPE;
Trond Myklebust8a64c4e2016-09-22 13:39:21 -04002926 return status;
Trond Myklebustc0ca0e52017-08-08 21:39:28 -04002927 }
Trond Myklebust8a64c4e2016-09-22 13:39:21 -04002928 if (nfs_open_stateid_recover_openmode(state))
2929 return -NFS4ERR_OPENMODE;
2930 return NFS_OK;
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05002931}
2932
2933static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
2934{
Chuck Levereb64cf92012-07-11 16:30:05 -04002935 int status;
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05002936
Trond Myklebust27a30cf2019-07-22 18:32:59 +01002937 status = nfs41_check_delegation_stateid(state);
2938 if (status != NFS_OK)
2939 return status;
2940 nfs41_delegation_recover_stateid(state);
2941
Trond Myklebustc5896fc2016-09-22 13:39:03 -04002942 status = nfs41_check_expired_locks(state);
2943 if (status != NFS_OK)
2944 return status;
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002945 status = nfs41_check_open_stateid(state);
Chuck Levereb64cf92012-07-11 16:30:05 -04002946 if (status != NFS_OK)
2947 status = nfs4_open_expired(sp, state);
2948 return status;
Bryan Schumakerf062eb62011-06-02 14:59:10 -04002949}
2950#endif
2951
Linus Torvalds1da177e2005-04-16 15:20:36 -07002952/*
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002953 * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-*
2954 * fields corresponding to attributes that were used to store the verifier.
2955 * Make sure we clobber those fields in the later setattr call
2956 */
Trond Myklebust609339c2018-03-28 16:18:17 -04002957static unsigned nfs4_exclusive_attrset(struct nfs4_opendata *opendata,
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002958 struct iattr *sattr, struct nfs4_label **label)
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002959{
Trond Myklebust609339c2018-03-28 16:18:17 -04002960 const __u32 *bitmask = opendata->o_arg.server->exclcreat_bitmask;
2961 __u32 attrset[3];
2962 unsigned ret;
2963 unsigned i;
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002964
Trond Myklebust609339c2018-03-28 16:18:17 -04002965 for (i = 0; i < ARRAY_SIZE(attrset); i++) {
2966 attrset[i] = opendata->o_res.attrset[i];
2967 if (opendata->o_arg.createmode == NFS4_CREATE_EXCLUSIVE4_1)
2968 attrset[i] &= ~bitmask[i];
2969 }
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002970
Trond Myklebust609339c2018-03-28 16:18:17 -04002971 ret = (opendata->o_arg.createmode == NFS4_CREATE_EXCLUSIVE) ?
2972 sattr->ia_valid : 0;
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002973
Trond Myklebust609339c2018-03-28 16:18:17 -04002974 if ((attrset[1] & (FATTR4_WORD1_TIME_ACCESS|FATTR4_WORD1_TIME_ACCESS_SET))) {
2975 if (sattr->ia_valid & ATTR_ATIME_SET)
2976 ret |= ATTR_ATIME_SET;
2977 else
2978 ret |= ATTR_ATIME;
2979 }
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002980
Trond Myklebust609339c2018-03-28 16:18:17 -04002981 if ((attrset[1] & (FATTR4_WORD1_TIME_MODIFY|FATTR4_WORD1_TIME_MODIFY_SET))) {
2982 if (sattr->ia_valid & ATTR_MTIME_SET)
2983 ret |= ATTR_MTIME_SET;
2984 else
2985 ret |= ATTR_MTIME;
2986 }
2987
2988 if (!(attrset[2] & FATTR4_WORD2_SECURITY_LABEL))
Kinglong Mee5334c5b2015-08-26 21:13:37 +08002989 *label = NULL;
Trond Myklebust609339c2018-03-28 16:18:17 -04002990 return ret;
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002991}
2992
Trond Myklebustc21443c2013-02-07 14:26:21 -05002993static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
Trond Myklebust1bf85d82019-06-27 06:30:48 -04002994 int flags, struct nfs_open_context *ctx)
Trond Myklebustc21443c2013-02-07 14:26:21 -05002995{
2996 struct nfs4_state_owner *sp = opendata->owner;
2997 struct nfs_server *server = sp->so_server;
Trond Myklebust275bb302013-05-29 13:11:28 -04002998 struct dentry *dentry;
Trond Myklebustc21443c2013-02-07 14:26:21 -05002999 struct nfs4_state *state;
Trond Myklebust1bf85d82019-06-27 06:30:48 -04003000 fmode_t acc_mode = _nfs4_ctx_to_accessmode(ctx);
Trond Myklebustcf5b4052020-02-05 09:01:53 -05003001 struct inode *dir = d_inode(opendata->dir);
3002 unsigned long dir_verifier;
Trond Myklebustc21443c2013-02-07 14:26:21 -05003003 unsigned int seq;
3004 int ret;
3005
3006 seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
Trond Myklebustcf5b4052020-02-05 09:01:53 -05003007 dir_verifier = nfs_save_change_attribute(dir);
Trond Myklebustc21443c2013-02-07 14:26:21 -05003008
Fred Isaman3b65a302016-09-19 10:06:49 -04003009 ret = _nfs4_proc_open(opendata, ctx);
Trond Myklebustdca780012014-10-23 19:23:03 +03003010 if (ret != 0)
Trond Myklebustc21443c2013-02-07 14:26:21 -05003011 goto out;
3012
Trond Myklebustae55e592018-05-22 11:17:16 -04003013 state = _nfs4_opendata_to_nfs4_state(opendata);
Trond Myklebustc21443c2013-02-07 14:26:21 -05003014 ret = PTR_ERR(state);
3015 if (IS_ERR(state))
3016 goto out;
Trond Myklebusta974dee2017-02-08 11:29:46 -05003017 ctx->state = state;
Trond Myklebustc21443c2013-02-07 14:26:21 -05003018 if (server->caps & NFS_CAP_POSIX_LOCK)
3019 set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
Jeff Laytona8ce3772016-09-17 18:17:35 -04003020 if (opendata->o_res.rflags & NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK)
3021 set_bit(NFS_STATE_MAY_NOTIFY_LOCK, &state->flags);
Trond Myklebustc21443c2013-02-07 14:26:21 -05003022
Trond Myklebust275bb302013-05-29 13:11:28 -04003023 dentry = opendata->dentry;
David Howells2b0143b2015-03-17 22:25:59 +00003024 if (d_really_is_negative(dentry)) {
Al Viro668d0cd2016-03-08 12:44:17 -05003025 struct dentry *alias;
Trond Myklebust275bb302013-05-29 13:11:28 -04003026 d_drop(dentry);
Al Viro668d0cd2016-03-08 12:44:17 -05003027 alias = d_exact_alias(dentry, state->inode);
3028 if (!alias)
3029 alias = d_splice_alias(igrab(state->inode), dentry);
3030 /* d_splice_alias() can't fail here - it's a non-directory */
3031 if (alias) {
Trond Myklebust275bb302013-05-29 13:11:28 -04003032 dput(ctx->dentry);
Al Viro668d0cd2016-03-08 12:44:17 -05003033 ctx->dentry = dentry = alias;
Trond Myklebust275bb302013-05-29 13:11:28 -04003034 }
Trond Myklebustcf5b4052020-02-05 09:01:53 -05003035 }
3036
3037 switch(opendata->o_arg.claim) {
3038 default:
3039 break;
3040 case NFS4_OPEN_CLAIM_NULL:
3041 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
3042 case NFS4_OPEN_CLAIM_DELEGATE_PREV:
3043 if (!opendata->rpc_done)
3044 break;
3045 if (opendata->o_res.delegation_type != 0)
3046 dir_verifier = nfs_save_change_attribute(dir);
3047 nfs_set_verifier(dentry, dir_verifier);
Trond Myklebust275bb302013-05-29 13:11:28 -04003048 }
3049
Trond Myklebustaf9b6d72018-06-29 12:45:53 -04003050 /* Parse layoutget results before we check for access */
3051 pnfs_parse_lgopen(state->inode, opendata->lgp, ctx);
3052
Trond Myklebust1bf85d82019-06-27 06:30:48 -04003053 ret = nfs4_opendata_access(sp->so_cred, opendata, state,
3054 acc_mode, flags);
Trond Myklebustc21443c2013-02-07 14:26:21 -05003055 if (ret != 0)
3056 goto out;
3057
David Howells2b0143b2015-03-17 22:25:59 +00003058 if (d_inode(dentry) == state->inode) {
Trond Myklebustc45ffdd2013-05-29 13:34:46 -04003059 nfs_inode_attach_open_context(ctx);
3060 if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
3061 nfs4_schedule_stateid_recovery(server, state);
3062 }
Fred Isaman2409a972016-10-06 12:11:21 -04003063
Trond Myklebustc21443c2013-02-07 14:26:21 -05003064out:
Olga Kornievskaia0cb98ab2019-03-19 12:12:13 -04003065 if (!opendata->cancelled)
3066 nfs4_sequence_free_slot(&opendata->o_res.seq_res);
Trond Myklebustc21443c2013-02-07 14:26:21 -05003067 return ret;
3068}
3069
Jeff Laytonaa53ed52007-06-05 14:49:03 -04003070/*
Trond Myklebust24ac23a2006-01-03 09:55:11 +01003071 * Returns a referenced nfs4_state
Linus Torvalds1da177e2005-04-16 15:20:36 -07003072 */
Andy Adamson82be4172012-05-23 05:02:35 -04003073static int _nfs4_do_open(struct inode *dir,
Trond Myklebust4197a052013-05-29 12:37:49 -04003074 struct nfs_open_context *ctx,
Andy Adamson82be4172012-05-23 05:02:35 -04003075 int flags,
Trond Myklebust8fd1ab72017-11-06 15:28:03 -05003076 const struct nfs4_open_createattrs *c,
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04003077 int *opened)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003078{
3079 struct nfs4_state_owner *sp;
3080 struct nfs4_state *state = NULL;
3081 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01003082 struct nfs4_opendata *opendata;
Trond Myklebust4197a052013-05-29 12:37:49 -04003083 struct dentry *dentry = ctx->dentry;
NeilBrowna52458b2018-12-03 11:30:31 +11003084 const struct cred *cred = ctx->cred;
Trond Myklebust4197a052013-05-29 12:37:49 -04003085 struct nfs4_threshold **ctx_th = &ctx->mdsthreshold;
Trond Myklebust1bf85d82019-06-27 06:30:48 -04003086 fmode_t fmode = _nfs4_ctx_to_openmode(ctx);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04003087 enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL;
Trond Myklebust8fd1ab72017-11-06 15:28:03 -05003088 struct iattr *sattr = c->sattr;
3089 struct nfs4_label *label = c->label;
David Quigley1775fd32013-05-22 12:50:42 -04003090 struct nfs4_label *olabel = NULL;
Trond Myklebustaac00a82007-07-05 19:02:21 -04003091 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003092
3093 /* Protect against reboot recovery conflicts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003094 status = -ENOMEM;
Trond Myklebustd1e284d2012-01-17 22:04:24 -05003095 sp = nfs4_get_state_owner(server, cred, GFP_KERNEL);
3096 if (sp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
3098 goto out_err;
3099 }
Anna Schumaker334f87d2017-01-11 16:17:17 -05003100 status = nfs4_client_recover_expired_lease(server->nfs_client);
Trond Myklebust58d97142006-01-03 09:55:24 +01003101 if (status != 0)
Trond Myklebustb4454fe2006-01-03 09:55:25 +01003102 goto err_put_state_owner;
David Howells2b0143b2015-03-17 22:25:59 +00003103 if (d_really_is_positive(dentry))
3104 nfs4_return_incompatible_delegation(d_inode(dentry), fmode);
Trond Myklebust58d97142006-01-03 09:55:24 +01003105 status = -ENOMEM;
David Howells2b0143b2015-03-17 22:25:59 +00003106 if (d_really_is_positive(dentry))
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04003107 claim = NFS4_OPEN_CLAIM_FH;
Trond Myklebust8fd1ab72017-11-06 15:28:03 -05003108 opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags,
3109 c, claim, GFP_KERNEL);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01003110 if (opendata == NULL)
Trond Myklebust95d35cb2008-12-23 15:21:45 -05003111 goto err_put_state_owner;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003112
David Quigley14c43f72013-05-22 12:50:43 -04003113 if (label) {
3114 olabel = nfs4_label_alloc(server, GFP_KERNEL);
3115 if (IS_ERR(olabel)) {
3116 status = PTR_ERR(olabel);
3117 goto err_opendata_put;
3118 }
3119 }
3120
Trond Myklebuste911b812014-03-26 13:24:37 -07003121 if (server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
3122 if (!opendata->f_attr.mdsthreshold) {
3123 opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
3124 if (!opendata->f_attr.mdsthreshold)
3125 goto err_free_label;
3126 }
Trond Myklebust1549210f2012-06-05 09:16:47 -04003127 opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0];
Andy Adamson82be4172012-05-23 05:02:35 -04003128 }
David Howells2b0143b2015-03-17 22:25:59 +00003129 if (d_really_is_positive(dentry))
3130 opendata->state = nfs4_get_open_state(d_inode(dentry), sp);
Trond Myklebustaac00a82007-07-05 19:02:21 -04003131
Trond Myklebust1bf85d82019-06-27 06:30:48 -04003132 status = _nfs4_open_and_get_state(opendata, flags, ctx);
Weston Andros Adamson6168f622012-09-10 14:00:46 -04003133 if (status != 0)
David Quigley14c43f72013-05-22 12:50:43 -04003134 goto err_free_label;
Trond Myklebust3efb9722013-05-29 13:17:04 -04003135 state = ctx->state;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04003136
NeilBrownefcbc042015-07-30 13:00:56 +10003137 if ((opendata->o_arg.open_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) &&
Trond Myklebust549b19c2013-04-16 18:42:34 -04003138 (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) {
Trond Myklebust609339c2018-03-28 16:18:17 -04003139 unsigned attrs = nfs4_exclusive_attrset(opendata, sattr, &label);
Tigran Mkrtchyana1d1c4f2016-05-12 11:16:38 +02003140 /*
3141 * send create attributes which was not set by open
3142 * with an extra setattr.
3143 */
Trond Myklebust609339c2018-03-28 16:18:17 -04003144 if (attrs || label) {
3145 unsigned ia_old = sattr->ia_valid;
3146
3147 sattr->ia_valid = attrs;
Tigran Mkrtchyana1d1c4f2016-05-12 11:16:38 +02003148 nfs_fattr_init(opendata->o_res.f_attr);
3149 status = nfs4_do_setattr(state->inode, cred,
3150 opendata->o_res.f_attr, sattr,
NeilBrown29b59f92016-10-13 15:26:47 +11003151 ctx, label, olabel);
Tigran Mkrtchyana1d1c4f2016-05-12 11:16:38 +02003152 if (status == 0) {
3153 nfs_setattr_update_inode(state->inode, sattr,
3154 opendata->o_res.f_attr);
3155 nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
3156 }
Trond Myklebust609339c2018-03-28 16:18:17 -04003157 sattr->ia_valid = ia_old;
David Quigley1775fd32013-05-22 12:50:42 -04003158 }
Trond Myklebust0ab64e02010-04-16 16:22:51 -04003159 }
Kinglong Meec5c3fb52015-08-26 21:11:39 +08003160 if (opened && opendata->file_created)
Al Viro73a09dd2018-06-08 13:22:02 -04003161 *opened = 1;
Andy Adamson82be4172012-05-23 05:02:35 -04003162
Trond Myklebuste911b812014-03-26 13:24:37 -07003163 if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) {
Andy Adamson82be4172012-05-23 05:02:35 -04003164 *ctx_th = opendata->f_attr.mdsthreshold;
Trond Myklebuste911b812014-03-26 13:24:37 -07003165 opendata->f_attr.mdsthreshold = NULL;
3166 }
Andy Adamson82be4172012-05-23 05:02:35 -04003167
David Quigley14c43f72013-05-22 12:50:43 -04003168 nfs4_label_free(olabel);
3169
Trond Myklebustc6d00e62007-06-17 16:02:44 -04003170 nfs4_opendata_put(opendata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003171 nfs4_put_state_owner(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 return 0;
David Quigley14c43f72013-05-22 12:50:43 -04003173err_free_label:
3174 nfs4_label_free(olabel);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04003175err_opendata_put:
3176 nfs4_opendata_put(opendata);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01003177err_put_state_owner:
3178 nfs4_put_state_owner(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003179out_err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003180 return status;
3181}
3182
3183
Andy Adamson82be4172012-05-23 05:02:35 -04003184static struct nfs4_state *nfs4_do_open(struct inode *dir,
Trond Myklebust4197a052013-05-29 12:37:49 -04003185 struct nfs_open_context *ctx,
Andy Adamson82be4172012-05-23 05:02:35 -04003186 int flags,
3187 struct iattr *sattr,
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04003188 struct nfs4_label *label,
3189 int *opened)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003190{
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04003191 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebust0688e642019-04-07 13:59:09 -04003192 struct nfs4_exception exception = {
3193 .interruptible = true,
3194 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003195 struct nfs4_state *res;
Trond Myklebust8fd1ab72017-11-06 15:28:03 -05003196 struct nfs4_open_createattrs c = {
3197 .label = label,
3198 .sattr = sattr,
3199 .verf = {
3200 [0] = (__u32)jiffies,
3201 [1] = (__u32)current->pid,
3202 },
3203 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003204 int status;
3205
3206 do {
Trond Myklebust8fd1ab72017-11-06 15:28:03 -05003207 status = _nfs4_do_open(dir, ctx, flags, &c, opened);
Trond Myklebust3efb9722013-05-29 13:17:04 -04003208 res = ctx->state;
Trond Myklebust42113a72013-08-12 16:19:27 -04003209 trace_nfs4_open_file(ctx, flags, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003210 if (status == 0)
3211 break;
3212 /* NOTE: BAD_SEQID means the server and client disagree about the
3213 * book-keeping w.r.t. state-changing operations
3214 * (OPEN/CLOSE/LOCK/LOCKU...)
3215 * It is actually a sign of a bug on the client or on the server.
3216 *
3217 * If we receive a BAD_SEQID error in the particular case of
Trond Myklebustcee54fc2005-10-18 14:20:12 -07003218 * doing an OPEN, we assume that nfs_increment_open_seqid() will
Linus Torvalds1da177e2005-04-16 15:20:36 -07003219 * have unhashed the old state_owner for us, and that we can
3220 * therefore safely retry using a new one. We should still warn
3221 * the user though...
3222 */
3223 if (status == -NFS4ERR_BAD_SEQID) {
Trond Myklebust9a3ba432012-03-12 18:01:48 -04003224 pr_warn_ratelimited("NFS: v4 server %s "
Trond Myklebust6f43ddc2007-07-08 16:49:11 -04003225 " returned a bad sequence-id error!\n",
3226 NFS_SERVER(dir)->nfs_client->cl_hostname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003227 exception.retry = 1;
3228 continue;
3229 }
Trond Myklebust550f5742005-10-18 14:20:21 -07003230 /*
3231 * BAD_STATEID on OPEN means that the server cancelled our
3232 * state before it received the OPEN_CONFIRM.
3233 * Recover by retrying the request as per the discussion
3234 * on Page 181 of RFC3530.
3235 */
3236 if (status == -NFS4ERR_BAD_STATEID) {
3237 exception.retry = 1;
3238 continue;
3239 }
Robert Milkowski924491f2020-01-28 08:37:47 +00003240 if (status == -NFS4ERR_EXPIRED) {
3241 nfs4_schedule_lease_recovery(server->nfs_client);
3242 exception.retry = 1;
3243 continue;
3244 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04003245 if (status == -EAGAIN) {
3246 /* We must have found a delegation */
3247 exception.retry = 1;
3248 continue;
3249 }
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04003250 if (nfs4_clear_cap_atomic_open_v1(server, status, &exception))
3251 continue;
3252 res = ERR_PTR(nfs4_handle_exception(server,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003253 status, &exception));
3254 } while (exception.retry);
3255 return res;
3256}
3257
Trond Myklebust8487c472016-06-26 08:44:35 -04003258static int _nfs4_do_setattr(struct inode *inode,
3259 struct nfs_setattrargs *arg,
3260 struct nfs_setattrres *res,
NeilBrowna52458b2018-12-03 11:30:31 +11003261 const struct cred *cred,
NeilBrown29b59f92016-10-13 15:26:47 +11003262 struct nfs_open_context *ctx)
Trond Myklebust8487c472016-06-26 08:44:35 -04003263{
3264 struct nfs_server *server = NFS_SERVER(inode);
Anna Schumakerd9b67e12017-01-11 15:04:25 -05003265 struct rpc_message msg = {
Trond Myklebust8487c472016-06-26 08:44:35 -04003266 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
3267 .rpc_argp = arg,
3268 .rpc_resp = res,
3269 .rpc_cred = cred,
Anna Schumakerd9b67e12017-01-11 15:04:25 -05003270 };
NeilBrowna52458b2018-12-03 11:30:31 +11003271 const struct cred *delegation_cred = NULL;
Trond Myklebust8487c472016-06-26 08:44:35 -04003272 unsigned long timestamp = jiffies;
Trond Myklebust8487c472016-06-26 08:44:35 -04003273 bool truncate;
3274 int status;
3275
3276 nfs_fattr_init(res->fattr);
3277
3278 /* Servers should only apply open mode checks for file size changes */
3279 truncate = (arg->iap->ia_valid & ATTR_SIZE) ? true : false;
Trond Myklebust991eedb2018-04-09 11:15:30 -04003280 if (!truncate)
3281 goto zero_stateid;
Trond Myklebust8487c472016-06-26 08:44:35 -04003282
Trond Myklebust991eedb2018-04-09 11:15:30 -04003283 if (nfs4_copy_delegation_stateid(inode, FMODE_WRITE, &arg->stateid, &delegation_cred)) {
Trond Myklebust8487c472016-06-26 08:44:35 -04003284 /* Use that stateid */
Trond Myklebust09a54f02019-08-03 10:28:18 -04003285 } else if (ctx != NULL && ctx->state) {
NeilBrown17393472016-10-13 15:26:47 +11003286 struct nfs_lock_context *l_ctx;
NeilBrown29b59f92016-10-13 15:26:47 +11003287 if (!nfs4_valid_open_stateid(ctx->state))
Trond Myklebust8487c472016-06-26 08:44:35 -04003288 return -EBADF;
NeilBrown17393472016-10-13 15:26:47 +11003289 l_ctx = nfs_get_lock_context(ctx);
3290 if (IS_ERR(l_ctx))
3291 return PTR_ERR(l_ctx);
NeilBrown7a0566b2016-12-06 15:50:06 -05003292 status = nfs4_select_rw_stateid(ctx->state, FMODE_WRITE, l_ctx,
3293 &arg->stateid, &delegation_cred);
3294 nfs_put_lock_context(l_ctx);
3295 if (status == -EIO)
Trond Myklebust8487c472016-06-26 08:44:35 -04003296 return -EBADF;
Olga Kornievskaiad826e5b2019-12-18 16:50:42 -05003297 else if (status == -EAGAIN)
3298 goto zero_stateid;
Trond Myklebust991eedb2018-04-09 11:15:30 -04003299 } else {
3300zero_stateid:
Trond Myklebust8487c472016-06-26 08:44:35 -04003301 nfs4_stateid_copy(&arg->stateid, &zero_stateid);
Trond Myklebust991eedb2018-04-09 11:15:30 -04003302 }
Trond Myklebust8487c472016-06-26 08:44:35 -04003303 if (delegation_cred)
3304 msg.rpc_cred = delegation_cred;
3305
3306 status = nfs4_call_sync(server->client, server, &msg, &arg->seq_args, &res->seq_res, 1);
3307
NeilBrowna52458b2018-12-03 11:30:31 +11003308 put_cred(delegation_cred);
NeilBrown29b59f92016-10-13 15:26:47 +11003309 if (status == 0 && ctx != NULL)
Trond Myklebust8487c472016-06-26 08:44:35 -04003310 renew_lease(server, timestamp);
3311 trace_nfs4_setattr(inode, &arg->stateid, status);
3312 return status;
3313}
3314
NeilBrowna52458b2018-12-03 11:30:31 +11003315static int nfs4_do_setattr(struct inode *inode, const struct cred *cred,
Trond Myklebust8487c472016-06-26 08:44:35 -04003316 struct nfs_fattr *fattr, struct iattr *sattr,
NeilBrown29b59f92016-10-13 15:26:47 +11003317 struct nfs_open_context *ctx, struct nfs4_label *ilabel,
Trond Myklebust8487c472016-06-26 08:44:35 -04003318 struct nfs4_label *olabel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319{
Trond Myklebust3e4f6292006-03-20 13:44:46 -05003320 struct nfs_server *server = NFS_SERVER(inode);
Trond Myklebust30846df2018-04-07 13:44:28 -04003321 __u32 bitmask[NFS4_BITMASK_SZ];
NeilBrown29b59f92016-10-13 15:26:47 +11003322 struct nfs4_state *state = ctx ? ctx->state : NULL;
Anna Schumakerd9b67e12017-01-11 15:04:25 -05003323 struct nfs_setattrargs arg = {
3324 .fh = NFS_FH(inode),
3325 .iap = sattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003326 .server = server,
Trond Myklebust30846df2018-04-07 13:44:28 -04003327 .bitmask = bitmask,
David Quigley1775fd32013-05-22 12:50:42 -04003328 .label = ilabel,
Anna Schumakerd9b67e12017-01-11 15:04:25 -05003329 };
3330 struct nfs_setattrres res = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003331 .fattr = fattr,
David Quigley1775fd32013-05-22 12:50:42 -04003332 .label = olabel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333 .server = server,
Anna Schumakerd9b67e12017-01-11 15:04:25 -05003334 };
Trond Myklebust8487c472016-06-26 08:44:35 -04003335 struct nfs4_exception exception = {
3336 .state = state,
3337 .inode = inode,
3338 .stateid = &arg.stateid,
3339 };
3340 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003341
Linus Torvalds1da177e2005-04-16 15:20:36 -07003342 do {
Trond Myklebust30846df2018-04-07 13:44:28 -04003343 nfs4_bitmap_copy_adjust_setattr(bitmask,
3344 nfs4_bitmask(server, olabel),
3345 inode);
3346
NeilBrown29b59f92016-10-13 15:26:47 +11003347 err = _nfs4_do_setattr(inode, &arg, &res, cred, ctx);
Trond Myklebust451146b2012-04-18 16:29:11 -04003348 switch (err) {
3349 case -NFS4ERR_OPENMODE:
Trond Myklebust721ccfb2013-04-29 11:11:58 -04003350 if (!(sattr->ia_valid & ATTR_SIZE)) {
3351 pr_warn_once("NFSv4: server %s is incorrectly "
3352 "applying open mode checks to "
3353 "a SETATTR that is not "
3354 "changing file size.\n",
3355 server->nfs_client->cl_hostname);
3356 }
Trond Myklebust451146b2012-04-18 16:29:11 -04003357 if (state && !(state->state & FMODE_WRITE)) {
3358 err = -EBADF;
3359 if (sattr->ia_valid & ATTR_OPEN)
3360 err = -EACCES;
3361 goto out;
3362 }
3363 }
3364 err = nfs4_handle_exception(server, err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003365 } while (exception.retry);
Trond Myklebust451146b2012-04-18 16:29:11 -04003366out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003367 return err;
3368}
3369
Peng Tao500d7012015-09-22 11:35:22 +08003370static bool
3371nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
3372{
3373 if (inode == NULL || !nfs_have_layout(inode))
3374 return false;
3375
3376 return pnfs_wait_on_layoutreturn(inode, task);
3377}
3378
Trond Myklebust0e0cb352019-09-20 07:23:47 -04003379/*
3380 * Update the seqid of an open stateid
3381 */
3382static void nfs4_sync_open_stateid(nfs4_stateid *dst,
3383 struct nfs4_state *state)
3384{
3385 __be32 seqid_open;
3386 u32 dst_seqid;
3387 int seq;
3388
3389 for (;;) {
3390 if (!nfs4_valid_open_stateid(state))
3391 break;
3392 seq = read_seqbegin(&state->seqlock);
3393 if (!nfs4_state_match_open_stateid_other(state, dst)) {
3394 nfs4_stateid_copy(dst, &state->open_stateid);
3395 if (read_seqretry(&state->seqlock, seq))
3396 continue;
3397 break;
3398 }
3399 seqid_open = state->open_stateid.seqid;
3400 if (read_seqretry(&state->seqlock, seq))
3401 continue;
3402
3403 dst_seqid = be32_to_cpu(dst->seqid);
3404 if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) < 0)
3405 dst->seqid = seqid_open;
3406 break;
3407 }
3408}
3409
3410/*
3411 * Update the seqid of an open stateid after receiving
3412 * NFS4ERR_OLD_STATEID
3413 */
3414static bool nfs4_refresh_open_old_stateid(nfs4_stateid *dst,
3415 struct nfs4_state *state)
3416{
3417 __be32 seqid_open;
3418 u32 dst_seqid;
3419 bool ret;
3420 int seq;
3421
3422 for (;;) {
3423 ret = false;
3424 if (!nfs4_valid_open_stateid(state))
3425 break;
3426 seq = read_seqbegin(&state->seqlock);
3427 if (!nfs4_state_match_open_stateid_other(state, dst)) {
3428 if (read_seqretry(&state->seqlock, seq))
3429 continue;
3430 break;
3431 }
3432 seqid_open = state->open_stateid.seqid;
3433 if (read_seqretry(&state->seqlock, seq))
3434 continue;
3435
3436 dst_seqid = be32_to_cpu(dst->seqid);
3437 if ((s32)(dst_seqid - be32_to_cpu(seqid_open)) >= 0)
3438 dst->seqid = cpu_to_be32(dst_seqid + 1);
3439 else
3440 dst->seqid = seqid_open;
3441 ret = true;
3442 break;
3443 }
3444
3445 return ret;
3446}
3447
Linus Torvalds1da177e2005-04-16 15:20:36 -07003448struct nfs4_closedata {
3449 struct inode *inode;
3450 struct nfs4_state *state;
3451 struct nfs_closeargs arg;
3452 struct nfs_closeres res;
Trond Myklebustcf805162016-11-15 14:56:07 -05003453 struct {
3454 struct nfs4_layoutreturn_args arg;
3455 struct nfs4_layoutreturn_res res;
Trond Myklebust4d796d72016-09-23 11:38:08 -04003456 struct nfs4_xdr_opaque_data ld_private;
Trond Myklebustcf805162016-11-15 14:56:07 -05003457 u32 roc_barrier;
3458 bool roc;
3459 } lr;
Trond Myklebust516a6af2005-10-27 22:12:41 -04003460 struct nfs_fattr fattr;
Trond Myklebust26e976a2006-01-03 09:55:21 +01003461 unsigned long timestamp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462};
3463
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003464static void nfs4_free_closedata(void *data)
Trond Myklebust95121352005-10-18 14:20:12 -07003465{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003466 struct nfs4_closedata *calldata = data;
3467 struct nfs4_state_owner *sp = calldata->state->owner;
Al Viro643168c2011-06-22 18:20:23 -04003468 struct super_block *sb = calldata->state->inode->i_sb;
Trond Myklebust95121352005-10-18 14:20:12 -07003469
Trond Myklebustcf805162016-11-15 14:56:07 -05003470 if (calldata->lr.roc)
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05003471 pnfs_roc_release(&calldata->lr.arg, &calldata->lr.res,
3472 calldata->res.lr_ret);
Trond Myklebust95121352005-10-18 14:20:12 -07003473 nfs4_put_open_state(calldata->state);
3474 nfs_free_seqid(calldata->arg.seqid);
Trond Myklebust95121352005-10-18 14:20:12 -07003475 nfs4_put_state_owner(sp);
Trond Myklebust322b2b92013-01-11 16:39:51 -05003476 nfs_sb_deactive(sb);
Trond Myklebust95121352005-10-18 14:20:12 -07003477 kfree(calldata);
3478}
3479
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003480static void nfs4_close_done(struct rpc_task *task, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003482 struct nfs4_closedata *calldata = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003483 struct nfs4_state *state = calldata->state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003484 struct nfs_server *server = NFS_SERVER(calldata->inode);
Trond Myklebust412f6c42014-08-25 22:09:08 -04003485 nfs4_stateid *res_stateid = NULL;
Trond Myklebustb8b8d222017-11-07 10:51:37 -05003486 struct nfs4_exception exception = {
3487 .state = state,
3488 .inode = calldata->inode,
3489 .stateid = &calldata->arg.stateid,
3490 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
Chuck Levera3ca5652012-03-01 17:00:40 -05003492 dprintk("%s: begin!\n", __func__);
Trond Myklebust14516c32010-07-31 14:29:06 -04003493 if (!nfs4_sequence_done(task, &calldata->res.seq_res))
3494 return;
Trond Myklebust42113a72013-08-12 16:19:27 -04003495 trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status);
Trond Myklebustcf805162016-11-15 14:56:07 -05003496
3497 /* Handle Layoutreturn errors */
Trond Myklebust287a9c52019-09-20 07:23:41 -04003498 if (pnfs_roc_done(task, calldata->inode,
3499 &calldata->arg.lr_args,
3500 &calldata->res.lr_res,
3501 &calldata->res.lr_ret) == -EAGAIN)
3502 goto out_restart;
Trond Myklebustcf805162016-11-15 14:56:07 -05003503
Anna Schumakerd9b67e12017-01-11 15:04:25 -05003504 /* hmm. we are done with the inode, and in the process of freeing
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 * the state_owner. we keep this around to process errors
3506 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003507 switch (task->tk_status) {
3508 case 0:
Trond Myklebust412f6c42014-08-25 22:09:08 -04003509 res_stateid = &calldata->res.stateid;
Trond Myklebust26e976a2006-01-03 09:55:21 +01003510 renew_lease(server, calldata->timestamp);
Trond Myklebust412f6c42014-08-25 22:09:08 -04003511 break;
Trond Myklebustf07d4a32016-12-19 10:34:14 -05003512 case -NFS4ERR_ACCESS:
3513 if (calldata->arg.bitmask != NULL) {
3514 calldata->arg.bitmask = NULL;
3515 calldata->res.fattr = NULL;
Trond Myklebust91b30d22017-11-06 15:28:09 -05003516 goto out_restart;
Trond Myklebustf07d4a32016-12-19 10:34:14 -05003517
3518 }
3519 break;
Trond Myklebust12f275c2017-11-06 15:28:05 -05003520 case -NFS4ERR_OLD_STATEID:
3521 /* Did we race with OPEN? */
Trond Myklebust0e0cb352019-09-20 07:23:47 -04003522 if (nfs4_refresh_open_old_stateid(&calldata->arg.stateid,
Trond Myklebust91b30d22017-11-06 15:28:09 -05003523 state))
3524 goto out_restart;
Trond Myklebust12f275c2017-11-06 15:28:05 -05003525 goto out_release;
Trond Myklebust69794ad2013-11-20 12:57:19 -05003526 case -NFS4ERR_ADMIN_REVOKED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527 case -NFS4ERR_STALE_STATEID:
Trond Myklebust26d36302016-09-22 13:39:05 -04003528 case -NFS4ERR_EXPIRED:
3529 nfs4_free_revoked_stateid(server,
3530 &calldata->arg.stateid,
3531 task->tk_msg.rpc_cred);
Trond Myklebust12f275c2017-11-06 15:28:05 -05003532 /* Fallthrough */
Trond Myklebust9e33bed2008-12-23 15:21:46 -05003533 case -NFS4ERR_BAD_STATEID:
Trond Myklebuste217e822019-09-20 07:23:46 -04003534 if (calldata->arg.fmode == 0)
3535 break;
3536 /* Fallthrough */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003537 default:
Trond Myklebustb8b8d222017-11-07 10:51:37 -05003538 task->tk_status = nfs4_async_handle_exception(task,
3539 server, task->tk_status, &exception);
3540 if (exception.retry)
Trond Myklebust91b30d22017-11-06 15:28:09 -05003541 goto out_restart;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003542 }
Trond Myklebust4a1e2fe2015-08-30 18:37:59 -07003543 nfs_clear_open_stateid(state, &calldata->arg.stateid,
3544 res_stateid, calldata->arg.fmode);
Trond Myklebust69794ad2013-11-20 12:57:19 -05003545out_release:
Trond Myklebust91b30d22017-11-06 15:28:09 -05003546 task->tk_status = 0;
Trond Myklebust72211db2009-12-15 14:47:36 -05003547 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebustd8d84982016-12-19 12:14:44 -05003548 nfs_refresh_inode(calldata->inode, &calldata->fattr);
Chuck Levera3ca5652012-03-01 17:00:40 -05003549 dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
Trond Myklebust91b30d22017-11-06 15:28:09 -05003550 return;
Trond Myklebust91b30d22017-11-06 15:28:09 -05003551out_restart:
3552 task->tk_status = 0;
3553 rpc_restart_call_prepare(task);
3554 goto out_release;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003555}
3556
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01003557static void nfs4_close_prepare(struct rpc_task *task, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003558{
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01003559 struct nfs4_closedata *calldata = data;
Trond Myklebust95121352005-10-18 14:20:12 -07003560 struct nfs4_state *state = calldata->state;
Trond Myklebust7fdab062012-09-20 20:15:57 -04003561 struct inode *inode = calldata->inode;
Trond Myklebustc8bf7072018-06-15 16:31:02 -04003562 struct pnfs_layout_hdr *lo;
Trond Myklebustaee7af32014-08-25 22:33:12 -04003563 bool is_rdonly, is_wronly, is_rdwr;
Trond Myklebust88069f72009-12-08 08:33:16 -05003564 int call_close = 0;
Trond Myklebust95121352005-10-18 14:20:12 -07003565
Chuck Levera3ca5652012-03-01 17:00:40 -05003566 dprintk("%s: begin!\n", __func__);
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003567 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05003568 goto out_wait;
Trond Myklebust003707c2007-07-05 18:07:55 -04003569
Trond Myklebust88069f72009-12-08 08:33:16 -05003570 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
Trond Myklebust4cecb762005-11-04 15:32:58 -05003571 spin_lock(&state->owner->so_lock);
Trond Myklebustaee7af32014-08-25 22:33:12 -04003572 is_rdwr = test_bit(NFS_O_RDWR_STATE, &state->flags);
3573 is_rdonly = test_bit(NFS_O_RDONLY_STATE, &state->flags);
3574 is_wronly = test_bit(NFS_O_WRONLY_STATE, &state->flags);
Trond Myklebust003707c2007-07-05 18:07:55 -04003575 /* Calculate the change in open mode */
Trond Myklebustcd9288f2014-09-18 11:51:32 -04003576 calldata->arg.fmode = 0;
Trond Myklebuste7616922006-01-03 09:55:13 +01003577 if (state->n_rdwr == 0) {
Trond Myklebustcd9288f2014-09-18 11:51:32 -04003578 if (state->n_rdonly == 0)
3579 call_close |= is_rdonly;
3580 else if (is_rdonly)
3581 calldata->arg.fmode |= FMODE_READ;
3582 if (state->n_wronly == 0)
3583 call_close |= is_wronly;
3584 else if (is_wronly)
3585 calldata->arg.fmode |= FMODE_WRITE;
Trond Myklebuste547f262016-06-25 19:19:28 -04003586 if (calldata->arg.fmode != (FMODE_READ|FMODE_WRITE))
3587 call_close |= is_rdwr;
Trond Myklebustcd9288f2014-09-18 11:51:32 -04003588 } else if (is_rdwr)
3589 calldata->arg.fmode |= FMODE_READ|FMODE_WRITE;
3590
Trond Myklebust0e0cb352019-09-20 07:23:47 -04003591 nfs4_sync_open_stateid(&calldata->arg.stateid, state);
3592 if (!nfs4_valid_open_stateid(state))
Trond Myklebust5d422302013-03-14 16:57:48 -04003593 call_close = 0;
Trond Myklebust4cecb762005-11-04 15:32:58 -05003594 spin_unlock(&state->owner->so_lock);
Trond Myklebust88069f72009-12-08 08:33:16 -05003595
3596 if (!call_close) {
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003597 /* Note: exit _without_ calling nfs4_close_done */
Trond Myklebustc8da19b2013-02-11 19:01:21 -05003598 goto out_no_action;
Trond Myklebust95121352005-10-18 14:20:12 -07003599 }
Trond Myklebust88069f72009-12-08 08:33:16 -05003600
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05003601 if (!calldata->lr.roc && nfs4_wait_on_layoutreturn(inode, task)) {
Peng Tao500d7012015-09-22 11:35:22 +08003602 nfs_release_seqid(calldata->arg.seqid);
3603 goto out_wait;
3604 }
3605
Trond Myklebustc8bf7072018-06-15 16:31:02 -04003606 lo = calldata->arg.lr_args ? calldata->arg.lr_args->layout : NULL;
3607 if (lo && !pnfs_layout_is_valid(lo)) {
3608 calldata->arg.lr_args = NULL;
3609 calldata->res.lr_res = NULL;
3610 }
3611
Trond Myklebust9413a1a2016-12-19 11:36:41 -05003612 if (calldata->arg.fmode == 0)
Trond Myklebust88069f72009-12-08 08:33:16 -05003613 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
Trond Myklebust3ecefc92016-10-27 18:25:04 -04003614
Trond Myklebust9413a1a2016-12-19 11:36:41 -05003615 if (calldata->arg.fmode == 0 || calldata->arg.fmode == FMODE_READ) {
Trond Myklebust3ecefc92016-10-27 18:25:04 -04003616 /* Close-to-open cache consistency revalidation */
3617 if (!nfs4_have_delegation(inode, FMODE_READ))
3618 calldata->arg.bitmask = NFS_SERVER(inode)->cache_consistency_bitmask;
3619 else
3620 calldata->arg.bitmask = NULL;
3621 }
Trond Myklebust3c13cb52015-08-18 23:45:13 -05003622
Trond Myklebust6ae37332015-01-30 14:21:14 -05003623 calldata->arg.share_access =
3624 nfs4_map_atomic_open_share(NFS_SERVER(inode),
3625 calldata->arg.fmode, 0);
Trond Myklebust88069f72009-12-08 08:33:16 -05003626
Trond Myklebustd8d84982016-12-19 12:14:44 -05003627 if (calldata->res.fattr == NULL)
3628 calldata->arg.bitmask = NULL;
3629 else if (calldata->arg.bitmask == NULL)
3630 calldata->res.fattr = NULL;
Trond Myklebust26e976a2006-01-03 09:55:21 +01003631 calldata->timestamp = jiffies;
Anna Schumaker42e1cca2017-01-09 15:48:22 -05003632 if (nfs4_setup_sequence(NFS_SERVER(inode)->nfs_client,
Trond Myklebust9d12b212012-01-17 22:04:25 -05003633 &calldata->arg.seq_args,
3634 &calldata->res.seq_res,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04003635 task) != 0)
3636 nfs_release_seqid(calldata->arg.seqid);
Chuck Levera3ca5652012-03-01 17:00:40 -05003637 dprintk("%s: done!\n", __func__);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05003638 return;
3639out_no_action:
3640 task->tk_action = NULL;
3641out_wait:
3642 nfs4_sequence_done(task, &calldata->res.seq_res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003643}
3644
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003645static const struct rpc_call_ops nfs4_close_ops = {
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01003646 .rpc_call_prepare = nfs4_close_prepare,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01003647 .rpc_call_done = nfs4_close_done,
3648 .rpc_release = nfs4_free_closedata,
3649};
3650
Linus Torvalds1da177e2005-04-16 15:20:36 -07003651/*
3652 * It is possible for data to be read/written from a mem-mapped file
3653 * after the sys_close call (which hits the vfs layer as a flush).
3654 * This means that we can't safely call nfsv4 close on a file until
3655 * the inode is cleared. This in turn means that we are not good
3656 * NFSv4 citizens - we do not indicate to the server to update the file's
3657 * share state even when we are done with one of the three share
3658 * stateid's in the inode.
3659 *
3660 * NOTE: Caller must be holding the sp->so_owner semaphore!
3661 */
Trond Myklebust1f7977c2012-09-20 20:31:51 -04003662int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003663{
Trond Myklebust4a35bd42007-06-05 10:31:33 -04003664 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust63f5f792015-01-23 19:19:25 -05003665 struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003666 struct nfs4_closedata *calldata;
Trond Myklebustb39e6252007-06-11 23:05:07 -04003667 struct nfs4_state_owner *sp = state->owner;
3668 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04003669 struct rpc_message msg = {
3670 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE],
3671 .rpc_cred = state->owner->so_cred,
3672 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04003673 struct rpc_task_setup task_setup_data = {
3674 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04003675 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04003676 .callback_ops = &nfs4_close_ops,
Trond Myklebust101070c2008-02-19 20:04:23 -05003677 .workqueue = nfsiod_workqueue,
Trond Myklebust61296502020-02-07 19:38:12 -05003678 .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF,
Trond Myklebustc970aa82007-07-14 15:39:59 -04003679 };
Trond Myklebust95121352005-10-18 14:20:12 -07003680 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003681
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04003682 nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_CLEANUP,
3683 &task_setup_data.rpc_client, &msg);
3684
Trond Myklebust8535b2b2010-05-13 12:51:01 -04003685 calldata = kzalloc(sizeof(*calldata), gfp_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003686 if (calldata == NULL)
Trond Myklebust95121352005-10-18 14:20:12 -07003687 goto out;
Anna Schumakerfba83f32018-05-04 16:22:50 -04003688 nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1, 0);
Trond Myklebust4a35bd42007-06-05 10:31:33 -04003689 calldata->inode = state->inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003690 calldata->state = state;
Trond Myklebust4a35bd42007-06-05 10:31:33 -04003691 calldata->arg.fh = NFS_FH(state->inode);
Trond Myklebustc82bac62017-11-06 15:28:06 -05003692 if (!nfs4_copy_open_stateid(&calldata->arg.stateid, state))
3693 goto out_free_calldata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694 /* Serialization for the sequence id */
Trond Myklebust63f5f792015-01-23 19:19:25 -05003695 alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
3696 calldata->arg.seqid = alloc_seqid(&state->owner->so_seqid, gfp_mask);
Trond Myklebustbadc76d2015-01-23 18:48:00 -05003697 if (IS_ERR(calldata->arg.seqid))
Trond Myklebust95121352005-10-18 14:20:12 -07003698 goto out_free_calldata;
Trond Myklebustd8d84982016-12-19 12:14:44 -05003699 nfs_fattr_init(&calldata->fattr);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05003700 calldata->arg.fmode = 0;
Trond Myklebust4d796d72016-09-23 11:38:08 -04003701 calldata->lr.arg.ld_private = &calldata->lr.ld_private;
Trond Myklebust516a6af2005-10-27 22:12:41 -04003702 calldata->res.fattr = &calldata->fattr;
Trond Myklebustc1d51932008-04-07 13:20:54 -04003703 calldata->res.seqid = calldata->arg.seqid;
Trond Myklebust516a6af2005-10-27 22:12:41 -04003704 calldata->res.server = server;
Trond Myklebustcf805162016-11-15 14:56:07 -05003705 calldata->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT;
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05003706 calldata->lr.roc = pnfs_roc(state->inode,
3707 &calldata->lr.arg, &calldata->lr.res, msg.rpc_cred);
3708 if (calldata->lr.roc) {
3709 calldata->arg.lr_args = &calldata->lr.arg;
3710 calldata->res.lr_res = &calldata->lr.res;
3711 }
Al Viro643168c2011-06-22 18:20:23 -04003712 nfs_sb_active(calldata->inode->i_sb);
Trond Myklebust95121352005-10-18 14:20:12 -07003713
Trond Myklebust1174dd12010-12-21 10:52:24 -05003714 msg.rpc_argp = &calldata->arg;
3715 msg.rpc_resp = &calldata->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04003716 task_setup_data.callback_data = calldata;
3717 task = rpc_run_task(&task_setup_data);
Trond Myklebustb39e6252007-06-11 23:05:07 -04003718 if (IS_ERR(task))
3719 return PTR_ERR(task);
Trond Myklebusta49c3c72007-10-18 18:03:27 -04003720 status = 0;
3721 if (wait)
3722 status = rpc_wait_for_completion_task(task);
Trond Myklebustb39e6252007-06-11 23:05:07 -04003723 rpc_put_task(task);
Trond Myklebusta49c3c72007-10-18 18:03:27 -04003724 return status;
Trond Myklebust95121352005-10-18 14:20:12 -07003725out_free_calldata:
3726 kfree(calldata);
3727out:
Trond Myklebustb39e6252007-06-11 23:05:07 -04003728 nfs4_put_open_state(state);
3729 nfs4_put_state_owner(sp);
Trond Myklebust95121352005-10-18 14:20:12 -07003730 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731}
3732
Trond Myklebust2b484292010-09-17 10:56:51 -04003733static struct inode *
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04003734nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
3735 int open_flags, struct iattr *attr, int *opened)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003736{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003737 struct nfs4_state *state;
David Quigleyaa9c2662013-05-22 12:50:44 -04003738 struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
3739
3740 label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003741
Trond Myklebust565277f2007-10-15 18:17:53 -04003742 /* Protect against concurrent sillydeletes */
Trond Myklebust5bc2afc2013-09-23 18:01:28 -04003743 state = nfs4_do_open(dir, ctx, open_flags, attr, label, opened);
David Quigleyaa9c2662013-05-22 12:50:44 -04003744
3745 nfs4_label_release_security(label);
3746
Trond Myklebustf46e0bd2010-09-17 10:56:50 -04003747 if (IS_ERR(state))
3748 return ERR_CAST(state);
Trond Myklebust275bb302013-05-29 13:11:28 -04003749 return state->inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003750}
3751
Trond Myklebust1185a552009-12-03 15:54:02 -05003752static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
Trond Myklebust7fe5c392009-03-19 15:35:50 -04003753{
3754 if (ctx->state == NULL)
3755 return;
3756 if (is_sync)
Trond Myklebust1bf85d82019-06-27 06:30:48 -04003757 nfs4_close_sync(ctx->state, _nfs4_ctx_to_openmode(ctx));
Trond Myklebust7fe5c392009-03-19 15:35:50 -04003758 else
Trond Myklebust1bf85d82019-06-27 06:30:48 -04003759 nfs4_close_state(ctx->state, _nfs4_ctx_to_openmode(ctx));
Trond Myklebust7fe5c392009-03-19 15:35:50 -04003760}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003761
Trond Myklebustb944dba2013-11-04 15:20:20 -05003762#define FATTR4_WORD1_NFS40_MASK (2*FATTR4_WORD1_MOUNTED_ON_FILEID - 1UL)
3763#define FATTR4_WORD2_NFS41_MASK (2*FATTR4_WORD2_SUPPATTR_EXCLCREAT - 1UL)
Frank van der Lindenb78ef842020-06-23 22:38:55 +00003764#define FATTR4_WORD2_NFS42_MASK (2*FATTR4_WORD2_XATTR_SUPPORT - 1UL)
Trond Myklebustb944dba2013-11-04 15:20:20 -05003765
Linus Torvalds1da177e2005-04-16 15:20:36 -07003766static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
3767{
Kinglong Mee8c612822015-08-26 21:12:58 +08003768 u32 bitmask[3] = {}, minorversion = server->nfs_client->cl_minorversion;
Benny Halevy43652ad2009-04-01 09:21:54 -04003769 struct nfs4_server_caps_arg args = {
3770 .fhandle = fhandle,
Kinglong Mee8c612822015-08-26 21:12:58 +08003771 .bitmask = bitmask,
Benny Halevy43652ad2009-04-01 09:21:54 -04003772 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003773 struct nfs4_server_caps_res res = {};
3774 struct rpc_message msg = {
3775 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS],
Benny Halevy43652ad2009-04-01 09:21:54 -04003776 .rpc_argp = &args,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003777 .rpc_resp = &res,
3778 };
3779 int status;
Trond Myklebustf4b23de2017-05-09 15:47:15 -04003780 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003781
Kinglong Mee8c612822015-08-26 21:12:58 +08003782 bitmask[0] = FATTR4_WORD0_SUPPORTED_ATTRS |
3783 FATTR4_WORD0_FH_EXPIRE_TYPE |
3784 FATTR4_WORD0_LINK_SUPPORT |
3785 FATTR4_WORD0_SYMLINK_SUPPORT |
3786 FATTR4_WORD0_ACLSUPPORT;
3787 if (minorversion)
3788 bitmask[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT;
3789
Bryan Schumaker7c513052011-03-24 17:12:24 +00003790 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791 if (status == 0) {
Trond Myklebustb944dba2013-11-04 15:20:20 -05003792 /* Sanity check the server answers */
Kinglong Mee8c612822015-08-26 21:12:58 +08003793 switch (minorversion) {
Trond Myklebustb944dba2013-11-04 15:20:20 -05003794 case 0:
3795 res.attr_bitmask[1] &= FATTR4_WORD1_NFS40_MASK;
3796 res.attr_bitmask[2] = 0;
3797 break;
3798 case 1:
3799 res.attr_bitmask[2] &= FATTR4_WORD2_NFS41_MASK;
3800 break;
3801 case 2:
3802 res.attr_bitmask[2] &= FATTR4_WORD2_NFS42_MASK;
3803 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003804 memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
Trond Myklebust62ab4602009-08-09 15:06:19 -04003805 server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS|
3806 NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
3807 NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|
3808 NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME|
Trond Myklebustb944dba2013-11-04 15:20:20 -05003809 NFS_CAP_CTIME|NFS_CAP_MTIME|
3810 NFS_CAP_SECURITY_LABEL);
Malahal Naineni7dd7d952014-01-23 08:54:55 -06003811 if (res.attr_bitmask[0] & FATTR4_WORD0_ACL &&
3812 res.acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003813 server->caps |= NFS_CAP_ACLS;
3814 if (res.has_links != 0)
3815 server->caps |= NFS_CAP_HARDLINKS;
3816 if (res.has_symlinks != 0)
3817 server->caps |= NFS_CAP_SYMLINKS;
Trond Myklebust62ab4602009-08-09 15:06:19 -04003818 if (res.attr_bitmask[0] & FATTR4_WORD0_FILEID)
3819 server->caps |= NFS_CAP_FILEID;
3820 if (res.attr_bitmask[1] & FATTR4_WORD1_MODE)
3821 server->caps |= NFS_CAP_MODE;
3822 if (res.attr_bitmask[1] & FATTR4_WORD1_NUMLINKS)
3823 server->caps |= NFS_CAP_NLINK;
3824 if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER)
3825 server->caps |= NFS_CAP_OWNER;
3826 if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER_GROUP)
3827 server->caps |= NFS_CAP_OWNER_GROUP;
3828 if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_ACCESS)
3829 server->caps |= NFS_CAP_ATIME;
3830 if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_METADATA)
3831 server->caps |= NFS_CAP_CTIME;
3832 if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY)
3833 server->caps |= NFS_CAP_MTIME;
David Quigleyaa9c2662013-05-22 12:50:44 -04003834#ifdef CONFIG_NFS_V4_SECURITY_LABEL
3835 if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
3836 server->caps |= NFS_CAP_SECURITY_LABEL;
3837#endif
3838 memcpy(server->attr_bitmask_nl, res.attr_bitmask,
3839 sizeof(server->attr_bitmask));
Trond Myklebustb944dba2013-11-04 15:20:20 -05003840 server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
Trond Myklebust62ab4602009-08-09 15:06:19 -04003841
Trond Myklebusta65318b2009-03-11 14:10:28 -04003842 memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
3843 server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
3844 server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
Trond Myklebustb944dba2013-11-04 15:20:20 -05003845 server->cache_consistency_bitmask[2] = 0;
Trond Myklebustf4b23de2017-05-09 15:47:15 -04003846
3847 /* Avoid a regression due to buggy server */
3848 for (i = 0; i < ARRAY_SIZE(res.exclcreat_bitmask); i++)
3849 res.exclcreat_bitmask[i] &= res.attr_bitmask[i];
Kinglong Mee8c612822015-08-26 21:12:58 +08003850 memcpy(server->exclcreat_bitmask, res.exclcreat_bitmask,
3851 sizeof(server->exclcreat_bitmask));
Trond Myklebustf4b23de2017-05-09 15:47:15 -04003852
Linus Torvalds1da177e2005-04-16 15:20:36 -07003853 server->acl_bitmask = res.acl_bitmask;
Chuck Lever264e6352012-03-01 17:02:05 -05003854 server->fh_expire_type = res.fh_expire_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855 }
Andy Adamsoncccef3b2009-04-01 09:22:03 -04003856
Linus Torvalds1da177e2005-04-16 15:20:36 -07003857 return status;
3858}
3859
Trond Myklebust55a97592006-06-09 09:34:19 -04003860int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861{
Trond Myklebust0688e642019-04-07 13:59:09 -04003862 struct nfs4_exception exception = {
3863 .interruptible = true,
3864 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865 int err;
3866 do {
3867 err = nfs4_handle_exception(server,
3868 _nfs4_server_capabilities(server, fhandle),
3869 &exception);
3870 } while (exception.retry);
3871 return err;
3872}
3873
3874static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
3875 struct nfs_fsinfo *info)
3876{
David Quigleyaa9c2662013-05-22 12:50:44 -04003877 u32 bitmask[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878 struct nfs4_lookup_root_arg args = {
David Quigleyaa9c2662013-05-22 12:50:44 -04003879 .bitmask = bitmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003880 };
3881 struct nfs4_lookup_res res = {
3882 .server = server,
Trond Myklebust0e574af2005-10-27 22:12:38 -04003883 .fattr = info->fattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003884 .fh = fhandle,
3885 };
3886 struct rpc_message msg = {
3887 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT],
3888 .rpc_argp = &args,
3889 .rpc_resp = &res,
3890 };
Benny Halevy008f55d2009-04-01 09:22:50 -04003891
David Quigleyaa9c2662013-05-22 12:50:44 -04003892 bitmask[0] = nfs4_fattr_bitmap[0];
3893 bitmask[1] = nfs4_fattr_bitmap[1];
3894 /*
3895 * Process the label in the upcoming getfattr
3896 */
3897 bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
3898
Trond Myklebust0e574af2005-10-27 22:12:38 -04003899 nfs_fattr_init(info->fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00003900 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901}
3902
3903static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
3904 struct nfs_fsinfo *info)
3905{
Trond Myklebust0688e642019-04-07 13:59:09 -04003906 struct nfs4_exception exception = {
3907 .interruptible = true,
3908 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003909 int err;
3910 do {
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04003911 err = _nfs4_lookup_root(server, fhandle, info);
Trond Myklebustb5f875a2013-08-13 13:01:39 -04003912 trace_nfs4_lookup_root(server, fhandle, info->fattr, err);
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04003913 switch (err) {
3914 case 0:
3915 case -NFS4ERR_WRONGSEC:
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04003916 goto out;
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04003917 default:
3918 err = nfs4_handle_exception(server, err, &exception);
3919 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 } while (exception.retry);
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04003921out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003922 return err;
3923}
3924
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003925static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
3926 struct nfs_fsinfo *info, rpc_authflavor_t flavor)
3927{
Trond Myklebustc2190662013-08-26 19:23:04 -04003928 struct rpc_auth_create_args auth_args = {
3929 .pseudoflavor = flavor,
3930 };
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003931 struct rpc_auth *auth;
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003932
Trond Myklebustc2190662013-08-26 19:23:04 -04003933 auth = rpcauth_create(&auth_args, server->client);
Anna Schumaker9df13362017-01-11 16:30:08 -05003934 if (IS_ERR(auth))
3935 return -EACCES;
3936 return nfs4_lookup_root(server, fhandle, info);
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003937}
3938
Chuck Lever9a744ba2013-03-16 15:56:02 -04003939/*
3940 * Retry pseudoroot lookup with various security flavors. We do this when:
3941 *
3942 * NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
3943 * NFSv4.1: the server does not support the SECINFO_NO_NAME operation
3944 *
3945 * Returns zero on success, or a negative NFS4ERR value, or a
3946 * negative errno value.
3947 */
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04003948static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
David Howells54ceac42006-08-22 20:06:13 -04003949 struct nfs_fsinfo *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003950{
Chuck Lever9a744ba2013-03-16 15:56:02 -04003951 /* Per 3530bis 15.33.5 */
3952 static const rpc_authflavor_t flav_array[] = {
3953 RPC_AUTH_GSS_KRB5P,
3954 RPC_AUTH_GSS_KRB5I,
3955 RPC_AUTH_GSS_KRB5,
Chuck Leverc4eafe12013-03-16 15:56:11 -04003956 RPC_AUTH_UNIX, /* courtesy */
Chuck Lever9a744ba2013-03-16 15:56:02 -04003957 RPC_AUTH_NULL,
3958 };
3959 int status = -EPERM;
3960 size_t i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961
Weston Andros Adamson4d4b69d2013-10-18 15:15:19 -04003962 if (server->auth_info.flavor_len > 0) {
3963 /* try each flavor specified by user */
3964 for (i = 0; i < server->auth_info.flavor_len; i++) {
3965 status = nfs4_lookup_root_sec(server, fhandle, info,
3966 server->auth_info.flavors[i]);
3967 if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
3968 continue;
3969 break;
3970 }
3971 } else {
3972 /* no flavors specified by user, try default list */
3973 for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
3974 status = nfs4_lookup_root_sec(server, fhandle, info,
3975 flav_array[i]);
3976 if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
3977 continue;
3978 break;
3979 }
Bryan Schumaker8f70e952011-03-24 17:12:31 +00003980 }
Chuck Lever9a744ba2013-03-16 15:56:02 -04003981
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04003982 /*
Colin Ian Kingd3787af2018-10-26 19:10:31 +01003983 * -EACCES could mean that the user doesn't have correct permissions
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04003984 * to access the mount. It could also mean that we tried to mount
3985 * with a gss auth flavor, but rpc.gssd isn't running. Either way,
3986 * existing mount programs don't handle -EACCES very well so it should
3987 * be mapped to -EPERM instead.
3988 */
3989 if (status == -EACCES)
3990 status = -EPERM;
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04003991 return status;
3992}
3993
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04003994/**
3995 * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
3996 * @server: initialized nfs_server handle
3997 * @fhandle: we fill in the pseudo-fs root file handle
3998 * @info: we fill in an FSINFO struct
Trond Myklebust5e6b1992013-09-07 12:58:57 -04003999 * @auth_probe: probe the auth flavours
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04004000 *
4001 * Returns zero on success, or a negative errno.
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04004002 */
Bryan Schumaker3028eb22012-05-10 15:07:30 -04004003int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
Trond Myklebust5e6b1992013-09-07 12:58:57 -04004004 struct nfs_fsinfo *info,
4005 bool auth_probe)
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04004006{
Andre Przywarac7757072015-04-23 17:17:40 +01004007 int status = 0;
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04004008
Andre Przywarac7757072015-04-23 17:17:40 +01004009 if (!auth_probe)
Trond Myklebust5e6b1992013-09-07 12:58:57 -04004010 status = nfs4_lookup_root(server, fhandle, info);
Andre Przywarac7757072015-04-23 17:17:40 +01004011
4012 if (auth_probe || status == NFS4ERR_WRONGSEC)
Trond Myklebust698c9372016-07-25 13:31:14 -04004013 status = server->nfs_client->cl_mvops->find_root_sec(server,
4014 fhandle, info);
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04004015
Linus Torvalds1da177e2005-04-16 15:20:36 -07004016 if (status == 0)
4017 status = nfs4_server_capabilities(server, fhandle);
4018 if (status == 0)
4019 status = nfs4_do_fsinfo(server, fhandle, info);
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04004020
Trond Myklebustc12e87f2006-03-13 21:20:47 -08004021 return nfs4_map_errors(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022}
4023
Bryan Schumakerbae36242012-05-10 15:07:31 -04004024static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
4025 struct nfs_fsinfo *info)
4026{
4027 int error;
4028 struct nfs_fattr *fattr = info->fattr;
Scott Mayhew779df6a2020-03-03 17:58:37 -05004029 struct nfs4_label *label = fattr->label;
Bryan Schumakerbae36242012-05-10 15:07:31 -04004030
4031 error = nfs4_server_capabilities(server, mntfh);
4032 if (error < 0) {
4033 dprintk("nfs4_get_root: getcaps error = %d\n", -error);
4034 return error;
4035 }
4036
Trond Myklebusta841b542018-04-07 13:50:59 -04004037 error = nfs4_proc_getattr(server, mntfh, fattr, label, NULL);
Bryan Schumakerbae36242012-05-10 15:07:31 -04004038 if (error < 0) {
4039 dprintk("nfs4_get_root: getattr error = %d\n", -error);
Scott Mayhew779df6a2020-03-03 17:58:37 -05004040 goto out;
Bryan Schumakerbae36242012-05-10 15:07:31 -04004041 }
4042
4043 if (fattr->valid & NFS_ATTR_FATTR_FSID &&
4044 !nfs_fsid_equal(&server->fsid, &fattr->fsid))
4045 memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
4046
Scott Mayhew779df6a2020-03-03 17:58:37 -05004047out:
Bryan Schumakerbae36242012-05-10 15:07:31 -04004048 return error;
4049}
4050
Manoj Naik6b97fd32006-06-09 09:34:29 -04004051/*
4052 * Get locations and (maybe) other attributes of a referral.
4053 * Note that we'll actually follow the referral later when
4054 * we detect fsid mismatch in inode revalidation
4055 */
Bryan Schumakerf05d1472012-04-27 13:27:41 -04004056static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
4057 const struct qstr *name, struct nfs_fattr *fattr,
4058 struct nfs_fh *fhandle)
Manoj Naik6b97fd32006-06-09 09:34:29 -04004059{
4060 int status = -ENOMEM;
4061 struct page *page = NULL;
4062 struct nfs4_fs_locations *locations = NULL;
Manoj Naik6b97fd32006-06-09 09:34:29 -04004063
4064 page = alloc_page(GFP_KERNEL);
4065 if (page == NULL)
4066 goto out;
4067 locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
4068 if (locations == NULL)
4069 goto out;
4070
Bryan Schumakerf05d1472012-04-27 13:27:41 -04004071 status = nfs4_proc_fs_locations(client, dir, name, locations, page);
Manoj Naik6b97fd32006-06-09 09:34:29 -04004072 if (status != 0)
4073 goto out;
Chuck Lever519ae252013-10-17 14:13:19 -04004074
4075 /*
4076 * If the fsid didn't change, this is a migration event, not a
4077 * referral. Cause us to drop into the exception handler, which
4078 * will kick off migration recovery.
4079 */
Manoj Naik6b97fd32006-06-09 09:34:29 -04004080 if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
Andy Adamson533eb462011-06-13 18:25:56 -04004081 dprintk("%s: server did not return a different fsid for"
4082 " a referral at %s\n", __func__, name->name);
Chuck Lever519ae252013-10-17 14:13:19 -04004083 status = -NFS4ERR_MOVED;
Manoj Naik6b97fd32006-06-09 09:34:29 -04004084 goto out;
4085 }
Andy Adamson533eb462011-06-13 18:25:56 -04004086 /* Fixup attributes for the nfs_lookup() call to nfs_fhget() */
4087 nfs_fixup_referral_attributes(&locations->fattr);
Manoj Naik6b97fd32006-06-09 09:34:29 -04004088
Andy Adamson533eb462011-06-13 18:25:56 -04004089 /* replace the lookup nfs_fattr with the locations nfs_fattr */
Manoj Naik6b97fd32006-06-09 09:34:29 -04004090 memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
Manoj Naik6b97fd32006-06-09 09:34:29 -04004091 memset(fhandle, 0, sizeof(struct nfs_fh));
4092out:
4093 if (page)
4094 __free_page(page);
Davidlohr Bueso5d7ca352010-08-11 12:42:15 -04004095 kfree(locations);
Manoj Naik6b97fd32006-06-09 09:34:29 -04004096 return status;
4097}
4098
David Quigley1775fd32013-05-22 12:50:42 -04004099static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
Trond Myklebusta841b542018-04-07 13:50:59 -04004100 struct nfs_fattr *fattr, struct nfs4_label *label,
4101 struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102{
Trond Myklebust771734f2018-04-07 13:54:23 -04004103 __u32 bitmask[NFS4_BITMASK_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 struct nfs4_getattr_arg args = {
4105 .fh = fhandle,
Trond Myklebust771734f2018-04-07 13:54:23 -04004106 .bitmask = bitmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004107 };
4108 struct nfs4_getattr_res res = {
4109 .fattr = fattr,
David Quigley1775fd32013-05-22 12:50:42 -04004110 .label = label,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111 .server = server,
4112 };
4113 struct rpc_message msg = {
4114 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
4115 .rpc_argp = &args,
4116 .rpc_resp = &res,
4117 };
Trond Myklebustc74dfe92020-01-06 15:39:37 -05004118 unsigned short task_flags = 0;
4119
4120 /* Is this is an attribute revalidation, subject to softreval? */
4121 if (inode && (server->flags & NFS_MOUNT_SOFTREVAL))
4122 task_flags |= RPC_TASK_TIMEOUT;
David Quigleyaa9c2662013-05-22 12:50:44 -04004123
Trond Myklebust771734f2018-04-07 13:54:23 -04004124 nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, label), inode);
David Quigleyaa9c2662013-05-22 12:50:44 -04004125
Trond Myklebust0e574af2005-10-27 22:12:38 -04004126 nfs_fattr_init(fattr);
Trond Myklebustc74dfe92020-01-06 15:39:37 -05004127 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
4128 return nfs4_do_call_sync(server->client, server, &msg,
4129 &args.seq_args, &res.seq_res, task_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004130}
4131
Olga Kornievskaiaec4b0922019-10-08 16:33:53 -04004132int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
Trond Myklebusta841b542018-04-07 13:50:59 -04004133 struct nfs_fattr *fattr, struct nfs4_label *label,
4134 struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004135{
Trond Myklebust0688e642019-04-07 13:59:09 -04004136 struct nfs4_exception exception = {
4137 .interruptible = true,
4138 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 int err;
4140 do {
Trond Myklebusta841b542018-04-07 13:50:59 -04004141 err = _nfs4_proc_getattr(server, fhandle, fattr, label, inode);
Trond Myklebustb5f875a2013-08-13 13:01:39 -04004142 trace_nfs4_getattr(server, fhandle, fattr, err);
4143 err = nfs4_handle_exception(server, err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004144 &exception);
4145 } while (exception.retry);
4146 return err;
4147}
4148
4149/*
4150 * The file is not closed if it is opened due to the a request to change
4151 * the size of the file. The open call will not be needed once the
4152 * VFS layer lookup-intents are implemented.
4153 *
4154 * Close is called when the inode is destroyed.
4155 * If we haven't opened the file for O_WRONLY, we
4156 * need to in the size_change case to obtain a stateid.
4157 *
4158 * Got race?
4159 * Because OPEN is always done by name in nfsv4, it is
4160 * possible that we opened a different file by the same
4161 * name. We can recognize this race condition, but we
4162 * can't do anything about it besides returning an error.
4163 *
4164 * This will be fixed with VFS changes (lookup-intent).
4165 */
4166static int
4167nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
4168 struct iattr *sattr)
4169{
David Howells2b0143b2015-03-17 22:25:59 +00004170 struct inode *inode = d_inode(dentry);
NeilBrowna52458b2018-12-03 11:30:31 +11004171 const struct cred *cred = NULL;
NeilBrown29b59f92016-10-13 15:26:47 +11004172 struct nfs_open_context *ctx = NULL;
David Quigley14c43f72013-05-22 12:50:43 -04004173 struct nfs4_label *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004174 int status;
4175
Peng Tao88ac8152014-09-12 11:04:10 +08004176 if (pnfs_ld_layoutret_on_setattr(inode) &&
4177 sattr->ia_valid & ATTR_SIZE &&
4178 sattr->ia_size < i_size_read(inode))
Trond Myklebust24028672013-03-20 13:23:33 -04004179 pnfs_commit_and_return_layout(inode);
Benny Halevy8a1636c2010-07-14 15:43:57 -04004180
Trond Myklebust0e574af2005-10-27 22:12:38 -04004181 nfs_fattr_init(fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182
Andy Adamson26699402012-05-30 16:12:24 -04004183 /* Deal with open(O_TRUNC) */
4184 if (sattr->ia_valid & ATTR_OPEN)
Nadav Shemercc7936f2013-07-21 17:21:43 +03004185 sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME);
Andy Adamson26699402012-05-30 16:12:24 -04004186
4187 /* Optimization: if the end result is no change, don't RPC */
Nadav Shemercc7936f2013-07-21 17:21:43 +03004188 if ((sattr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
Andy Adamson26699402012-05-30 16:12:24 -04004189 return 0;
4190
Trond Myklebustd5308382005-11-04 15:33:38 -05004191 /* Search for an existing open(O_WRITE) file */
Trond Myklebust659bfcd2008-06-10 19:39:41 -04004192 if (sattr->ia_valid & ATTR_FILE) {
Trond Myklebust08e9eac2005-06-22 17:16:29 +00004193
Trond Myklebust659bfcd2008-06-10 19:39:41 -04004194 ctx = nfs_file_open_context(sattr->ia_file);
NeilBrown29b59f92016-10-13 15:26:47 +11004195 if (ctx)
Neil Brown504e5182008-10-16 14:15:16 +11004196 cred = ctx->cred;
Trond Myklebust659bfcd2008-06-10 19:39:41 -04004197 }
4198
David Quigley14c43f72013-05-22 12:50:43 -04004199 label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
4200 if (IS_ERR(label))
4201 return PTR_ERR(label);
4202
Trond Myklebust199366f2018-03-20 16:43:18 -04004203 /* Return any delegations if we're going to change ACLs */
4204 if ((sattr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0)
Trond Myklebustc01d3642018-03-20 16:43:20 -04004205 nfs4_inode_make_writeable(inode);
Trond Myklebust199366f2018-03-20 16:43:18 -04004206
NeilBrown29b59f92016-10-13 15:26:47 +11004207 status = nfs4_do_setattr(inode, cred, fattr, sattr, ctx, NULL, label);
David Quigleyaa9c2662013-05-22 12:50:44 -04004208 if (status == 0) {
Trond Myklebustf0446362015-02-26 16:09:04 -05004209 nfs_setattr_update_inode(inode, sattr, fattr);
David Quigleyaa9c2662013-05-22 12:50:44 -04004210 nfs_setsecurity(inode, fattr, label);
4211 }
David Quigley14c43f72013-05-22 12:50:43 -04004212 nfs4_label_free(label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 return status;
4214}
4215
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07004216static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004217 struct dentry *dentry, struct nfs_fh *fhandle,
David Quigley1775fd32013-05-22 12:50:42 -04004218 struct nfs_fattr *fattr, struct nfs4_label *label)
David Howells2b3de442006-08-22 20:06:09 -04004219{
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07004220 struct nfs_server *server = NFS_SERVER(dir);
David Howells2b3de442006-08-22 20:06:09 -04004221 int status;
4222 struct nfs4_lookup_arg args = {
4223 .bitmask = server->attr_bitmask,
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07004224 .dir_fh = NFS_FH(dir),
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004225 .name = &dentry->d_name,
David Howells2b3de442006-08-22 20:06:09 -04004226 };
4227 struct nfs4_lookup_res res = {
4228 .server = server,
4229 .fattr = fattr,
David Quigleyaa9c2662013-05-22 12:50:44 -04004230 .label = label,
David Howells2b3de442006-08-22 20:06:09 -04004231 .fh = fhandle,
4232 };
4233 struct rpc_message msg = {
4234 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
4235 .rpc_argp = &args,
4236 .rpc_resp = &res,
4237 };
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004238 unsigned short task_flags = 0;
4239
4240 /* Is this is an attribute revalidation, subject to softreval? */
4241 if (nfs_lookup_is_soft_revalidate(dentry))
4242 task_flags |= RPC_TASK_TIMEOUT;
David Howells2b3de442006-08-22 20:06:09 -04004243
David Quigleyaa9c2662013-05-22 12:50:44 -04004244 args.bitmask = nfs4_bitmask(server, label);
4245
David Howells2b3de442006-08-22 20:06:09 -04004246 nfs_fattr_init(fattr);
4247
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004248 dprintk("NFS call lookup %pd2\n", dentry);
4249 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
4250 status = nfs4_do_call_sync(clnt, server, &msg,
4251 &args.seq_args, &res.seq_res, task_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004252 dprintk("NFS reply lookup: %d\n", status);
4253 return status;
4254}
4255
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004256static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
Bryan Schumaker7ebb9312011-03-24 17:12:30 +00004257{
Bryan Schumaker7ebb9312011-03-24 17:12:30 +00004258 fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004259 NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_MOUNTPOINT;
Bryan Schumaker7ebb9312011-03-24 17:12:30 +00004260 fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
4261 fattr->nlink = 2;
4262}
4263
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004264static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004265 struct dentry *dentry, struct nfs_fh *fhandle,
David Quigley1775fd32013-05-22 12:50:42 -04004266 struct nfs_fattr *fattr, struct nfs4_label *label)
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004267{
Trond Myklebust0688e642019-04-07 13:59:09 -04004268 struct nfs4_exception exception = {
4269 .interruptible = true,
4270 };
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004271 struct rpc_clnt *client = *clnt;
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004272 const struct qstr *name = &dentry->d_name;
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004273 int err;
4274 do {
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004275 err = _nfs4_proc_lookup(client, dir, dentry, fhandle, fattr, label);
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004276 trace_nfs4_lookup(dir, name, err);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004277 switch (err) {
4278 case -NFS4ERR_BADNAME:
4279 err = -ENOENT;
4280 goto out;
4281 case -NFS4ERR_MOVED:
Bryan Schumakerf05d1472012-04-27 13:27:41 -04004282 err = nfs4_get_referral(client, dir, name, fattr, fhandle);
Dominique Martinetc86c90c2015-06-04 17:04:17 +02004283 if (err == -NFS4ERR_MOVED)
4284 err = nfs4_handle_exception(NFS_SERVER(dir), err, &exception);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004285 goto out;
4286 case -NFS4ERR_WRONGSEC:
4287 err = -EPERM;
4288 if (client != *clnt)
4289 goto out;
Andy Adamson66b06862014-06-12 15:02:32 -04004290 client = nfs4_negotiate_security(client, dir, name);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004291 if (IS_ERR(client))
4292 return PTR_ERR(client);
4293
4294 exception.retry = 1;
4295 break;
4296 default:
4297 err = nfs4_handle_exception(NFS_SERVER(dir), err, &exception);
4298 }
4299 } while (exception.retry);
4300
4301out:
4302 if (err == 0)
4303 *clnt = client;
4304 else if (client != *clnt)
4305 rpc_shutdown_client(client);
4306
4307 return err;
4308}
4309
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004310static int nfs4_proc_lookup(struct inode *dir, struct dentry *dentry,
David Quigley1775fd32013-05-22 12:50:42 -04004311 struct nfs_fh *fhandle, struct nfs_fattr *fattr,
4312 struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004313{
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004314 int status;
4315 struct rpc_clnt *client = NFS_CLIENT(dir);
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07004316
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004317 status = nfs4_proc_lookup_common(&client, dir, dentry, fhandle, fattr, label);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04004318 if (client != NFS_CLIENT(dir)) {
4319 rpc_shutdown_client(client);
4320 nfs_fixup_secinfo_attributes(fattr);
4321 }
4322 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323}
4324
Bryan Schumakerf05d1472012-04-27 13:27:41 -04004325struct rpc_clnt *
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004326nfs4_proc_lookup_mountpoint(struct inode *dir, struct dentry *dentry,
Bryan Schumakerf05d1472012-04-27 13:27:41 -04004327 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
4328{
Trond Myklebustb72888c2013-08-07 20:38:07 -04004329 struct rpc_clnt *client = NFS_CLIENT(dir);
Bryan Schumakerf05d1472012-04-27 13:27:41 -04004330 int status;
Bryan Schumakerf05d1472012-04-27 13:27:41 -04004331
Trond Myklebustf7b37b82020-01-14 12:06:34 -05004332 status = nfs4_proc_lookup_common(&client, dir, dentry, fhandle, fattr, NULL);
Trond Myklebustb72888c2013-08-07 20:38:07 -04004333 if (status < 0)
Bryan Schumakerf05d1472012-04-27 13:27:41 -04004334 return ERR_PTR(status);
Trond Myklebustb72888c2013-08-07 20:38:07 -04004335 return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client;
Bryan Schumakerf05d1472012-04-27 13:27:41 -04004336}
4337
Jeff Layton5b5faaf2017-06-29 06:34:52 -07004338static int _nfs4_proc_lookupp(struct inode *inode,
4339 struct nfs_fh *fhandle, struct nfs_fattr *fattr,
4340 struct nfs4_label *label)
4341{
4342 struct rpc_clnt *clnt = NFS_CLIENT(inode);
4343 struct nfs_server *server = NFS_SERVER(inode);
4344 int status;
4345 struct nfs4_lookupp_arg args = {
4346 .bitmask = server->attr_bitmask,
4347 .fh = NFS_FH(inode),
4348 };
4349 struct nfs4_lookupp_res res = {
4350 .server = server,
4351 .fattr = fattr,
4352 .label = label,
4353 .fh = fhandle,
4354 };
4355 struct rpc_message msg = {
4356 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUPP],
4357 .rpc_argp = &args,
4358 .rpc_resp = &res,
4359 };
4360
4361 args.bitmask = nfs4_bitmask(server, label);
4362
4363 nfs_fattr_init(fattr);
4364
4365 dprintk("NFS call lookupp ino=0x%lx\n", inode->i_ino);
4366 status = nfs4_call_sync(clnt, server, &msg, &args.seq_args,
4367 &res.seq_res, 0);
4368 dprintk("NFS reply lookupp: %d\n", status);
4369 return status;
4370}
4371
4372static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
4373 struct nfs_fattr *fattr, struct nfs4_label *label)
4374{
Trond Myklebust0688e642019-04-07 13:59:09 -04004375 struct nfs4_exception exception = {
4376 .interruptible = true,
4377 };
Jeff Layton5b5faaf2017-06-29 06:34:52 -07004378 int err;
4379 do {
4380 err = _nfs4_proc_lookupp(inode, fhandle, fattr, label);
4381 trace_nfs4_lookupp(inode, err);
4382 err = nfs4_handle_exception(NFS_SERVER(inode), err,
4383 &exception);
4384 } while (exception.retry);
4385 return err;
4386}
4387
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
4389{
Trond Myklebust76b32992007-08-10 17:45:11 -04004390 struct nfs_server *server = NFS_SERVER(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 struct nfs4_accessargs args = {
4392 .fh = NFS_FH(inode),
Anna Schumaker1750d922017-07-26 12:00:21 -04004393 .access = entry->mask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004394 };
Trond Myklebust76b32992007-08-10 17:45:11 -04004395 struct nfs4_accessres res = {
4396 .server = server,
Trond Myklebust76b32992007-08-10 17:45:11 -04004397 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004398 struct rpc_message msg = {
4399 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
4400 .rpc_argp = &args,
4401 .rpc_resp = &res,
4402 .rpc_cred = entry->cred,
4403 };
David Quigleyaa9c2662013-05-22 12:50:44 -04004404 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004405
Trond Myklebust7c672652018-06-04 15:00:53 -04004406 if (!nfs4_have_delegation(inode, FMODE_READ)) {
Trond Myklebust8bcbe7d2018-03-20 17:03:11 -04004407 res.fattr = nfs_alloc_fattr();
4408 if (res.fattr == NULL)
4409 return -ENOMEM;
4410 args.bitmask = server->cache_consistency_bitmask;
4411 }
Bryan Schumaker7c513052011-03-24 17:12:24 +00004412 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 if (!status) {
Weston Andros Adamson6168f622012-09-10 14:00:46 -04004414 nfs_access_set_mask(entry, res.access);
Trond Myklebust8bcbe7d2018-03-20 17:03:11 -04004415 if (res.fattr)
4416 nfs_refresh_inode(inode, res.fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004417 }
Trond Myklebustc407d412010-04-16 16:22:48 -04004418 nfs_free_fattr(res.fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 return status;
4420}
4421
4422static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
4423{
Trond Myklebust0688e642019-04-07 13:59:09 -04004424 struct nfs4_exception exception = {
4425 .interruptible = true,
4426 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427 int err;
4428 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04004429 err = _nfs4_proc_access(inode, entry);
4430 trace_nfs4_access(inode, err);
4431 err = nfs4_handle_exception(NFS_SERVER(inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 &exception);
4433 } while (exception.retry);
4434 return err;
4435}
4436
4437/*
4438 * TODO: For the time being, we don't try to get any attributes
4439 * along with any of the zero-copy operations READ, READDIR,
4440 * READLINK, WRITE.
4441 *
4442 * In the case of the first three, we want to put the GETATTR
4443 * after the read-type operation -- this is because it is hard
4444 * to predict the length of a GETATTR response in v4, and thus
4445 * align the READ data correctly. This means that the GETATTR
4446 * may end up partially falling into the page cache, and we should
4447 * shift it into the 'tail' of the xdr_buf before processing.
4448 * To do this efficiently, we need to know the total length
4449 * of data received, which doesn't seem to be available outside
4450 * of the RPC layer.
4451 *
4452 * In the case of WRITE, we also want to put the GETATTR after
4453 * the operation -- in this case because we want to make sure
Trond Myklebust140150d2012-06-05 15:20:25 -04004454 * we get the post-operation mtime and size.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455 *
4456 * Both of these changes to the XDR layer would in fact be quite
4457 * minor, but I decided to leave them for a subsequent patch.
4458 */
4459static int _nfs4_proc_readlink(struct inode *inode, struct page *page,
4460 unsigned int pgbase, unsigned int pglen)
4461{
4462 struct nfs4_readlink args = {
4463 .fh = NFS_FH(inode),
4464 .pgbase = pgbase,
4465 .pglen = pglen,
4466 .pages = &page,
4467 };
Benny Halevyf50c7002009-04-01 09:21:55 -04004468 struct nfs4_readlink_res res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469 struct rpc_message msg = {
4470 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK],
4471 .rpc_argp = &args,
Benny Halevyf50c7002009-04-01 09:21:55 -04004472 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 };
4474
Bryan Schumaker7c513052011-03-24 17:12:24 +00004475 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 -07004476}
4477
4478static int nfs4_proc_readlink(struct inode *inode, struct page *page,
4479 unsigned int pgbase, unsigned int pglen)
4480{
Trond Myklebust0688e642019-04-07 13:59:09 -04004481 struct nfs4_exception exception = {
4482 .interruptible = true,
4483 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 int err;
4485 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04004486 err = _nfs4_proc_readlink(inode, page, pgbase, pglen);
4487 trace_nfs4_readlink(inode, err);
4488 err = nfs4_handle_exception(NFS_SERVER(inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004489 &exception);
4490 } while (exception.retry);
4491 return err;
4492}
4493
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494/*
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004495 * This is just for mknod. open(O_CREAT) will always do ->open_context().
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004497static int
4498nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004499 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500{
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004501 struct nfs_server *server = NFS_SERVER(dir);
David Quigleyaa9c2662013-05-22 12:50:44 -04004502 struct nfs4_label l, *ilabel = NULL;
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004503 struct nfs_open_context *ctx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004504 struct nfs4_state *state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004505 int status = 0;
4506
NeilBrown532d4de2016-10-13 15:26:47 +11004507 ctx = alloc_nfs_open_context(dentry, FMODE_READ, NULL);
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004508 if (IS_ERR(ctx))
4509 return PTR_ERR(ctx);
4510
David Quigleyaa9c2662013-05-22 12:50:44 -04004511 ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
4512
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004513 if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
4514 sattr->ia_mode &= ~current_umask();
Kinglong Meec5c3fb52015-08-26 21:11:39 +08004515 state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004516 if (IS_ERR(state)) {
4517 status = PTR_ERR(state);
Trond Myklebustc0204fd2010-09-17 10:56:51 -04004518 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004519 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520out:
David Quigleyaa9c2662013-05-22 12:50:44 -04004521 nfs4_label_release_security(ilabel);
Miklos Szeredi8867fe52012-06-05 15:10:19 +02004522 put_nfs_open_context(ctx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004523 return status;
4524}
4525
Trond Myklebust3c591172018-07-31 15:54:10 -04004526static int
4527_nfs4_proc_remove(struct inode *dir, const struct qstr *name, u32 ftype)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004528{
Trond Myklebust16e42952005-10-27 22:12:44 -04004529 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04004530 struct nfs_removeargs args = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004531 .fh = NFS_FH(dir),
Linus Torvalds26fe5752012-05-10 13:14:12 -07004532 .name = *name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533 };
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04004534 struct nfs_removeres res = {
Trond Myklebust16e42952005-10-27 22:12:44 -04004535 .server = server,
Trond Myklebust16e42952005-10-27 22:12:44 -04004536 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004537 struct rpc_message msg = {
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04004538 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
4539 .rpc_argp = &args,
4540 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004541 };
Trond Myklebustd3129ef2017-01-11 22:07:28 -05004542 unsigned long timestamp = jiffies;
Trond Myklebust778d2812012-04-27 13:48:19 -04004543 int status;
Trond Myklebustd3468902010-04-16 16:22:50 -04004544
Bryan Schumaker7c513052011-03-24 17:12:24 +00004545 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
Trond Myklebust3c591172018-07-31 15:54:10 -04004546 if (status == 0) {
4547 spin_lock(&dir->i_lock);
Frank van der Linden1b523ca2020-06-23 22:38:59 +00004548 nfs4_update_changeattr_locked(dir, &res.cinfo, timestamp,
4549 NFS_INO_INVALID_DATA);
Trond Myklebust3c591172018-07-31 15:54:10 -04004550 /* Removing a directory decrements nlink in the parent */
4551 if (ftype == NF4DIR && dir->i_nlink > 2)
4552 nfs4_dec_nlink_locked(dir);
4553 spin_unlock(&dir->i_lock);
4554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004555 return status;
4556}
4557
Trond Myklebust912678d2018-03-20 16:43:15 -04004558static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
4559{
Trond Myklebust0688e642019-04-07 13:59:09 -04004560 struct nfs4_exception exception = {
4561 .interruptible = true,
4562 };
Trond Myklebust912678d2018-03-20 16:43:15 -04004563 struct inode *inode = d_inode(dentry);
4564 int err;
4565
Trond Myklebustc01d3642018-03-20 16:43:20 -04004566 if (inode) {
4567 if (inode->i_nlink == 1)
4568 nfs4_inode_return_delegation(inode);
4569 else
4570 nfs4_inode_make_writeable(inode);
4571 }
Trond Myklebust912678d2018-03-20 16:43:15 -04004572 do {
Trond Myklebust3c591172018-07-31 15:54:10 -04004573 err = _nfs4_proc_remove(dir, &dentry->d_name, NF4REG);
Trond Myklebust912678d2018-03-20 16:43:15 -04004574 trace_nfs4_remove(dir, &dentry->d_name, err);
4575 err = nfs4_handle_exception(NFS_SERVER(dir), err,
4576 &exception);
4577 } while (exception.retry);
4578 return err;
4579}
4580
4581static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004582{
Trond Myklebust0688e642019-04-07 13:59:09 -04004583 struct nfs4_exception exception = {
4584 .interruptible = true,
4585 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 int err;
Trond Myklebust912678d2018-03-20 16:43:15 -04004587
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 do {
Trond Myklebust3c591172018-07-31 15:54:10 -04004589 err = _nfs4_proc_remove(dir, name, NF4DIR);
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004590 trace_nfs4_remove(dir, name, err);
4591 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 &exception);
4593 } while (exception.retry);
4594 return err;
4595}
4596
Trond Myklebusted7e9ad2018-05-30 16:11:52 -04004597static void nfs4_proc_unlink_setup(struct rpc_message *msg,
4598 struct dentry *dentry,
4599 struct inode *inode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004600{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004601 struct nfs_removeargs *args = msg->rpc_argp;
4602 struct nfs_removeres *res = msg->rpc_resp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004603
Trond Myklebust977fcc22018-03-20 16:43:17 -04004604 res->server = NFS_SB(dentry->d_sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
Anna Schumakerfba83f32018-05-04 16:22:50 -04004606 nfs4_init_sequence(&args->seq_args, &res->seq_res, 1, 0);
David Quigleyaa9c2662013-05-22 12:50:44 -04004607
4608 nfs_fattr_init(res->dir_attr);
Trond Myklebust977fcc22018-03-20 16:43:17 -04004609
4610 if (inode)
4611 nfs4_inode_return_delegation(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612}
4613
Bryan Schumaker34e137c2012-03-19 14:54:41 -04004614static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
4615{
Anna Schumaker42e1cca2017-01-09 15:48:22 -05004616 nfs4_setup_sequence(NFS_SB(data->dentry->d_sb)->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04004617 &data->args.seq_args,
4618 &data->res.seq_res,
4619 task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004620}
4621
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004622static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623{
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004624 struct nfs_unlinkdata *data = task->tk_calldata;
4625 struct nfs_removeres *res = &data->res;
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004626
Trond Myklebust14516c32010-07-31 14:29:06 -04004627 if (!nfs4_sequence_done(task, &res->seq_res))
4628 return 0;
NeilBrown8478eaa2014-09-18 16:09:27 +10004629 if (nfs4_async_handle_error(task, res->server, NULL,
4630 &data->timeout) == -EAGAIN)
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004631 return 0;
Trond Myklebustc40d52f2017-01-11 12:36:11 -05004632 if (task->tk_status == 0)
Frank van der Linden1b523ca2020-06-23 22:38:59 +00004633 nfs4_update_changeattr(dir, &res->cinfo,
4634 res->dir_attr->time_start,
4635 NFS_INO_INVALID_DATA);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04004636 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637}
4638
Trond Myklebustf2c2c552018-03-20 16:43:16 -04004639static void nfs4_proc_rename_setup(struct rpc_message *msg,
4640 struct dentry *old_dentry,
4641 struct dentry *new_dentry)
Jeff Laytond3d41522010-09-17 17:31:57 -04004642{
Jeff Laytond3d41522010-09-17 17:31:57 -04004643 struct nfs_renameargs *arg = msg->rpc_argp;
4644 struct nfs_renameres *res = msg->rpc_resp;
Trond Myklebustf2c2c552018-03-20 16:43:16 -04004645 struct inode *old_inode = d_inode(old_dentry);
4646 struct inode *new_inode = d_inode(new_dentry);
Jeff Laytond3d41522010-09-17 17:31:57 -04004647
Trond Myklebustf2c2c552018-03-20 16:43:16 -04004648 if (old_inode)
Trond Myklebustc01d3642018-03-20 16:43:20 -04004649 nfs4_inode_make_writeable(old_inode);
Trond Myklebustf2c2c552018-03-20 16:43:16 -04004650 if (new_inode)
4651 nfs4_inode_return_delegation(new_inode);
Jeff Laytond3d41522010-09-17 17:31:57 -04004652 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
Trond Myklebustf2c2c552018-03-20 16:43:16 -04004653 res->server = NFS_SB(old_dentry->d_sb);
Anna Schumakerfba83f32018-05-04 16:22:50 -04004654 nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1, 0);
Jeff Laytond3d41522010-09-17 17:31:57 -04004655}
4656
Bryan Schumakerc6bfa1a2012-03-19 14:54:42 -04004657static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
4658{
Anna Schumaker42e1cca2017-01-09 15:48:22 -05004659 nfs4_setup_sequence(NFS_SERVER(data->old_dir)->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04004660 &data->args.seq_args,
4661 &data->res.seq_res,
4662 task);
Jeff Laytond3d41522010-09-17 17:31:57 -04004663}
4664
4665static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
4666 struct inode *new_dir)
4667{
Trond Myklebustfbc6f7c2013-08-12 17:08:26 -04004668 struct nfs_renamedata *data = task->tk_calldata;
4669 struct nfs_renameres *res = &data->res;
Jeff Laytond3d41522010-09-17 17:31:57 -04004670
4671 if (!nfs4_sequence_done(task, &res->seq_res))
4672 return 0;
NeilBrown8478eaa2014-09-18 16:09:27 +10004673 if (nfs4_async_handle_error(task, res->server, NULL, &data->timeout) == -EAGAIN)
Jeff Laytond3d41522010-09-17 17:31:57 -04004674 return 0;
4675
Trond Myklebustc733c492017-01-11 12:32:26 -05004676 if (task->tk_status == 0) {
Trond Myklebust5636ec42018-07-31 15:54:11 -04004677 if (new_dir != old_dir) {
4678 /* Note: If we moved a directory, nlink will change */
Frank van der Linden1b523ca2020-06-23 22:38:59 +00004679 nfs4_update_changeattr(old_dir, &res->old_cinfo,
Trond Myklebust5636ec42018-07-31 15:54:11 -04004680 res->old_fattr->time_start,
Frank van der Linden1b523ca2020-06-23 22:38:59 +00004681 NFS_INO_INVALID_OTHER |
4682 NFS_INO_INVALID_DATA);
4683 nfs4_update_changeattr(new_dir, &res->new_cinfo,
Trond Myklebust5636ec42018-07-31 15:54:11 -04004684 res->new_fattr->time_start,
Frank van der Linden1b523ca2020-06-23 22:38:59 +00004685 NFS_INO_INVALID_OTHER |
4686 NFS_INO_INVALID_DATA);
Trond Myklebust5636ec42018-07-31 15:54:11 -04004687 } else
Frank van der Linden1b523ca2020-06-23 22:38:59 +00004688 nfs4_update_changeattr(old_dir, &res->old_cinfo,
Trond Myklebust5636ec42018-07-31 15:54:11 -04004689 res->old_fattr->time_start,
Frank van der Linden1b523ca2020-06-23 22:38:59 +00004690 NFS_INO_INVALID_DATA);
Trond Myklebustc733c492017-01-11 12:32:26 -05004691 }
Jeff Laytond3d41522010-09-17 17:31:57 -04004692 return 1;
4693}
4694
Al Virobeffb8f2016-07-20 16:34:42 -04004695static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696{
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004697 struct nfs_server *server = NFS_SERVER(inode);
Trond Myklebust2f28dc32018-04-08 21:06:40 -04004698 __u32 bitmask[NFS4_BITMASK_SZ];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004699 struct nfs4_link_arg arg = {
4700 .fh = NFS_FH(inode),
4701 .dir_fh = NFS_FH(dir),
4702 .name = name,
Trond Myklebust2f28dc32018-04-08 21:06:40 -04004703 .bitmask = bitmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704 };
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004705 struct nfs4_link_res res = {
4706 .server = server,
David Quigley1775fd32013-05-22 12:50:42 -04004707 .label = NULL,
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004708 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709 struct rpc_message msg = {
4710 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
4711 .rpc_argp = &arg,
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004712 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 };
Trond Myklebust136f2622010-04-16 16:22:49 -04004714 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715
Trond Myklebust136f2622010-04-16 16:22:49 -04004716 res.fattr = nfs_alloc_fattr();
Trond Myklebust778d2812012-04-27 13:48:19 -04004717 if (res.fattr == NULL)
Trond Myklebust136f2622010-04-16 16:22:49 -04004718 goto out;
4719
David Quigley14c43f72013-05-22 12:50:43 -04004720 res.label = nfs4_label_alloc(server, GFP_KERNEL);
4721 if (IS_ERR(res.label)) {
4722 status = PTR_ERR(res.label);
4723 goto out;
4724 }
4725
Trond Myklebustc01d3642018-03-20 16:43:20 -04004726 nfs4_inode_make_writeable(inode);
Trond Myklebust2f28dc32018-04-08 21:06:40 -04004727 nfs4_bitmap_copy_adjust_setattr(bitmask, nfs4_bitmask(server, res.label), inode);
Trond Myklebust9f768272018-03-20 16:43:14 -04004728
Bryan Schumaker7c513052011-03-24 17:12:24 +00004729 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004730 if (!status) {
Frank van der Linden1b523ca2020-06-23 22:38:59 +00004731 nfs4_update_changeattr(dir, &res.cinfo, res.fattr->time_start,
4732 NFS_INO_INVALID_DATA);
David Quigleyaa9c2662013-05-22 12:50:44 -04004733 status = nfs_post_op_update_inode(inode, res.fattr);
4734 if (!status)
4735 nfs_setsecurity(inode, res.fattr, res.label);
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04004736 }
David Quigley14c43f72013-05-22 12:50:43 -04004737
4738
4739 nfs4_label_free(res.label);
4740
Trond Myklebust136f2622010-04-16 16:22:49 -04004741out:
Trond Myklebust136f2622010-04-16 16:22:49 -04004742 nfs_free_fattr(res.fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743 return status;
4744}
4745
Al Virobeffb8f2016-07-20 16:34:42 -04004746static int nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747{
Trond Myklebust0688e642019-04-07 13:59:09 -04004748 struct nfs4_exception exception = {
4749 .interruptible = true,
4750 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751 int err;
4752 do {
4753 err = nfs4_handle_exception(NFS_SERVER(inode),
4754 _nfs4_proc_link(inode, dir, name),
4755 &exception);
4756 } while (exception.retry);
4757 return err;
4758}
4759
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004760struct nfs4_createdata {
4761 struct rpc_message msg;
4762 struct nfs4_create_arg arg;
4763 struct nfs4_create_res res;
4764 struct nfs_fh fh;
4765 struct nfs_fattr fattr;
David Quigley1775fd32013-05-22 12:50:42 -04004766 struct nfs4_label *label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004767};
4768
4769static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
Al Virobeffb8f2016-07-20 16:34:42 -04004770 const struct qstr *name, struct iattr *sattr, u32 ftype)
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004771{
4772 struct nfs4_createdata *data;
4773
4774 data = kzalloc(sizeof(*data), GFP_KERNEL);
4775 if (data != NULL) {
4776 struct nfs_server *server = NFS_SERVER(dir);
4777
David Quigley14c43f72013-05-22 12:50:43 -04004778 data->label = nfs4_label_alloc(server, GFP_KERNEL);
4779 if (IS_ERR(data->label))
4780 goto out_free;
4781
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004782 data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
4783 data->msg.rpc_argp = &data->arg;
4784 data->msg.rpc_resp = &data->res;
4785 data->arg.dir_fh = NFS_FH(dir);
4786 data->arg.server = server;
4787 data->arg.name = name;
4788 data->arg.attrs = sattr;
4789 data->arg.ftype = ftype;
David Quigleyaa9c2662013-05-22 12:50:44 -04004790 data->arg.bitmask = nfs4_bitmask(server, data->label);
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004791 data->arg.umask = current_umask();
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004792 data->res.server = server;
4793 data->res.fh = &data->fh;
4794 data->res.fattr = &data->fattr;
David Quigley1775fd32013-05-22 12:50:42 -04004795 data->res.label = data->label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004796 nfs_fattr_init(data->res.fattr);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004797 }
4798 return data;
David Quigley14c43f72013-05-22 12:50:43 -04004799out_free:
4800 kfree(data);
4801 return NULL;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004802}
4803
4804static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
4805{
Bryan Schumaker7c513052011-03-24 17:12:24 +00004806 int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
Bryan Schumakere73b83f2011-03-24 17:12:23 +00004807 &data->arg.seq_args, &data->res.seq_res, 1);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004808 if (status == 0) {
Trond Myklebust3c591172018-07-31 15:54:10 -04004809 spin_lock(&dir->i_lock);
Frank van der Linden1b523ca2020-06-23 22:38:59 +00004810 nfs4_update_changeattr_locked(dir, &data->res.dir_cinfo,
4811 data->res.fattr->time_start,
4812 NFS_INO_INVALID_DATA);
Trond Myklebust3c591172018-07-31 15:54:10 -04004813 /* Creating a directory bumps nlink in the parent */
4814 if (data->arg.ftype == NF4DIR)
4815 nfs4_inc_nlink_locked(dir);
4816 spin_unlock(&dir->i_lock);
David Quigley1775fd32013-05-22 12:50:42 -04004817 status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004818 }
4819 return status;
4820}
4821
4822static void nfs4_free_createdata(struct nfs4_createdata *data)
4823{
David Quigley14c43f72013-05-22 12:50:43 -04004824 nfs4_label_free(data->label);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004825 kfree(data);
4826}
4827
Chuck Lever4f390c12006-08-22 20:06:22 -04004828static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
David Quigley1775fd32013-05-22 12:50:42 -04004829 struct page *page, unsigned int len, struct iattr *sattr,
4830 struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831{
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004832 struct nfs4_createdata *data;
4833 int status = -ENAMETOOLONG;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834
Chuck Lever94a6d752006-08-22 20:06:23 -04004835 if (len > NFS4_MAXPATHLEN)
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004836 goto out;
Chuck Lever4f390c12006-08-22 20:06:22 -04004837
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004838 status = -ENOMEM;
4839 data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4LNK);
4840 if (data == NULL)
4841 goto out;
4842
4843 data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
4844 data->arg.u.symlink.pages = &page;
4845 data->arg.u.symlink.len = len;
David Quigley1775fd32013-05-22 12:50:42 -04004846 data->arg.label = label;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004848 status = nfs4_do_create(dir, dentry, data);
4849
4850 nfs4_free_createdata(data);
4851out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004852 return status;
4853}
4854
Chuck Lever4f390c12006-08-22 20:06:22 -04004855static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
Chuck Lever94a6d752006-08-22 20:06:23 -04004856 struct page *page, unsigned int len, struct iattr *sattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857{
Trond Myklebust0688e642019-04-07 13:59:09 -04004858 struct nfs4_exception exception = {
4859 .interruptible = true,
4860 };
David Quigleyaa9c2662013-05-22 12:50:44 -04004861 struct nfs4_label l, *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004862 int err;
David Quigleyaa9c2662013-05-22 12:50:44 -04004863
4864 label = nfs4_label_init_security(dir, dentry, sattr, &l);
4865
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004867 err = _nfs4_proc_symlink(dir, dentry, page, len, sattr, label);
4868 trace_nfs4_symlink(dir, &dentry->d_name, err);
4869 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004870 &exception);
4871 } while (exception.retry);
David Quigleyaa9c2662013-05-22 12:50:44 -04004872
4873 nfs4_label_release_security(label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 return err;
4875}
4876
4877static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
David Quigley1775fd32013-05-22 12:50:42 -04004878 struct iattr *sattr, struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879{
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004880 struct nfs4_createdata *data;
4881 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004882
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004883 data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR);
4884 if (data == NULL)
4885 goto out;
4886
David Quigley1775fd32013-05-22 12:50:42 -04004887 data->arg.label = label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004888 status = nfs4_do_create(dir, dentry, data);
4889
4890 nfs4_free_createdata(data);
4891out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004892 return status;
4893}
4894
4895static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
4896 struct iattr *sattr)
4897{
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004898 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebust0688e642019-04-07 13:59:09 -04004899 struct nfs4_exception exception = {
4900 .interruptible = true,
4901 };
David Quigleyaa9c2662013-05-22 12:50:44 -04004902 struct nfs4_label l, *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004903 int err;
Aneesh Kumar K.Va8a5da92010-12-09 11:35:14 +00004904
David Quigleyaa9c2662013-05-22 12:50:44 -04004905 label = nfs4_label_init_security(dir, dentry, sattr, &l);
4906
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05004907 if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
4908 sattr->ia_mode &= ~current_umask();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004909 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04004910 err = _nfs4_proc_mkdir(dir, dentry, sattr, label);
4911 trace_nfs4_mkdir(dir, &dentry->d_name, err);
4912 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 &exception);
4914 } while (exception.retry);
David Quigleyaa9c2662013-05-22 12:50:44 -04004915 nfs4_label_release_security(label);
4916
Linus Torvalds1da177e2005-04-16 15:20:36 -07004917 return err;
4918}
4919
NeilBrown684f39b2018-12-03 11:30:30 +11004920static int _nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04004921 u64 cookie, struct page **pages, unsigned int count, bool plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004922{
David Howells2b0143b2015-03-17 22:25:59 +00004923 struct inode *dir = d_inode(dentry);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004924 struct nfs4_readdir_arg args = {
4925 .fh = NFS_FH(dir),
Bryan Schumaker56e4ebf2010-10-20 15:44:37 -04004926 .pages = pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004927 .pgbase = 0,
4928 .count = count,
David Howells2b0143b2015-03-17 22:25:59 +00004929 .bitmask = NFS_SERVER(d_inode(dentry))->attr_bitmask,
Bryan Schumaker82f2e542010-10-21 16:33:18 -04004930 .plus = plus,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004931 };
4932 struct nfs4_readdir_res res;
4933 struct rpc_message msg = {
4934 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
4935 .rpc_argp = &args,
4936 .rpc_resp = &res,
4937 .rpc_cred = cred,
4938 };
4939 int status;
4940
Al Viro6de14722013-09-16 10:53:17 -04004941 dprintk("%s: dentry = %pd2, cookie = %Lu\n", __func__,
4942 dentry,
Trond Myklebusteadf4592005-06-22 17:16:39 +00004943 (unsigned long long)cookie);
Trond Myklebustc3f52af2012-09-03 14:56:02 -04004944 nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945 res.pgbase = args.pgbase;
Bryan Schumaker7c513052011-03-24 17:12:24 +00004946 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 -05004947 if (status >= 0) {
Trond Myklebustc3f52af2012-09-03 14:56:02 -04004948 memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE);
Trond Myklebustac396122010-11-15 20:26:22 -05004949 status += args.pgbase;
4950 }
Trond Myklebustc4812992007-09-28 17:11:45 -04004951
4952 nfs_invalidate_atime(dir);
4953
Harvey Harrison3110ff82008-05-02 13:42:44 -07004954 dprintk("%s: returns %d\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 return status;
4956}
4957
NeilBrown684f39b2018-12-03 11:30:30 +11004958static int nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04004959 u64 cookie, struct page **pages, unsigned int count, bool plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004960{
Trond Myklebust0688e642019-04-07 13:59:09 -04004961 struct nfs4_exception exception = {
4962 .interruptible = true,
4963 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964 int err;
4965 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04004966 err = _nfs4_proc_readdir(dentry, cred, cookie,
4967 pages, count, plus);
David Howells2b0143b2015-03-17 22:25:59 +00004968 trace_nfs4_readdir(d_inode(dentry), err);
4969 err = nfs4_handle_exception(NFS_SERVER(d_inode(dentry)), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004970 &exception);
4971 } while (exception.retry);
4972 return err;
4973}
4974
4975static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
David Quigleyaa9c2662013-05-22 12:50:44 -04004976 struct iattr *sattr, struct nfs4_label *label, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004977{
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004978 struct nfs4_createdata *data;
4979 int mode = sattr->ia_mode;
4980 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004981
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004982 data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK);
4983 if (data == NULL)
4984 goto out;
4985
Linus Torvalds1da177e2005-04-16 15:20:36 -07004986 if (S_ISFIFO(mode))
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004987 data->arg.ftype = NF4FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004988 else if (S_ISBLK(mode)) {
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004989 data->arg.ftype = NF4BLK;
4990 data->arg.u.device.specdata1 = MAJOR(rdev);
4991 data->arg.u.device.specdata2 = MINOR(rdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004992 }
4993 else if (S_ISCHR(mode)) {
Trond Myklebust57dc9a52008-06-20 15:35:32 -04004994 data->arg.ftype = NF4CHR;
4995 data->arg.u.device.specdata1 = MAJOR(rdev);
4996 data->arg.u.device.specdata2 = MINOR(rdev);
Trond Myklebust4ea8fed2012-10-15 15:47:41 -04004997 } else if (!S_ISSOCK(mode)) {
4998 status = -EINVAL;
4999 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005000 }
David Quigley1775fd32013-05-22 12:50:42 -04005001
David Quigleyaa9c2662013-05-22 12:50:44 -04005002 data->arg.label = label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04005003 status = nfs4_do_create(dir, dentry, data);
Trond Myklebust4ea8fed2012-10-15 15:47:41 -04005004out_free:
Trond Myklebust57dc9a52008-06-20 15:35:32 -04005005 nfs4_free_createdata(data);
5006out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005007 return status;
5008}
5009
5010static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
5011 struct iattr *sattr, dev_t rdev)
5012{
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05005013 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebust0688e642019-04-07 13:59:09 -04005014 struct nfs4_exception exception = {
5015 .interruptible = true,
5016 };
David Quigleyaa9c2662013-05-22 12:50:44 -04005017 struct nfs4_label l, *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005018 int err;
Aneesh Kumar K.Va8a5da92010-12-09 11:35:14 +00005019
David Quigleyaa9c2662013-05-22 12:50:44 -04005020 label = nfs4_label_init_security(dir, dentry, sattr, &l);
5021
Andreas Gruenbacherdff25dd2016-12-02 22:53:30 -05005022 if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK))
5023 sattr->ia_mode &= ~current_umask();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005024 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04005025 err = _nfs4_proc_mknod(dir, dentry, sattr, label, rdev);
5026 trace_nfs4_mknod(dir, &dentry->d_name, err);
5027 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005028 &exception);
5029 } while (exception.retry);
David Quigleyaa9c2662013-05-22 12:50:44 -04005030
5031 nfs4_label_release_security(label);
5032
Linus Torvalds1da177e2005-04-16 15:20:36 -07005033 return err;
5034}
5035
5036static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
5037 struct nfs_fsstat *fsstat)
5038{
5039 struct nfs4_statfs_arg args = {
5040 .fh = fhandle,
5041 .bitmask = server->attr_bitmask,
5042 };
Benny Halevy24ad1482009-04-01 09:21:56 -04005043 struct nfs4_statfs_res res = {
5044 .fsstat = fsstat,
5045 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005046 struct rpc_message msg = {
5047 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS],
5048 .rpc_argp = &args,
Benny Halevy24ad1482009-04-01 09:21:56 -04005049 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005050 };
5051
Trond Myklebust0e574af2005-10-27 22:12:38 -04005052 nfs_fattr_init(fsstat->fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00005053 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005054}
5055
5056static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
5057{
Trond Myklebust0688e642019-04-07 13:59:09 -04005058 struct nfs4_exception exception = {
5059 .interruptible = true,
5060 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005061 int err;
5062 do {
5063 err = nfs4_handle_exception(server,
5064 _nfs4_proc_statfs(server, fhandle, fsstat),
5065 &exception);
5066 } while (exception.retry);
5067 return err;
5068}
5069
5070static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
5071 struct nfs_fsinfo *fsinfo)
5072{
5073 struct nfs4_fsinfo_arg args = {
5074 .fh = fhandle,
5075 .bitmask = server->attr_bitmask,
5076 };
Benny Halevy3dda5e42009-04-01 09:21:57 -04005077 struct nfs4_fsinfo_res res = {
5078 .fsinfo = fsinfo,
5079 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005080 struct rpc_message msg = {
5081 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO],
5082 .rpc_argp = &args,
Benny Halevy3dda5e42009-04-01 09:21:57 -04005083 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005084 };
5085
Bryan Schumaker7c513052011-03-24 17:12:24 +00005086 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005087}
5088
5089static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
5090{
Trond Myklebust0688e642019-04-07 13:59:09 -04005091 struct nfs4_exception exception = {
5092 .interruptible = true,
5093 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005094 int err;
5095
5096 do {
Chuck Lever83ca7f52013-03-16 15:55:53 -04005097 err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
Trond Myklebustb5f875a2013-08-13 13:01:39 -04005098 trace_nfs4_fsinfo(server, fhandle, fsinfo->fattr, err);
Chuck Lever83ca7f52013-03-16 15:55:53 -04005099 if (err == 0) {
Robert Milkowski7dc29932020-01-30 09:43:25 +00005100 nfs4_set_lease_period(server->nfs_client, fsinfo->lease_time * HZ);
Chuck Lever83ca7f52013-03-16 15:55:53 -04005101 break;
5102 }
5103 err = nfs4_handle_exception(server, err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005104 } while (exception.retry);
5105 return err;
5106}
5107
5108static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
5109{
Bryan Schumakere38eb652012-06-20 15:53:40 -04005110 int error;
5111
Trond Myklebust0e574af2005-10-27 22:12:38 -04005112 nfs_fattr_init(fsinfo->fattr);
Bryan Schumakere38eb652012-06-20 15:53:40 -04005113 error = nfs4_do_fsinfo(server, fhandle, fsinfo);
Peng Taodc182542012-08-24 00:27:49 +08005114 if (error == 0) {
5115 /* block layout checks this! */
5116 server->pnfs_blksize = fsinfo->blksize;
Jeff Laytonca440c32016-09-15 14:40:49 -04005117 set_pnfs_layoutdriver(server, fhandle, fsinfo);
Peng Taodc182542012-08-24 00:27:49 +08005118 }
Bryan Schumakere38eb652012-06-20 15:53:40 -04005119
5120 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121}
5122
5123static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
5124 struct nfs_pathconf *pathconf)
5125{
5126 struct nfs4_pathconf_arg args = {
5127 .fh = fhandle,
5128 .bitmask = server->attr_bitmask,
5129 };
Benny Halevyd45b2982009-04-01 09:21:58 -04005130 struct nfs4_pathconf_res res = {
5131 .pathconf = pathconf,
5132 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005133 struct rpc_message msg = {
5134 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF],
5135 .rpc_argp = &args,
Benny Halevyd45b2982009-04-01 09:21:58 -04005136 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005137 };
5138
5139 /* None of the pathconf attributes are mandatory to implement */
5140 if ((args.bitmask[0] & nfs4_pathconf_bitmap[0]) == 0) {
5141 memset(pathconf, 0, sizeof(*pathconf));
5142 return 0;
5143 }
5144
Trond Myklebust0e574af2005-10-27 22:12:38 -04005145 nfs_fattr_init(pathconf->fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00005146 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005147}
5148
5149static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
5150 struct nfs_pathconf *pathconf)
5151{
Trond Myklebust0688e642019-04-07 13:59:09 -04005152 struct nfs4_exception exception = {
5153 .interruptible = true,
5154 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005155 int err;
5156
5157 do {
5158 err = nfs4_handle_exception(server,
5159 _nfs4_proc_pathconf(server, fhandle, pathconf),
5160 &exception);
5161 } while (exception.retry);
5162 return err;
5163}
5164
Trond Myklebust5521abf2013-03-16 20:54:34 -04005165int nfs4_set_rw_stateid(nfs4_stateid *stateid,
Trond Myklebust9b206142013-03-17 15:52:00 -04005166 const struct nfs_open_context *ctx,
5167 const struct nfs_lock_context *l_ctx,
5168 fmode_t fmode)
5169{
NeilBrown17393472016-10-13 15:26:47 +11005170 return nfs4_select_rw_stateid(ctx->state, fmode, l_ctx, stateid, NULL);
Trond Myklebust9b206142013-03-17 15:52:00 -04005171}
5172EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid);
5173
Trond Myklebust5521abf2013-03-16 20:54:34 -04005174static bool nfs4_stateid_is_current(nfs4_stateid *stateid,
5175 const struct nfs_open_context *ctx,
5176 const struct nfs_lock_context *l_ctx,
5177 fmode_t fmode)
5178{
Ben Dooksd49dd112019-10-16 17:28:21 +01005179 nfs4_stateid _current_stateid;
Trond Myklebust5521abf2013-03-16 20:54:34 -04005180
Trond Myklebuste1253be2014-03-05 08:44:23 -05005181 /* If the current stateid represents a lost lock, then exit */
Ben Dooksd49dd112019-10-16 17:28:21 +01005182 if (nfs4_set_rw_stateid(&_current_stateid, ctx, l_ctx, fmode) == -EIO)
Trond Myklebuste1253be2014-03-05 08:44:23 -05005183 return true;
Ben Dooksd49dd112019-10-16 17:28:21 +01005184 return nfs4_stateid_match(stateid, &_current_stateid);
Trond Myklebust5521abf2013-03-16 20:54:34 -04005185}
5186
5187static bool nfs4_error_stateid_expired(int err)
5188{
5189 switch (err) {
5190 case -NFS4ERR_DELEG_REVOKED:
5191 case -NFS4ERR_ADMIN_REVOKED:
5192 case -NFS4ERR_BAD_STATEID:
5193 case -NFS4ERR_STALE_STATEID:
5194 case -NFS4ERR_OLD_STATEID:
5195 case -NFS4ERR_OPENMODE:
5196 case -NFS4ERR_EXPIRED:
5197 return true;
5198 }
5199 return false;
5200}
5201
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005202static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005203{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005204 struct nfs_server *server = NFS_SERVER(hdr->inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005205
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005206 trace_nfs4_read(hdr, task->tk_status);
Trond Myklebust9c278692016-09-22 13:39:11 -04005207 if (task->tk_status < 0) {
5208 struct nfs4_exception exception = {
5209 .inode = hdr->inode,
5210 .state = hdr->args.context->state,
5211 .stateid = &hdr->args.stateid,
5212 };
5213 task->tk_status = nfs4_async_handle_exception(task,
5214 server, task->tk_status, &exception);
5215 if (exception.retry) {
5216 rpc_restart_call_prepare(task);
5217 return -EAGAIN;
5218 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005219 }
Trond Myklebust8850df92007-09-28 17:20:07 -04005220
Linus Torvalds1da177e2005-04-16 15:20:36 -07005221 if (task->tk_status > 0)
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005222 renew_lease(server, hdr->timestamp);
Trond Myklebustec06c092006-03-20 13:44:27 -05005223 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005224}
5225
Trond Myklebust5521abf2013-03-16 20:54:34 -04005226static bool nfs4_read_stateid_changed(struct rpc_task *task,
Anna Schumaker3c6b8992014-05-06 09:12:24 -04005227 struct nfs_pgio_args *args)
Trond Myklebust5521abf2013-03-16 20:54:34 -04005228{
5229
5230 if (!nfs4_error_stateid_expired(task->tk_status) ||
5231 nfs4_stateid_is_current(&args->stateid,
5232 args->context,
5233 args->lock_context,
5234 FMODE_READ))
5235 return false;
5236 rpc_restart_call_prepare(task);
5237 return true;
5238}
5239
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005240static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
Andy Adamsoncbdabc72011-03-01 01:34:20 +00005241{
5242
5243 dprintk("--> %s\n", __func__);
5244
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005245 if (!nfs4_sequence_done(task, &hdr->res.seq_res))
Andy Adamsoncbdabc72011-03-01 01:34:20 +00005246 return -EAGAIN;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005247 if (nfs4_read_stateid_changed(task, &hdr->args))
Trond Myklebust5521abf2013-03-16 20:54:34 -04005248 return -EAGAIN;
Trond Myklebustbfc505d2016-09-15 18:26:05 -04005249 if (task->tk_status > 0)
5250 nfs_invalidate_atime(hdr->inode);
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005251 return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) :
5252 nfs4_read_done_cb(task, hdr);
Andy Adamsoncbdabc72011-03-01 01:34:20 +00005253}
5254
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005255static void nfs4_proc_read_setup(struct nfs_pgio_header *hdr,
5256 struct rpc_message *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005257{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005258 hdr->timestamp = jiffies;
Trond Myklebustca857cc2016-06-28 13:54:09 -04005259 if (!hdr->pgio_done_cb)
5260 hdr->pgio_done_cb = nfs4_read_done_cb;
Trond Myklebustbdc7f022007-07-14 15:40:00 -04005261 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
Anna Schumakerfba83f32018-05-04 16:22:50 -04005262 nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005263}
5264
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005265static int nfs4_proc_pgio_rpc_prepare(struct rpc_task *task,
5266 struct nfs_pgio_header *hdr)
Bryan Schumakerea7c3302012-03-19 14:54:40 -04005267{
Anna Schumaker42e1cca2017-01-09 15:48:22 -05005268 if (nfs4_setup_sequence(NFS_SERVER(hdr->inode)->nfs_client,
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005269 &hdr->args.seq_args,
5270 &hdr->res.seq_res,
Trond Myklebust9b206142013-03-17 15:52:00 -04005271 task))
NeilBrownef1820f2013-09-04 17:04:49 +10005272 return 0;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005273 if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context,
5274 hdr->args.lock_context,
Benjamin Coddingtonfbe77c32017-04-19 10:11:35 -04005275 hdr->rw_mode) == -EIO)
NeilBrownef1820f2013-09-04 17:04:49 +10005276 return -EIO;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005277 if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags)))
NeilBrownef1820f2013-09-04 17:04:49 +10005278 return -EIO;
5279 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280}
5281
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005282static int nfs4_write_done_cb(struct rpc_task *task,
5283 struct nfs_pgio_header *hdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005285 struct inode *inode = hdr->inode;
NeilBrown8478eaa2014-09-18 16:09:27 +10005286
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005287 trace_nfs4_write(hdr, task->tk_status);
Trond Myklebust9c278692016-09-22 13:39:11 -04005288 if (task->tk_status < 0) {
5289 struct nfs4_exception exception = {
5290 .inode = hdr->inode,
5291 .state = hdr->args.context->state,
5292 .stateid = &hdr->args.stateid,
5293 };
5294 task->tk_status = nfs4_async_handle_exception(task,
5295 NFS_SERVER(inode), task->tk_status,
5296 &exception);
5297 if (exception.retry) {
5298 rpc_restart_call_prepare(task);
5299 return -EAGAIN;
5300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005301 }
Trond Myklebust4f9838c2005-10-27 22:12:44 -04005302 if (task->tk_status >= 0) {
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005303 renew_lease(NFS_SERVER(inode), hdr->timestamp);
Trond Myklebusta08a8cd2015-02-26 17:36:09 -05005304 nfs_writeback_update_inode(hdr);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04005305 }
Trond Myklebust788e7a82006-03-20 13:44:27 -05005306 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005307}
5308
Trond Myklebust5521abf2013-03-16 20:54:34 -04005309static bool nfs4_write_stateid_changed(struct rpc_task *task,
Anna Schumaker3c6b8992014-05-06 09:12:24 -04005310 struct nfs_pgio_args *args)
Trond Myklebust5521abf2013-03-16 20:54:34 -04005311{
5312
5313 if (!nfs4_error_stateid_expired(task->tk_status) ||
5314 nfs4_stateid_is_current(&args->stateid,
5315 args->context,
5316 args->lock_context,
5317 FMODE_WRITE))
5318 return false;
5319 rpc_restart_call_prepare(task);
5320 return true;
5321}
5322
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005323static int nfs4_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
Fred Isamanb029bc92011-03-03 15:13:42 +00005324{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005325 if (!nfs4_sequence_done(task, &hdr->res.seq_res))
Fred Isamanb029bc92011-03-03 15:13:42 +00005326 return -EAGAIN;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005327 if (nfs4_write_stateid_changed(task, &hdr->args))
Trond Myklebust5521abf2013-03-16 20:54:34 -04005328 return -EAGAIN;
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005329 return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) :
5330 nfs4_write_done_cb(task, hdr);
Fred Isamanb029bc92011-03-03 15:13:42 +00005331}
5332
Trond Myklebust5a37f852012-04-28 14:55:16 -04005333static
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005334bool nfs4_write_need_cache_consistency_data(struct nfs_pgio_header *hdr)
Fred Isamana69aef12011-03-03 15:13:47 +00005335{
Trond Myklebust5a37f852012-04-28 14:55:16 -04005336 /* Don't request attributes for pNFS or O_DIRECT writes */
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005337 if (hdr->ds_clp != NULL || hdr->dreq != NULL)
Trond Myklebust5a37f852012-04-28 14:55:16 -04005338 return false;
5339 /* Otherwise, request attributes if and only if we don't hold
5340 * a delegation
5341 */
Bryan Schumaker011e2a72012-06-20 15:53:43 -04005342 return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0;
Fred Isamana69aef12011-03-03 15:13:47 +00005343}
Fred Isamana69aef12011-03-03 15:13:47 +00005344
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005345static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr,
Anna Schumakerfb91fb02018-05-04 16:22:48 -04005346 struct rpc_message *msg,
5347 struct rpc_clnt **clnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005348{
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005349 struct nfs_server *server = NFS_SERVER(hdr->inode);
Trond Myklebustbdc7f022007-07-14 15:40:00 -04005350
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005351 if (!nfs4_write_need_cache_consistency_data(hdr)) {
5352 hdr->args.bitmask = NULL;
5353 hdr->res.fattr = NULL;
Fred Isaman7ffd1062011-03-03 15:13:46 +00005354 } else
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005355 hdr->args.bitmask = server->cache_consistency_bitmask;
Trond Myklebust5a37f852012-04-28 14:55:16 -04005356
Weston Andros Adamsond45f60c2014-06-09 11:48:35 -04005357 if (!hdr->pgio_done_cb)
5358 hdr->pgio_done_cb = nfs4_write_done_cb;
5359 hdr->res.server = server;
5360 hdr->timestamp = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005361
Trond Myklebustbdc7f022007-07-14 15:40:00 -04005362 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
Olga Kornievskaiacd1b6592020-02-12 17:32:12 -05005363 nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0, 0);
Anna Schumakerfb91fb02018-05-04 16:22:48 -04005364 nfs4_state_protect_write(server->nfs_client, clnt, msg, hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005365}
5366
Fred Isaman0b7c0152012-04-20 14:47:39 -04005367static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
5368{
Anna Schumaker42e1cca2017-01-09 15:48:22 -05005369 nfs4_setup_sequence(NFS_SERVER(data->inode)->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04005370 &data->args.seq_args,
5371 &data->res.seq_res,
5372 task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005373}
5374
Fred Isaman0b7c0152012-04-20 14:47:39 -04005375static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005376{
Linus Torvalds1da177e2005-04-16 15:20:36 -07005377 struct inode *inode = data->inode;
Trond Myklebust14516c32010-07-31 14:29:06 -04005378
Trond Myklebustcc668ab2013-08-14 15:31:28 -04005379 trace_nfs4_commit(data, task->tk_status);
NeilBrown8478eaa2014-09-18 16:09:27 +10005380 if (nfs4_async_handle_error(task, NFS_SERVER(inode),
5381 NULL, NULL) == -EAGAIN) {
Trond Myklebustd00c5d42011-10-19 12:17:29 -07005382 rpc_restart_call_prepare(task);
Trond Myklebust788e7a82006-03-20 13:44:27 -05005383 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005384 }
Trond Myklebust788e7a82006-03-20 13:44:27 -05005385 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005386}
5387
Fred Isaman0b7c0152012-04-20 14:47:39 -04005388static int nfs4_commit_done(struct rpc_task *task, struct nfs_commit_data *data)
Fred Isaman5f452432011-03-23 13:27:46 +00005389{
5390 if (!nfs4_sequence_done(task, &data->res.seq_res))
5391 return -EAGAIN;
Fred Isaman0b7c0152012-04-20 14:47:39 -04005392 return data->commit_done_cb(task, data);
Fred Isaman5f452432011-03-23 13:27:46 +00005393}
5394
Anna Schumakere9ae1ee2018-05-04 16:22:49 -04005395static void nfs4_proc_commit_setup(struct nfs_commit_data *data, struct rpc_message *msg,
5396 struct rpc_clnt **clnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005397{
Trond Myklebust788e7a82006-03-20 13:44:27 -05005398 struct nfs_server *server = NFS_SERVER(data->inode);
Fred Isaman988b6dc2011-03-23 13:27:52 +00005399
Fred Isaman0b7c0152012-04-20 14:47:39 -04005400 if (data->commit_done_cb == NULL)
5401 data->commit_done_cb = nfs4_commit_done_cb;
Trond Myklebust4f9838c2005-10-27 22:12:44 -04005402 data->res.server = server;
Trond Myklebustbdc7f022007-07-14 15:40:00 -04005403 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
Anna Schumakerfba83f32018-05-04 16:22:50 -04005404 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1, 0);
Anna Schumakere9ae1ee2018-05-04 16:22:49 -04005405 nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_COMMIT, clnt, msg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406}
5407
Olga Kornievskaia6b8d84e2018-07-09 15:13:36 -04005408static int _nfs4_proc_commit(struct file *dst, struct nfs_commitargs *args,
5409 struct nfs_commitres *res)
5410{
5411 struct inode *dst_inode = file_inode(dst);
5412 struct nfs_server *server = NFS_SERVER(dst_inode);
5413 struct rpc_message msg = {
5414 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT],
5415 .rpc_argp = args,
5416 .rpc_resp = res,
5417 };
5418
5419 args->fh = NFS_FH(dst_inode);
5420 return nfs4_call_sync(server->client, server, &msg,
5421 &args->seq_args, &res->seq_res, 1);
5422}
5423
5424int nfs4_proc_commit(struct file *dst, __u64 offset, __u32 count, struct nfs_commitres *res)
5425{
5426 struct nfs_commitargs args = {
5427 .offset = offset,
5428 .count = count,
5429 };
5430 struct nfs_server *dst_server = NFS_SERVER(file_inode(dst));
5431 struct nfs4_exception exception = { };
5432 int status;
5433
5434 do {
5435 status = _nfs4_proc_commit(dst, &args, res);
5436 status = nfs4_handle_exception(dst_server, status, &exception);
5437 } while (exception.retry);
5438
5439 return status;
5440}
5441
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005442struct nfs4_renewdata {
5443 struct nfs_client *client;
5444 unsigned long timestamp;
5445};
5446
Linus Torvalds1da177e2005-04-16 15:20:36 -07005447/*
5448 * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special
5449 * standalone procedure for queueing an asynchronous RENEW.
5450 */
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005451static void nfs4_renew_release(void *calldata)
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08005452{
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005453 struct nfs4_renewdata *data = calldata;
5454 struct nfs_client *clp = data->client;
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08005455
Elena Reshetova212bf412017-10-20 12:53:38 +03005456 if (refcount_read(&clp->cl_count) > 1)
Alexandros Batsakis0851de062010-02-05 03:45:06 -08005457 nfs4_schedule_state_renewal(clp);
5458 nfs_put_client(clp);
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005459 kfree(data);
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08005460}
5461
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005462static void nfs4_renew_done(struct rpc_task *task, void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005463{
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005464 struct nfs4_renewdata *data = calldata;
5465 struct nfs_client *clp = data->client;
5466 unsigned long timestamp = data->timestamp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467
Trond Myklebustc6d01c62013-08-09 11:51:26 -04005468 trace_nfs4_renew_async(clp, task->tk_status);
Chuck Leverf8aba1e2013-10-17 14:13:53 -04005469 switch (task->tk_status) {
5470 case 0:
5471 break;
5472 case -NFS4ERR_LEASE_MOVED:
5473 nfs4_schedule_lease_moved_recovery(clp);
5474 break;
5475 default:
Trond Myklebust95baa252009-05-26 14:51:00 -04005476 /* Unless we're shutting down, schedule state recovery! */
Trond Myklebust042b60b2011-08-24 15:07:37 -04005477 if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0)
5478 return;
5479 if (task->tk_status != NFS4ERR_CB_PATH_DOWN) {
Trond Myklebust0400a6b2011-03-09 16:00:53 -05005480 nfs4_schedule_lease_recovery(clp);
Trond Myklebust042b60b2011-08-24 15:07:37 -04005481 return;
5482 }
5483 nfs4_schedule_path_down_recovery(clp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005484 }
Trond Myklebust452e9352010-07-31 14:29:06 -04005485 do_renew_lease(clp, timestamp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005486}
5487
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005488static const struct rpc_call_ops nfs4_renew_ops = {
5489 .rpc_call_done = nfs4_renew_done,
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08005490 .rpc_release = nfs4_renew_release,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005491};
5492
NeilBrowna52458b2018-12-03 11:30:31 +11005493static int nfs4_proc_async_renew(struct nfs_client *clp, const struct cred *cred, unsigned renew_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494{
5495 struct rpc_message msg = {
5496 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
5497 .rpc_argp = clp,
Trond Myklebustb4454fe2006-01-03 09:55:25 +01005498 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499 };
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005500 struct nfs4_renewdata *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501
Trond Myklebust2f60ea62011-08-24 15:07:37 -04005502 if (renew_flags == 0)
5503 return 0;
Elena Reshetova212bf412017-10-20 12:53:38 +03005504 if (!refcount_inc_not_zero(&clp->cl_count))
Alexandros Batsakis0851de062010-02-05 03:45:06 -08005505 return -EIO;
Trond Myklebustb569ad32011-08-24 15:07:35 -04005506 data = kmalloc(sizeof(*data), GFP_NOFS);
Dave Wysochanski5c737cb2017-04-27 10:45:15 -04005507 if (data == NULL) {
5508 nfs_put_client(clp);
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005509 return -ENOMEM;
Dave Wysochanski5c737cb2017-04-27 10:45:15 -04005510 }
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005511 data->client = clp;
5512 data->timestamp = jiffies;
Trond Myklebustbc7a05c2013-04-08 17:50:28 -04005513 return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT,
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04005514 &nfs4_renew_ops, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515}
5516
NeilBrowna52458b2018-12-03 11:30:31 +11005517static int nfs4_proc_renew(struct nfs_client *clp, const struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005518{
5519 struct rpc_message msg = {
5520 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
5521 .rpc_argp = clp,
Trond Myklebustb4454fe2006-01-03 09:55:25 +01005522 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523 };
5524 unsigned long now = jiffies;
5525 int status;
5526
Trond Myklebustbc7a05c2013-04-08 17:50:28 -04005527 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528 if (status < 0)
5529 return status;
Trond Myklebust452e9352010-07-31 14:29:06 -04005530 do_renew_lease(clp, now);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005531 return 0;
5532}
5533
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005534static inline int nfs4_server_supports_acls(struct nfs_server *server)
5535{
Malahal Naineni7dd7d952014-01-23 08:54:55 -06005536 return server->caps & NFS_CAP_ACLS;
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005537}
5538
Trond Myklebust21f498c2012-08-24 10:59:25 -04005539/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
5540 * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005541 * the stack.
5542 */
Trond Myklebust21f498c2012-08-24 10:59:25 -04005543#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005544
Frank van der Lindenccde1e92020-06-23 22:39:01 +00005545int nfs4_buf_to_pages_noslab(const void *buf, size_t buflen,
Andreas Gruenbacher8fbcf232015-11-03 18:25:34 +01005546 struct page **pages)
Neil Hormane9e3d722011-03-04 19:26:03 -05005547{
5548 struct page *newpage, **spages;
5549 int rc = 0;
5550 size_t len;
5551 spages = pages;
5552
5553 do {
Trond Myklebust21f498c2012-08-24 10:59:25 -04005554 len = min_t(size_t, PAGE_SIZE, buflen);
Neil Hormane9e3d722011-03-04 19:26:03 -05005555 newpage = alloc_page(GFP_KERNEL);
5556
5557 if (newpage == NULL)
5558 goto unwind;
5559 memcpy(page_address(newpage), buf, len);
Anna Schumakerd9b67e12017-01-11 15:04:25 -05005560 buf += len;
5561 buflen -= len;
Neil Hormane9e3d722011-03-04 19:26:03 -05005562 *pages++ = newpage;
5563 rc++;
5564 } while (buflen != 0);
5565
5566 return rc;
5567
5568unwind:
5569 for(; rc > 0; rc--)
5570 __free_page(spages[rc-1]);
5571 return -ENOMEM;
5572}
5573
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005574struct nfs4_cached_acl {
5575 int cached;
5576 size_t len;
Gustavo A. R. Silva5601cda2020-03-09 13:24:42 -05005577 char data[];
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005578};
5579
5580static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl)
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005581{
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005582 struct nfs_inode *nfsi = NFS_I(inode);
5583
5584 spin_lock(&inode->i_lock);
5585 kfree(nfsi->nfs4_acl);
5586 nfsi->nfs4_acl = acl;
5587 spin_unlock(&inode->i_lock);
5588}
5589
5590static void nfs4_zap_acl_attr(struct inode *inode)
5591{
5592 nfs4_set_cached_acl(inode, NULL);
5593}
5594
5595static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen)
5596{
5597 struct nfs_inode *nfsi = NFS_I(inode);
5598 struct nfs4_cached_acl *acl;
5599 int ret = -ENOENT;
5600
5601 spin_lock(&inode->i_lock);
5602 acl = nfsi->nfs4_acl;
5603 if (acl == NULL)
5604 goto out;
5605 if (buf == NULL) /* user is just asking for length */
5606 goto out_len;
5607 if (acl->cached == 0)
5608 goto out;
5609 ret = -ERANGE; /* see getxattr(2) man page */
5610 if (acl->len > buflen)
5611 goto out;
5612 memcpy(buf, acl->data, acl->len);
5613out_len:
5614 ret = acl->len;
5615out:
5616 spin_unlock(&inode->i_lock);
5617 return ret;
5618}
5619
Sachin Prabhu5794d212012-04-17 14:36:40 +01005620static 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 +00005621{
5622 struct nfs4_cached_acl *acl;
Trond Myklebustb291f1b2012-08-14 18:30:41 -04005623 size_t buflen = sizeof(*acl) + acl_len;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005624
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005625 if (buflen <= PAGE_SIZE) {
Trond Myklebustb291f1b2012-08-14 18:30:41 -04005626 acl = kmalloc(buflen, GFP_KERNEL);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005627 if (acl == NULL)
5628 goto out;
5629 acl->cached = 1;
Sachin Prabhu5794d212012-04-17 14:36:40 +01005630 _copy_from_pages(acl->data, pages, pgbase, acl_len);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005631 } else {
5632 acl = kmalloc(sizeof(*acl), GFP_KERNEL);
5633 if (acl == NULL)
5634 goto out;
5635 acl->cached = 0;
5636 }
5637 acl->len = acl_len;
5638out:
5639 nfs4_set_cached_acl(inode, acl);
5640}
5641
Andy Adamsonbf118a32011-12-07 11:55:27 -05005642/*
5643 * The getxattr API returns the required buffer length when called with a
5644 * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating
5645 * the required buf. On a NULL buf, we send a page of data to the server
5646 * guessing that the ACL request can be serviced by a page. If so, we cache
5647 * up to the page of ACL data, and the 2nd call to getxattr is serviced by
5648 * the cache. If not so, we throw away the page, and cache the required
5649 * length. The next getxattr call will then produce another round trip to
5650 * the server, this time with the input buf of the required size.
5651 */
Trond Myklebust16b42892006-08-24 12:27:15 -04005652static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005653{
Olga Kornievskaia62a15732020-01-02 17:09:54 -05005654 struct page **pages;
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005655 struct nfs_getaclargs args = {
5656 .fh = NFS_FH(inode),
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005657 .acl_len = buflen,
5658 };
Benny Halevy663c79b2009-04-01 09:21:59 -04005659 struct nfs_getaclres res = {
5660 .acl_len = buflen,
5661 };
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005662 struct rpc_message msg = {
5663 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],
5664 .rpc_argp = &args,
Benny Halevy663c79b2009-04-01 09:21:59 -04005665 .rpc_resp = &res,
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005666 };
Olga Kornievskaia62a15732020-01-02 17:09:54 -05005667 unsigned int npages;
Trond Myklebust21f498c2012-08-24 10:59:25 -04005668 int ret = -ENOMEM, i;
Olga Kornievskaia62a15732020-01-02 17:09:54 -05005669 struct nfs_server *server = NFS_SERVER(inode);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005670
Olga Kornievskaia62a15732020-01-02 17:09:54 -05005671 if (buflen == 0)
5672 buflen = server->rsize;
5673
5674 npages = DIV_ROUND_UP(buflen, PAGE_SIZE) + 1;
5675 pages = kmalloc_array(npages, sizeof(struct page *), GFP_NOFS);
5676 if (!pages)
5677 return -ENOMEM;
5678
5679 args.acl_pages = pages;
Sachin Prabhu5a006892012-04-17 14:35:39 +01005680
Andy Adamsonbf118a32011-12-07 11:55:27 -05005681 for (i = 0; i < npages; i++) {
5682 pages[i] = alloc_page(GFP_KERNEL);
5683 if (!pages[i])
5684 goto out_free;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005685 }
Sachin Prabhu5a006892012-04-17 14:35:39 +01005686
5687 /* for decoding across pages */
5688 res.acl_scratch = alloc_page(GFP_KERNEL);
5689 if (!res.acl_scratch)
5690 goto out_free;
5691
Andy Adamsonbf118a32011-12-07 11:55:27 -05005692 args.acl_len = npages * PAGE_SIZE;
Sachin Prabhu5a006892012-04-17 14:35:39 +01005693
Peng Taode040be2012-01-10 22:42:47 +08005694 dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n",
Andy Adamsonbf118a32011-12-07 11:55:27 -05005695 __func__, buf, buflen, npages, args.acl_len);
5696 ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
5697 &msg, &args.seq_args, &res.seq_res, 0);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005698 if (ret)
5699 goto out_free;
Andy Adamsonbf118a32011-12-07 11:55:27 -05005700
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005701 /* Handle the case where the passed-in buffer is too short */
5702 if (res.acl_flags & NFS4_ACL_TRUNC) {
5703 /* Did the user only issue a request for the acl length? */
5704 if (buf == NULL)
5705 goto out_ok;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005706 ret = -ERANGE;
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005707 goto out_free;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005708 }
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005709 nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len);
Sven Wegener7d3e91a2012-12-08 15:30:18 +01005710 if (buf) {
5711 if (res.acl_len > buflen) {
5712 ret = -ERANGE;
5713 goto out_free;
5714 }
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005715 _copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len);
Sven Wegener7d3e91a2012-12-08 15:30:18 +01005716 }
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07005717out_ok:
5718 ret = res.acl_len;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005719out_free:
Andy Adamsonbf118a32011-12-07 11:55:27 -05005720 for (i = 0; i < npages; i++)
5721 if (pages[i])
5722 __free_page(pages[i]);
Trond Myklebust331818f2012-02-03 18:30:53 -05005723 if (res.acl_scratch)
5724 __free_page(res.acl_scratch);
Olga Kornievskaia62a15732020-01-02 17:09:54 -05005725 kfree(pages);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005726 return ret;
5727}
5728
Trond Myklebust16b42892006-08-24 12:27:15 -04005729static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
5730{
Trond Myklebust0688e642019-04-07 13:59:09 -04005731 struct nfs4_exception exception = {
5732 .interruptible = true,
5733 };
Trond Myklebust16b42892006-08-24 12:27:15 -04005734 ssize_t ret;
5735 do {
5736 ret = __nfs4_get_acl_uncached(inode, buf, buflen);
Trond Myklebustc1578b72013-08-12 16:58:42 -04005737 trace_nfs4_get_acl(inode, ret);
Trond Myklebust16b42892006-08-24 12:27:15 -04005738 if (ret >= 0)
5739 break;
5740 ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
5741 } while (exception.retry);
5742 return ret;
5743}
5744
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005745static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
5746{
5747 struct nfs_server *server = NFS_SERVER(inode);
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005748 int ret;
5749
5750 if (!nfs4_server_supports_acls(server))
5751 return -EOPNOTSUPP;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005752 ret = nfs_revalidate_inode(server, inode);
5753 if (ret < 0)
5754 return ret;
Aneesh Kumar K.V08a22b32010-12-01 10:42:16 +00005755 if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
5756 nfs_zap_acl_cache(inode);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005757 ret = nfs4_read_cached_acl(inode, buf, buflen);
5758 if (ret != -ENOENT)
Andy Adamsonbf118a32011-12-07 11:55:27 -05005759 /* -ENOENT is returned if there is no ACL or if there is an ACL
5760 * but no cached acl data, just the acl length */
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00005761 return ret;
5762 return nfs4_get_acl_uncached(inode, buf, buflen);
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005763}
5764
Trond Myklebust16b42892006-08-24 12:27:15 -04005765static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005766{
5767 struct nfs_server *server = NFS_SERVER(inode);
5768 struct page *pages[NFS4ACL_MAXPAGES];
5769 struct nfs_setaclargs arg = {
5770 .fh = NFS_FH(inode),
5771 .acl_pages = pages,
5772 .acl_len = buflen,
5773 };
Benny Halevy73c403a2009-04-01 09:22:01 -04005774 struct nfs_setaclres res;
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005775 struct rpc_message msg = {
5776 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL],
5777 .rpc_argp = &arg,
Benny Halevy73c403a2009-04-01 09:22:01 -04005778 .rpc_resp = &res,
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005779 };
Trond Myklebust21f498c2012-08-24 10:59:25 -04005780 unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
Neil Hormane9e3d722011-03-04 19:26:03 -05005781 int ret, i;
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005782
5783 if (!nfs4_server_supports_acls(server))
5784 return -EOPNOTSUPP;
Trond Myklebust21f498c2012-08-24 10:59:25 -04005785 if (npages > ARRAY_SIZE(pages))
5786 return -ERANGE;
Frank van der Lindenccde1e92020-06-23 22:39:01 +00005787 i = nfs4_buf_to_pages_noslab(buf, buflen, arg.acl_pages);
Neil Hormane9e3d722011-03-04 19:26:03 -05005788 if (i < 0)
5789 return i;
Trond Myklebustc01d3642018-03-20 16:43:20 -04005790 nfs4_inode_make_writeable(inode);
Bryan Schumaker7c513052011-03-24 17:12:24 +00005791 ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Neil Hormane9e3d722011-03-04 19:26:03 -05005792
5793 /*
5794 * Free each page after tx, so the only ref left is
5795 * held by the network stack
5796 */
5797 for (; i > 0; i--)
5798 put_page(pages[i-1]);
5799
Aneesh Kumar K.V08a22b32010-12-01 10:42:16 +00005800 /*
5801 * Acl update can result in inode attribute update.
5802 * so mark the attribute cache invalid.
5803 */
5804 spin_lock(&inode->i_lock);
Trond Myklebust16e14372018-03-20 16:53:31 -04005805 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_CHANGE
Trond Myklebust472f7612018-04-08 18:14:43 -04005806 | NFS_INO_INVALID_CTIME
5807 | NFS_INO_REVAL_FORCED;
Aneesh Kumar K.V08a22b32010-12-01 10:42:16 +00005808 spin_unlock(&inode->i_lock);
Trond Myklebustf41f7412008-06-11 17:39:04 -04005809 nfs_access_zap_cache(inode);
5810 nfs_zap_acl_cache(inode);
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005811 return ret;
5812}
5813
Trond Myklebust16b42892006-08-24 12:27:15 -04005814static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
5815{
5816 struct nfs4_exception exception = { };
5817 int err;
5818 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04005819 err = __nfs4_proc_set_acl(inode, buf, buflen);
5820 trace_nfs4_set_acl(inode, err);
5821 err = nfs4_handle_exception(NFS_SERVER(inode), err,
Trond Myklebust16b42892006-08-24 12:27:15 -04005822 &exception);
5823 } while (exception.retry);
5824 return err;
5825}
5826
David Quigleyaa9c2662013-05-22 12:50:44 -04005827#ifdef CONFIG_NFS_V4_SECURITY_LABEL
5828static int _nfs4_get_security_label(struct inode *inode, void *buf,
5829 size_t buflen)
5830{
5831 struct nfs_server *server = NFS_SERVER(inode);
5832 struct nfs_fattr fattr;
5833 struct nfs4_label label = {0, 0, buflen, buf};
5834
5835 u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
Trond Myklebustfcb63a92013-11-01 12:42:25 -04005836 struct nfs4_getattr_arg arg = {
David Quigleyaa9c2662013-05-22 12:50:44 -04005837 .fh = NFS_FH(inode),
5838 .bitmask = bitmask,
5839 };
5840 struct nfs4_getattr_res res = {
5841 .fattr = &fattr,
5842 .label = &label,
5843 .server = server,
5844 };
5845 struct rpc_message msg = {
5846 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
Trond Myklebustfcb63a92013-11-01 12:42:25 -04005847 .rpc_argp = &arg,
David Quigleyaa9c2662013-05-22 12:50:44 -04005848 .rpc_resp = &res,
5849 };
5850 int ret;
5851
5852 nfs_fattr_init(&fattr);
5853
Trond Myklebustfcb63a92013-11-01 12:42:25 -04005854 ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 0);
David Quigleyaa9c2662013-05-22 12:50:44 -04005855 if (ret)
5856 return ret;
5857 if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))
5858 return -ENOENT;
5859 if (buflen < label.len)
5860 return -ERANGE;
5861 return 0;
5862}
5863
5864static int nfs4_get_security_label(struct inode *inode, void *buf,
5865 size_t buflen)
5866{
Trond Myklebust0688e642019-04-07 13:59:09 -04005867 struct nfs4_exception exception = {
5868 .interruptible = true,
5869 };
David Quigleyaa9c2662013-05-22 12:50:44 -04005870 int err;
5871
5872 if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
5873 return -EOPNOTSUPP;
5874
5875 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04005876 err = _nfs4_get_security_label(inode, buf, buflen);
5877 trace_nfs4_get_security_label(inode, err);
5878 err = nfs4_handle_exception(NFS_SERVER(inode), err,
David Quigleyaa9c2662013-05-22 12:50:44 -04005879 &exception);
5880 } while (exception.retry);
5881 return err;
5882}
5883
5884static int _nfs4_do_set_security_label(struct inode *inode,
5885 struct nfs4_label *ilabel,
5886 struct nfs_fattr *fattr,
5887 struct nfs4_label *olabel)
5888{
5889
5890 struct iattr sattr = {0};
5891 struct nfs_server *server = NFS_SERVER(inode);
5892 const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
Jeff Layton12207f62013-11-01 10:49:32 -04005893 struct nfs_setattrargs arg = {
Anna Schumakerd9b67e12017-01-11 15:04:25 -05005894 .fh = NFS_FH(inode),
5895 .iap = &sattr,
David Quigleyaa9c2662013-05-22 12:50:44 -04005896 .server = server,
5897 .bitmask = bitmask,
5898 .label = ilabel,
5899 };
5900 struct nfs_setattrres res = {
5901 .fattr = fattr,
5902 .label = olabel,
5903 .server = server,
5904 };
5905 struct rpc_message msg = {
Anna Schumakerd9b67e12017-01-11 15:04:25 -05005906 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
5907 .rpc_argp = &arg,
5908 .rpc_resp = &res,
David Quigleyaa9c2662013-05-22 12:50:44 -04005909 };
5910 int status;
5911
Jeff Layton12207f62013-11-01 10:49:32 -04005912 nfs4_stateid_copy(&arg.stateid, &zero_stateid);
David Quigleyaa9c2662013-05-22 12:50:44 -04005913
Jeff Layton12207f62013-11-01 10:49:32 -04005914 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
David Quigleyaa9c2662013-05-22 12:50:44 -04005915 if (status)
5916 dprintk("%s failed: %d\n", __func__, status);
5917
5918 return status;
5919}
5920
5921static int nfs4_do_set_security_label(struct inode *inode,
5922 struct nfs4_label *ilabel,
5923 struct nfs_fattr *fattr,
5924 struct nfs4_label *olabel)
5925{
5926 struct nfs4_exception exception = { };
5927 int err;
5928
5929 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04005930 err = _nfs4_do_set_security_label(inode, ilabel,
5931 fattr, olabel);
5932 trace_nfs4_set_security_label(inode, err);
5933 err = nfs4_handle_exception(NFS_SERVER(inode), err,
David Quigleyaa9c2662013-05-22 12:50:44 -04005934 &exception);
5935 } while (exception.retry);
5936 return err;
5937}
5938
5939static int
Al Viro59301222016-05-27 10:19:30 -04005940nfs4_set_security_label(struct inode *inode, const void *buf, size_t buflen)
David Quigleyaa9c2662013-05-22 12:50:44 -04005941{
5942 struct nfs4_label ilabel, *olabel = NULL;
5943 struct nfs_fattr fattr;
David Quigleyaa9c2662013-05-22 12:50:44 -04005944 int status;
5945
5946 if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
5947 return -EOPNOTSUPP;
5948
5949 nfs_fattr_init(&fattr);
5950
5951 ilabel.pi = 0;
5952 ilabel.lfs = 0;
5953 ilabel.label = (char *)buf;
5954 ilabel.len = buflen;
5955
David Quigleyaa9c2662013-05-22 12:50:44 -04005956 olabel = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
5957 if (IS_ERR(olabel)) {
5958 status = -PTR_ERR(olabel);
5959 goto out;
5960 }
5961
5962 status = nfs4_do_set_security_label(inode, &ilabel, &fattr, olabel);
5963 if (status == 0)
5964 nfs_setsecurity(inode, &fattr, olabel);
5965
5966 nfs4_label_free(olabel);
5967out:
David Quigleyaa9c2662013-05-22 12:50:44 -04005968 return status;
5969}
5970#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
5971
5972
Chuck Leverf0920752012-05-21 22:45:41 -04005973static void nfs4_init_boot_verifier(const struct nfs_client *clp,
5974 nfs4_verifier *bootverf)
Chuck Levercd937102012-03-02 17:14:31 -05005975{
5976 __be32 verf[2];
5977
Chuck Lever2c820d92012-05-21 22:45:33 -04005978 if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
5979 /* An impossible timestamp guarantees this value
5980 * will never match a generated boot time. */
Deepa Dinamani2f86e092016-10-01 16:46:26 -07005981 verf[0] = cpu_to_be32(U32_MAX);
5982 verf[1] = cpu_to_be32(U32_MAX);
Chuck Lever2c820d92012-05-21 22:45:33 -04005983 } else {
Chuck Leverf0920752012-05-21 22:45:41 -04005984 struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
Deepa Dinamani2f86e092016-10-01 16:46:26 -07005985 u64 ns = ktime_to_ns(nn->boot_time);
5986
5987 verf[0] = cpu_to_be32(ns >> 32);
5988 verf[1] = cpu_to_be32(ns);
Chuck Lever2c820d92012-05-21 22:45:33 -04005989 }
Chuck Levercd937102012-03-02 17:14:31 -05005990 memcpy(bootverf->data, verf, sizeof(bootverf->data));
5991}
5992
Jeff Laytona3192682015-06-09 19:43:59 -04005993static int
5994nfs4_init_nonuniform_client_string(struct nfs_client *clp)
Chuck Levere984a552012-09-14 17:24:21 -04005995{
Jeff Laytona3192682015-06-09 19:43:59 -04005996 size_t len;
5997 char *str;
Chuck Levere984a552012-09-14 17:24:21 -04005998
Trond Myklebustceb3a162015-01-03 15:16:04 -05005999 if (clp->cl_owner_id != NULL)
Jeff Laytona3192682015-06-09 19:43:59 -04006000 return 0;
Kinglong Mee4a3e5772015-08-31 10:53:43 +08006001
Jeff Laytona3192682015-06-09 19:43:59 -04006002 rcu_read_lock();
Chuck Lever848a4eb2018-06-04 10:53:29 -04006003 len = 14 +
6004 strlen(clp->cl_rpcclient->cl_nodename) +
6005 1 +
Jeff Laytona3192682015-06-09 19:43:59 -04006006 strlen(rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)) +
Jeff Laytona3192682015-06-09 19:43:59 -04006007 1;
6008 rcu_read_unlock();
Chuck Lever848a4eb2018-06-04 10:53:29 -04006009 if (nfs4_client_id_uniquifier[0] != '\0')
6010 len += strlen(nfs4_client_id_uniquifier) + 1;
Jeff Laytona3192682015-06-09 19:43:59 -04006011 if (len > NFS4_OPAQUE_LIMIT + 1)
6012 return -EINVAL;
6013
6014 /*
6015 * Since this string is allocated at mount time, and held until the
6016 * nfs_client is destroyed, we can use GFP_KERNEL here w/o worrying
6017 * about a memory-reclaim deadlock.
6018 */
6019 str = kmalloc(len, GFP_KERNEL);
6020 if (!str)
6021 return -ENOMEM;
Trond Myklebustceb3a162015-01-03 15:16:04 -05006022
Chuck Levere984a552012-09-14 17:24:21 -04006023 rcu_read_lock();
Chuck Lever848a4eb2018-06-04 10:53:29 -04006024 if (nfs4_client_id_uniquifier[0] != '\0')
Chuck Lever025bb9f2018-06-04 10:53:34 -04006025 scnprintf(str, len, "Linux NFSv4.0 %s/%s/%s",
Chuck Lever848a4eb2018-06-04 10:53:29 -04006026 clp->cl_rpcclient->cl_nodename,
6027 nfs4_client_id_uniquifier,
6028 rpc_peeraddr2str(clp->cl_rpcclient,
Chuck Lever025bb9f2018-06-04 10:53:34 -04006029 RPC_DISPLAY_ADDR));
Chuck Lever848a4eb2018-06-04 10:53:29 -04006030 else
Chuck Lever025bb9f2018-06-04 10:53:34 -04006031 scnprintf(str, len, "Linux NFSv4.0 %s/%s",
Chuck Lever848a4eb2018-06-04 10:53:29 -04006032 clp->cl_rpcclient->cl_nodename,
6033 rpc_peeraddr2str(clp->cl_rpcclient,
Chuck Lever025bb9f2018-06-04 10:53:34 -04006034 RPC_DISPLAY_ADDR));
Chuck Levere984a552012-09-14 17:24:21 -04006035 rcu_read_unlock();
Jeff Laytona3192682015-06-09 19:43:59 -04006036
Jeff Laytona3192682015-06-09 19:43:59 -04006037 clp->cl_owner_id = str;
6038 return 0;
Chuck Levere984a552012-09-14 17:24:21 -04006039}
6040
Jeff Layton873e3852015-06-09 19:44:00 -04006041static int
6042nfs4_init_uniquifier_client_string(struct nfs_client *clp)
Chuck Levere984a552012-09-14 17:24:21 -04006043{
Jeff Layton873e3852015-06-09 19:44:00 -04006044 size_t len;
6045 char *str;
6046
6047 len = 10 + 10 + 1 + 10 + 1 +
6048 strlen(nfs4_client_id_uniquifier) + 1 +
6049 strlen(clp->cl_rpcclient->cl_nodename) + 1;
6050
6051 if (len > NFS4_OPAQUE_LIMIT + 1)
6052 return -EINVAL;
6053
6054 /*
6055 * Since this string is allocated at mount time, and held until the
6056 * nfs_client is destroyed, we can use GFP_KERNEL here w/o worrying
6057 * about a memory-reclaim deadlock.
6058 */
6059 str = kmalloc(len, GFP_KERNEL);
6060 if (!str)
6061 return -ENOMEM;
6062
Trond Myklebustf2dd4362015-10-08 11:33:17 -04006063 scnprintf(str, len, "Linux NFSv%u.%u %s/%s",
Jeff Layton873e3852015-06-09 19:44:00 -04006064 clp->rpc_ops->version, clp->cl_minorversion,
6065 nfs4_client_id_uniquifier,
6066 clp->cl_rpcclient->cl_nodename);
Jeff Layton873e3852015-06-09 19:44:00 -04006067 clp->cl_owner_id = str;
6068 return 0;
6069}
6070
6071static int
6072nfs4_init_uniform_client_string(struct nfs_client *clp)
6073{
Jeff Layton873e3852015-06-09 19:44:00 -04006074 size_t len;
6075 char *str;
Trond Myklebustceb3a162015-01-03 15:16:04 -05006076
6077 if (clp->cl_owner_id != NULL)
Jeff Layton873e3852015-06-09 19:44:00 -04006078 return 0;
Chuck Lever6f2ea7f2012-09-14 17:24:41 -04006079
6080 if (nfs4_client_id_uniquifier[0] != '\0')
Jeff Layton873e3852015-06-09 19:44:00 -04006081 return nfs4_init_uniquifier_client_string(clp);
6082
6083 len = 10 + 10 + 1 + 10 + 1 +
6084 strlen(clp->cl_rpcclient->cl_nodename) + 1;
6085
6086 if (len > NFS4_OPAQUE_LIMIT + 1)
6087 return -EINVAL;
6088
6089 /*
6090 * Since this string is allocated at mount time, and held until the
6091 * nfs_client is destroyed, we can use GFP_KERNEL here w/o worrying
6092 * about a memory-reclaim deadlock.
6093 */
6094 str = kmalloc(len, GFP_KERNEL);
6095 if (!str)
6096 return -ENOMEM;
6097
Trond Myklebustf2dd4362015-10-08 11:33:17 -04006098 scnprintf(str, len, "Linux NFSv%u.%u %s",
Jeff Layton873e3852015-06-09 19:44:00 -04006099 clp->rpc_ops->version, clp->cl_minorversion,
6100 clp->cl_rpcclient->cl_nodename);
Jeff Layton873e3852015-06-09 19:44:00 -04006101 clp->cl_owner_id = str;
6102 return 0;
Chuck Levere984a552012-09-14 17:24:21 -04006103}
6104
Chuck Lever706cb8d2014-03-12 12:51:47 -04006105/*
6106 * nfs4_callback_up_net() starts only "tcp" and "tcp6" callback
6107 * services. Advertise one based on the address family of the
6108 * clientaddr.
6109 */
6110static unsigned int
6111nfs4_init_callback_netid(const struct nfs_client *clp, char *buf, size_t len)
6112{
6113 if (strchr(clp->cl_ipaddr, ':') != NULL)
6114 return scnprintf(buf, len, "tcp6");
6115 else
6116 return scnprintf(buf, len, "tcp");
6117}
6118
Jeff Laytonf11b2a12014-06-21 20:52:17 -04006119static void nfs4_setclientid_done(struct rpc_task *task, void *calldata)
6120{
6121 struct nfs4_setclientid *sc = calldata;
6122
6123 if (task->tk_status == 0)
6124 sc->sc_cred = get_rpccred(task->tk_rqstp->rq_cred);
6125}
6126
6127static const struct rpc_call_ops nfs4_setclientid_ops = {
6128 .rpc_call_done = nfs4_setclientid_done,
6129};
6130
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006131/**
6132 * nfs4_proc_setclientid - Negotiate client ID
6133 * @clp: state data structure
6134 * @program: RPC program for NFSv4 callback service
6135 * @port: IP port number for NFS4 callback service
NeilBrowna52458b2018-12-03 11:30:31 +11006136 * @cred: credential to use for this call
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006137 * @res: where to place the result
6138 *
6139 * Returns zero, a negative errno, or a negative NFS4ERR status code.
6140 */
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04006141int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
NeilBrowna52458b2018-12-03 11:30:31 +11006142 unsigned short port, const struct cred *cred,
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04006143 struct nfs4_setclientid_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006144{
6145 nfs4_verifier sc_verifier;
6146 struct nfs4_setclientid setclientid = {
6147 .sc_verifier = &sc_verifier,
6148 .sc_prog = program,
Jeff Layton3a6bb732015-06-09 19:43:57 -04006149 .sc_clnt = clp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006150 };
6151 struct rpc_message msg = {
6152 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
6153 .rpc_argp = &setclientid,
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04006154 .rpc_resp = res,
Trond Myklebust286d7d62006-01-03 09:55:26 +01006155 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006156 };
Jeff Laytonf11b2a12014-06-21 20:52:17 -04006157 struct rpc_task_setup task_setup_data = {
6158 .rpc_client = clp->cl_rpcclient,
6159 .rpc_message = &msg,
6160 .callback_ops = &nfs4_setclientid_ops,
6161 .callback_data = &setclientid,
NeilBrown5a0c2572019-05-30 10:41:28 +10006162 .flags = RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN,
Jeff Laytonf11b2a12014-06-21 20:52:17 -04006163 };
Robert Milkowski7dc29932020-01-30 09:43:25 +00006164 unsigned long now = jiffies;
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006165 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006166
Chuck Leverde734832012-07-11 16:30:50 -04006167 /* nfs_client_id4 */
Chuck Leverf0920752012-05-21 22:45:41 -04006168 nfs4_init_boot_verifier(clp, &sc_verifier);
Jeff Layton873e3852015-06-09 19:44:00 -04006169
6170 if (test_bit(NFS_CS_MIGRATION, &clp->cl_flags))
6171 status = nfs4_init_uniform_client_string(clp);
6172 else
Jeff Laytona3192682015-06-09 19:43:59 -04006173 status = nfs4_init_nonuniform_client_string(clp);
Jeff Layton873e3852015-06-09 19:44:00 -04006174
6175 if (status)
6176 goto out;
Jeff Layton3a6bb732015-06-09 19:43:57 -04006177
Chuck Leverde734832012-07-11 16:30:50 -04006178 /* cb_client4 */
Chuck Lever706cb8d2014-03-12 12:51:47 -04006179 setclientid.sc_netid_len =
6180 nfs4_init_callback_netid(clp,
6181 setclientid.sc_netid,
6182 sizeof(setclientid.sc_netid));
Chuck Leverde734832012-07-11 16:30:50 -04006183 setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
Chuck Leverd4d3c502007-12-10 14:57:09 -05006184 sizeof(setclientid.sc_uaddr), "%s.%u.%u",
Linus Torvalds1da177e2005-04-16 15:20:36 -07006185 clp->cl_ipaddr, port >> 8, port & 255);
6186
Jeff Layton3a6bb732015-06-09 19:43:57 -04006187 dprintk("NFS call setclientid auth=%s, '%s'\n",
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006188 clp->cl_rpcclient->cl_auth->au_ops->au_name,
Jeff Layton3a6bb732015-06-09 19:43:57 -04006189 clp->cl_owner_id);
Anna Schumakerdae40962019-08-14 15:28:28 -04006190
6191 status = nfs4_call_sync_custom(&task_setup_data);
Jeff Laytonf11b2a12014-06-21 20:52:17 -04006192 if (setclientid.sc_cred) {
Chuck Lever1047ec82019-10-04 09:58:54 -04006193 kfree(clp->cl_acceptor);
Jeff Laytonf11b2a12014-06-21 20:52:17 -04006194 clp->cl_acceptor = rpcauth_stringify_acceptor(setclientid.sc_cred);
6195 put_rpccred(setclientid.sc_cred);
6196 }
Robert Milkowski7dc29932020-01-30 09:43:25 +00006197
6198 if (status == 0)
6199 do_renew_lease(clp, now);
Jeff Laytonf11b2a12014-06-21 20:52:17 -04006200out:
Trond Myklebustc6d01c62013-08-09 11:51:26 -04006201 trace_nfs4_setclientid(clp, status);
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006202 dprintk("NFS reply setclientid: %d\n", status);
6203 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006204}
6205
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006206/**
6207 * nfs4_proc_setclientid_confirm - Confirm client ID
6208 * @clp: state data structure
Trond Myklebust302fad72019-02-18 13:32:38 -05006209 * @arg: result of a previous SETCLIENTID
NeilBrowna52458b2018-12-03 11:30:31 +11006210 * @cred: credential to use for this call
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006211 *
6212 * Returns zero, a negative errno, or a negative NFS4ERR status code.
6213 */
Trond Myklebustfd954ae2011-04-24 14:28:18 -04006214int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04006215 struct nfs4_setclientid_res *arg,
NeilBrowna52458b2018-12-03 11:30:31 +11006216 const struct cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006217{
Linus Torvalds1da177e2005-04-16 15:20:36 -07006218 struct rpc_message msg = {
6219 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04006220 .rpc_argp = arg,
Trond Myklebust286d7d62006-01-03 09:55:26 +01006221 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006222 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006223 int status;
6224
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006225 dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n",
6226 clp->cl_rpcclient->cl_auth->au_ops->au_name,
6227 clp->cl_clientid);
NeilBrown5a0c2572019-05-30 10:41:28 +10006228 status = rpc_call_sync(clp->cl_rpcclient, &msg,
6229 RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04006230 trace_nfs4_setclientid_confirm(clp, status);
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006231 dprintk("NFS reply setclientid_confirm: %d\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006232 return status;
6233}
6234
Trond Myklebustfe650402006-01-03 09:55:18 +01006235struct nfs4_delegreturndata {
6236 struct nfs4_delegreturnargs args;
Trond Myklebustfa178f22006-01-03 09:55:38 +01006237 struct nfs4_delegreturnres res;
Trond Myklebustfe650402006-01-03 09:55:18 +01006238 struct nfs_fh fh;
6239 nfs4_stateid stateid;
Trond Myklebust26e976a2006-01-03 09:55:21 +01006240 unsigned long timestamp;
Trond Myklebust586f1c32016-11-15 15:03:33 -05006241 struct {
6242 struct nfs4_layoutreturn_args arg;
6243 struct nfs4_layoutreturn_res res;
Trond Myklebust4d796d72016-09-23 11:38:08 -04006244 struct nfs4_xdr_opaque_data ld_private;
Trond Myklebust586f1c32016-11-15 15:03:33 -05006245 u32 roc_barrier;
6246 bool roc;
6247 } lr;
Trond Myklebustfa178f22006-01-03 09:55:38 +01006248 struct nfs_fattr fattr;
Trond Myklebustfe650402006-01-03 09:55:18 +01006249 int rpc_status;
Peng Tao039b7562014-07-03 13:05:02 +08006250 struct inode *inode;
Trond Myklebustfe650402006-01-03 09:55:18 +01006251};
6252
Trond Myklebustfe650402006-01-03 09:55:18 +01006253static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
6254{
6255 struct nfs4_delegreturndata *data = calldata;
Trond Myklebuste0dba012017-11-07 11:02:32 -05006256 struct nfs4_exception exception = {
6257 .inode = data->inode,
6258 .stateid = &data->stateid,
6259 };
Andy Adamson938e1012009-04-01 09:22:28 -04006260
Trond Myklebust14516c32010-07-31 14:29:06 -04006261 if (!nfs4_sequence_done(task, &data->res.seq_res))
6262 return;
Andy Adamson938e1012009-04-01 09:22:28 -04006263
Trond Myklebustca8acf82013-08-13 10:36:56 -04006264 trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status);
Trond Myklebust586f1c32016-11-15 15:03:33 -05006265
6266 /* Handle Layoutreturn errors */
Trond Myklebust287a9c52019-09-20 07:23:41 -04006267 if (pnfs_roc_done(task, data->inode,
6268 &data->args.lr_args,
6269 &data->res.lr_res,
6270 &data->res.lr_ret) == -EAGAIN)
6271 goto out_restart;
Trond Myklebust586f1c32016-11-15 15:03:33 -05006272
Ricardo Labiaga79708862009-12-07 09:23:21 -05006273 switch (task->tk_status) {
Ricardo Labiaga79708862009-12-07 09:23:21 -05006274 case 0:
Trond Myklebustfa178f22006-01-03 09:55:38 +01006275 renew_lease(data->res.server, data->timestamp);
Trond Myklebust23ea44c2016-11-10 16:06:28 -05006276 break;
Trond Myklebustc97cf602013-11-19 16:34:14 -05006277 case -NFS4ERR_ADMIN_REVOKED:
6278 case -NFS4ERR_DELEG_REVOKED:
Trond Myklebust26d36302016-09-22 13:39:05 -04006279 case -NFS4ERR_EXPIRED:
6280 nfs4_free_revoked_stateid(data->res.server,
6281 data->args.stateid,
6282 task->tk_msg.rpc_cred);
Trond Myklebust12f275c2017-11-06 15:28:05 -05006283 /* Fallthrough */
Trond Myklebustc97cf602013-11-19 16:34:14 -05006284 case -NFS4ERR_BAD_STATEID:
Trond Myklebustc97cf602013-11-19 16:34:14 -05006285 case -NFS4ERR_STALE_STATEID:
Trond Myklebust244fcd22019-12-20 10:43:37 -05006286 case -ETIMEDOUT:
Trond Myklebustc97cf602013-11-19 16:34:14 -05006287 task->tk_status = 0;
6288 break;
Trond Myklebust12f275c2017-11-06 15:28:05 -05006289 case -NFS4ERR_OLD_STATEID:
Trond Myklebust246afc0a2019-10-24 18:00:35 -04006290 if (!nfs4_refresh_delegation_stateid(&data->stateid, data->inode))
6291 nfs4_stateid_seqid_inc(&data->stateid);
Trond Myklebust70d136b2019-10-26 22:37:40 -04006292 if (data->args.bitmask) {
6293 data->args.bitmask = NULL;
6294 data->res.fattr = NULL;
6295 }
Trond Myklebust246afc0a2019-10-24 18:00:35 -04006296 goto out_restart;
Trond Myklebust8ac2b4222016-12-19 10:23:10 -05006297 case -NFS4ERR_ACCESS:
6298 if (data->args.bitmask) {
6299 data->args.bitmask = NULL;
6300 data->res.fattr = NULL;
Trond Myklebust140087fd2017-11-06 15:28:10 -05006301 goto out_restart;
Trond Myklebust8ac2b4222016-12-19 10:23:10 -05006302 }
Trond Myklebust140087fd2017-11-06 15:28:10 -05006303 /* Fallthrough */
Ricardo Labiaga79708862009-12-07 09:23:21 -05006304 default:
Trond Myklebuste0dba012017-11-07 11:02:32 -05006305 task->tk_status = nfs4_async_handle_exception(task,
6306 data->res.server, task->tk_status,
6307 &exception);
6308 if (exception.retry)
Trond Myklebust140087fd2017-11-06 15:28:10 -05006309 goto out_restart;
Ricardo Labiaga79708862009-12-07 09:23:21 -05006310 }
Trond Myklebustd51f91d2019-10-21 14:22:14 -04006311 nfs_delegation_mark_returned(data->inode, data->args.stateid);
Ricardo Labiaga79708862009-12-07 09:23:21 -05006312 data->rpc_status = task->tk_status;
Trond Myklebust140087fd2017-11-06 15:28:10 -05006313 return;
Trond Myklebust140087fd2017-11-06 15:28:10 -05006314out_restart:
6315 task->tk_status = 0;
6316 rpc_restart_call_prepare(task);
Trond Myklebustfe650402006-01-03 09:55:18 +01006317}
6318
6319static void nfs4_delegreturn_release(void *calldata)
6320{
Peng Tao039b7562014-07-03 13:05:02 +08006321 struct nfs4_delegreturndata *data = calldata;
Trond Myklebustea7c38f2015-02-05 15:13:24 -05006322 struct inode *inode = data->inode;
Peng Tao039b7562014-07-03 13:05:02 +08006323
Trond Myklebustea7c38f2015-02-05 15:13:24 -05006324 if (inode) {
Trond Myklebust586f1c32016-11-15 15:03:33 -05006325 if (data->lr.roc)
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05006326 pnfs_roc_release(&data->lr.arg, &data->lr.res,
6327 data->res.lr_ret);
Trond Myklebust0bc2c9b2016-12-16 19:48:09 -05006328 nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
Trond Myklebustea7c38f2015-02-05 15:13:24 -05006329 nfs_iput_and_deactive(inode);
6330 }
Trond Myklebustfe650402006-01-03 09:55:18 +01006331 kfree(calldata);
6332}
6333
Andy Adamson938e1012009-04-01 09:22:28 -04006334static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
6335{
6336 struct nfs4_delegreturndata *d_data;
Trond Myklebustc8bf7072018-06-15 16:31:02 -04006337 struct pnfs_layout_hdr *lo;
Andy Adamson938e1012009-04-01 09:22:28 -04006338
6339 d_data = (struct nfs4_delegreturndata *)data;
6340
Trond Myklebust5326de92019-11-13 09:39:36 +01006341 if (!d_data->lr.roc && nfs4_wait_on_layoutreturn(d_data->inode, task)) {
6342 nfs4_sequence_done(task, &d_data->res.seq_res);
Peng Tao500d7012015-09-22 11:35:22 +08006343 return;
Trond Myklebust5326de92019-11-13 09:39:36 +01006344 }
Peng Tao500d7012015-09-22 11:35:22 +08006345
Trond Myklebustc8bf7072018-06-15 16:31:02 -04006346 lo = d_data->args.lr_args ? d_data->args.lr_args->layout : NULL;
6347 if (lo && !pnfs_layout_is_valid(lo)) {
6348 d_data->args.lr_args = NULL;
6349 d_data->res.lr_res = NULL;
6350 }
6351
Anna Schumaker42e1cca2017-01-09 15:48:22 -05006352 nfs4_setup_sequence(d_data->res.server->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04006353 &d_data->args.seq_args,
6354 &d_data->res.seq_res,
6355 task);
Andy Adamson938e1012009-04-01 09:22:28 -04006356}
Andy Adamson938e1012009-04-01 09:22:28 -04006357
Jesper Juhlc8d149f2006-03-20 13:44:07 -05006358static const struct rpc_call_ops nfs4_delegreturn_ops = {
Andy Adamson938e1012009-04-01 09:22:28 -04006359 .rpc_call_prepare = nfs4_delegreturn_prepare,
Trond Myklebustfe650402006-01-03 09:55:18 +01006360 .rpc_call_done = nfs4_delegreturn_done,
6361 .rpc_release = nfs4_delegreturn_release,
6362};
6363
NeilBrowna52458b2018-12-03 11:30:31 +11006364static int _nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, const nfs4_stateid *stateid, int issync)
Trond Myklebustfe650402006-01-03 09:55:18 +01006365{
6366 struct nfs4_delegreturndata *data;
Trond Myklebustfa178f22006-01-03 09:55:38 +01006367 struct nfs_server *server = NFS_SERVER(inode);
Trond Myklebustfe650402006-01-03 09:55:18 +01006368 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04006369 struct rpc_message msg = {
6370 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN],
6371 .rpc_cred = cred,
6372 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04006373 struct rpc_task_setup task_setup_data = {
6374 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04006375 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006376 .callback_ops = &nfs4_delegreturn_ops,
Trond Myklebustf304a802020-05-11 10:42:04 -04006377 .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006378 };
Trond Myklebuste6f81072008-01-24 18:14:34 -05006379 int status = 0;
Trond Myklebustfe650402006-01-03 09:55:18 +01006380
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006381 data = kzalloc(sizeof(*data), GFP_NOFS);
Trond Myklebustfe650402006-01-03 09:55:18 +01006382 if (data == NULL)
6383 return -ENOMEM;
Anna Schumakerfba83f32018-05-04 16:22:50 -04006384 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1, 0);
Andrew Elble99ade3c2015-12-02 09:39:51 -05006385
6386 nfs4_state_protect(server->nfs_client,
6387 NFS_SP4_MACH_CRED_CLEANUP,
6388 &task_setup_data.rpc_client, &msg);
6389
Trond Myklebustfe650402006-01-03 09:55:18 +01006390 data->args.fhandle = &data->fh;
6391 data->args.stateid = &data->stateid;
Trond Myklebust9e907fe2012-04-27 13:48:17 -04006392 data->args.bitmask = server->cache_consistency_bitmask;
Trond Myklebustfe650402006-01-03 09:55:18 +01006393 nfs_copy_fh(&data->fh, NFS_FH(inode));
Trond Myklebustf597c532012-03-04 18:13:56 -05006394 nfs4_stateid_copy(&data->stateid, stateid);
Trond Myklebustfa178f22006-01-03 09:55:38 +01006395 data->res.fattr = &data->fattr;
6396 data->res.server = server;
Trond Myklebust586f1c32016-11-15 15:03:33 -05006397 data->res.lr_ret = -NFS4ERR_NOMATCHING_LAYOUT;
Trond Myklebust4d796d72016-09-23 11:38:08 -04006398 data->lr.arg.ld_private = &data->lr.ld_private;
Trond Myklebust5138fde2007-07-14 15:40:01 -04006399 nfs_fattr_init(data->res.fattr);
Trond Myklebust26e976a2006-01-03 09:55:21 +01006400 data->timestamp = jiffies;
Trond Myklebustfe650402006-01-03 09:55:18 +01006401 data->rpc_status = 0;
Trond Myklebust53e6fc82016-11-19 08:48:47 -05006402 data->lr.roc = pnfs_roc(inode, &data->lr.arg, &data->lr.res, cred);
Trond Myklebustea7c38f2015-02-05 15:13:24 -05006403 data->inode = nfs_igrab_and_active(inode);
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05006404 if (data->inode) {
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05006405 if (data->lr.roc) {
6406 data->args.lr_args = &data->lr.arg;
6407 data->res.lr_res = &data->lr.res;
6408 }
Trond Myklebust53e6fc82016-11-19 08:48:47 -05006409 } else if (data->lr.roc) {
6410 pnfs_roc_release(&data->lr.arg, &data->lr.res, 0);
6411 data->lr.roc = false;
Trond Myklebust1c5bd76d2016-11-16 01:11:25 -05006412 }
Trond Myklebustfe650402006-01-03 09:55:18 +01006413
Trond Myklebustc970aa82007-07-14 15:39:59 -04006414 task_setup_data.callback_data = data;
Trond Myklebust1174dd12010-12-21 10:52:24 -05006415 msg.rpc_argp = &data->args;
6416 msg.rpc_resp = &data->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04006417 task = rpc_run_task(&task_setup_data);
Trond Myklebust7a1218a2006-03-20 18:11:10 -05006418 if (IS_ERR(task))
Trond Myklebustfe650402006-01-03 09:55:18 +01006419 return PTR_ERR(task);
Trond Myklebuste6f81072008-01-24 18:14:34 -05006420 if (!issync)
6421 goto out;
Anna Schumaker820bf852017-01-11 15:01:43 -05006422 status = rpc_wait_for_completion_task(task);
Trond Myklebuste6f81072008-01-24 18:14:34 -05006423 if (status != 0)
6424 goto out;
6425 status = data->rpc_status;
Trond Myklebuste6f81072008-01-24 18:14:34 -05006426out:
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05006427 rpc_put_task(task);
Trond Myklebustfe650402006-01-03 09:55:18 +01006428 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006429}
6430
NeilBrowna52458b2018-12-03 11:30:31 +11006431int nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, const nfs4_stateid *stateid, int issync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07006432{
6433 struct nfs_server *server = NFS_SERVER(inode);
6434 struct nfs4_exception exception = { };
6435 int err;
6436 do {
Trond Myklebuste6f81072008-01-24 18:14:34 -05006437 err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
Olga Kornievskaia48c95792015-11-24 13:29:41 -05006438 trace_nfs4_delegreturn(inode, stateid, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006439 switch (err) {
6440 case -NFS4ERR_STALE_STATEID:
6441 case -NFS4ERR_EXPIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006442 case 0:
6443 return 0;
6444 }
6445 err = nfs4_handle_exception(server, err, &exception);
6446 } while (exception.retry);
6447 return err;
6448}
6449
Linus Torvalds1da177e2005-04-16 15:20:36 -07006450static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
6451{
6452 struct inode *inode = state->inode;
6453 struct nfs_server *server = NFS_SERVER(inode);
David Howells7539bba2006-08-22 20:06:09 -04006454 struct nfs_client *clp = server->nfs_client;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006455 struct nfs_lockt_args arg = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07006456 .fh = NFS_FH(inode),
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006457 .fl = request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006458 };
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006459 struct nfs_lockt_res res = {
6460 .denied = request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006461 };
6462 struct rpc_message msg = {
6463 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT],
Anna Schumakerd9b67e12017-01-11 15:04:25 -05006464 .rpc_argp = &arg,
6465 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006466 .rpc_cred = state->owner->so_cred,
6467 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006468 struct nfs4_lock_state *lsp;
6469 int status;
6470
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006471 arg.lock_owner.clientid = clp->cl_clientid;
Trond Myklebust8d0a8a92005-06-22 17:16:32 +00006472 status = nfs4_set_lock_state(state, request);
6473 if (status != 0)
6474 goto out;
6475 lsp = request->fl_u.nfs4_fl.owner;
Trond Myklebust48c22eb2012-01-17 22:04:25 -05006476 arg.lock_owner.id = lsp->ls_seqid.owner_id;
Trond Myklebustd035c362010-12-21 10:45:27 -05006477 arg.lock_owner.s_dev = server->s_dev;
Bryan Schumaker7c513052011-03-24 17:12:24 +00006478 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006479 switch (status) {
6480 case 0:
6481 request->fl_type = F_UNLCK;
6482 break;
6483 case -NFS4ERR_DENIED:
6484 status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006485 }
J. Bruce Fields70cc6482007-02-22 18:48:53 -05006486 request->fl_ops->fl_release_private(request);
Trond Myklebusta6f951d2013-10-01 14:24:58 -04006487 request->fl_ops = NULL;
Trond Myklebust8d0a8a92005-06-22 17:16:32 +00006488out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07006489 return status;
6490}
6491
6492static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
6493{
Trond Myklebust0688e642019-04-07 13:59:09 -04006494 struct nfs4_exception exception = {
6495 .interruptible = true,
6496 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07006497 int err;
6498
6499 do {
Trond Myklebustd1b748a2013-08-12 16:35:20 -04006500 err = _nfs4_proc_getlk(state, cmd, request);
6501 trace_nfs4_get_lock(request, state, cmd, err);
6502 err = nfs4_handle_exception(NFS_SERVER(state->inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07006503 &exception);
6504 } while (exception.retry);
6505 return err;
6506}
6507
Trond Myklebust32c6e7e2019-09-20 07:23:48 -04006508/*
6509 * Update the seqid of a lock stateid after receiving
6510 * NFS4ERR_OLD_STATEID
6511 */
6512static bool nfs4_refresh_lock_old_stateid(nfs4_stateid *dst,
6513 struct nfs4_lock_state *lsp)
6514{
6515 struct nfs4_state *state = lsp->ls_state;
6516 bool ret = false;
6517
6518 spin_lock(&state->state_lock);
6519 if (!nfs4_stateid_match_other(dst, &lsp->ls_stateid))
6520 goto out;
6521 if (!nfs4_stateid_is_newer(&lsp->ls_stateid, dst))
6522 nfs4_stateid_seqid_inc(dst);
6523 else
6524 dst->seqid = lsp->ls_stateid.seqid;
6525 ret = true;
6526out:
6527 spin_unlock(&state->state_lock);
6528 return ret;
6529}
6530
6531static bool nfs4_sync_lock_stateid(nfs4_stateid *dst,
6532 struct nfs4_lock_state *lsp)
6533{
6534 struct nfs4_state *state = lsp->ls_state;
6535 bool ret;
6536
6537 spin_lock(&state->state_lock);
6538 ret = !nfs4_stateid_match_other(dst, &lsp->ls_stateid);
6539 nfs4_stateid_copy(dst, &lsp->ls_stateid);
6540 spin_unlock(&state->state_lock);
6541 return ret;
6542}
6543
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006544struct nfs4_unlockdata {
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006545 struct nfs_locku_args arg;
6546 struct nfs_locku_res res;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006547 struct nfs4_lock_state *lsp;
6548 struct nfs_open_context *ctx;
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04006549 struct nfs_lock_context *l_ctx;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006550 struct file_lock fl;
Trond Myklebust516285eb2015-09-20 16:15:24 -04006551 struct nfs_server *server;
Trond Myklebust26e976a2006-01-03 09:55:21 +01006552 unsigned long timestamp;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006553};
6554
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006555static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
6556 struct nfs_open_context *ctx,
6557 struct nfs4_lock_state *lsp,
6558 struct nfs_seqid *seqid)
6559{
6560 struct nfs4_unlockdata *p;
Trond Myklebust32c6e7e2019-09-20 07:23:48 -04006561 struct nfs4_state *state = lsp->ls_state;
6562 struct inode *inode = state->inode;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006563
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006564 p = kzalloc(sizeof(*p), GFP_NOFS);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006565 if (p == NULL)
6566 return NULL;
6567 p->arg.fh = NFS_FH(inode);
6568 p->arg.fl = &p->fl;
6569 p->arg.seqid = seqid;
Trond Myklebustc1d51932008-04-07 13:20:54 -04006570 p->res.seqid = seqid;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006571 p->lsp = lsp;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006572 /* Ensure we don't close file until we're done freeing locks! */
6573 p->ctx = get_nfs_open_context(ctx);
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04006574 p->l_ctx = nfs_get_lock_context(ctx);
NeilBrown7b587e12018-11-30 10:04:08 +11006575 locks_init_lock(&p->fl);
6576 locks_copy_lock(&p->fl, fl);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006577 p->server = NFS_SERVER(inode);
Trond Myklebust32c6e7e2019-09-20 07:23:48 -04006578 spin_lock(&state->state_lock);
6579 nfs4_stateid_copy(&p->arg.stateid, &lsp->ls_stateid);
6580 spin_unlock(&state->state_lock);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006581 return p;
6582}
6583
Trond Myklebust06f814a2006-01-03 09:55:07 +01006584static void nfs4_locku_release_calldata(void *data)
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006585{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006586 struct nfs4_unlockdata *calldata = data;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006587 nfs_free_seqid(calldata->arg.seqid);
Trond Myklebust06f814a2006-01-03 09:55:07 +01006588 nfs4_put_lock_state(calldata->lsp);
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04006589 nfs_put_lock_context(calldata->l_ctx);
Trond Myklebust06f814a2006-01-03 09:55:07 +01006590 put_nfs_open_context(calldata->ctx);
6591 kfree(calldata);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006592}
6593
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006594static void nfs4_locku_done(struct rpc_task *task, void *data)
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006595{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006596 struct nfs4_unlockdata *calldata = data;
Trond Myklebust82571552017-11-07 11:14:49 -05006597 struct nfs4_exception exception = {
6598 .inode = calldata->lsp->ls_state->inode,
6599 .stateid = &calldata->arg.stateid,
6600 };
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006601
Trond Myklebust14516c32010-07-31 14:29:06 -04006602 if (!nfs4_sequence_done(task, &calldata->res.seq_res))
6603 return;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006604 switch (task->tk_status) {
6605 case 0:
Trond Myklebust26e976a2006-01-03 09:55:21 +01006606 renew_lease(calldata->server, calldata->timestamp);
Jeff Layton75575dd2016-09-17 18:17:32 -04006607 locks_lock_inode_wait(calldata->lsp->ls_state->inode, &calldata->fl);
Trond Myklebustc69899a2015-01-24 16:03:52 -05006608 if (nfs4_update_lock_stateid(calldata->lsp,
6609 &calldata->res.stateid))
6610 break;
Gustavo A. R. Silva01e03bd2018-07-31 21:18:44 -05006611 /* Fall through */
Trond Myklebust26d36302016-09-22 13:39:05 -04006612 case -NFS4ERR_ADMIN_REVOKED:
6613 case -NFS4ERR_EXPIRED:
6614 nfs4_free_revoked_stateid(calldata->server,
6615 &calldata->arg.stateid,
6616 task->tk_msg.rpc_cred);
Gustavo A. R. Silva01e03bd2018-07-31 21:18:44 -05006617 /* Fall through */
Trond Myklebust9e33bed2008-12-23 15:21:46 -05006618 case -NFS4ERR_BAD_STATEID:
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006619 case -NFS4ERR_STALE_STATEID:
Trond Myklebust32c6e7e2019-09-20 07:23:48 -04006620 if (nfs4_sync_lock_stateid(&calldata->arg.stateid,
6621 calldata->lsp))
6622 rpc_restart_call_prepare(task);
6623 break;
6624 case -NFS4ERR_OLD_STATEID:
6625 if (nfs4_refresh_lock_old_stateid(&calldata->arg.stateid,
6626 calldata->lsp))
Trond Myklebust425c1d42015-01-24 14:57:53 -05006627 rpc_restart_call_prepare(task);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006628 break;
6629 default:
Trond Myklebust82571552017-11-07 11:14:49 -05006630 task->tk_status = nfs4_async_handle_exception(task,
6631 calldata->server, task->tk_status,
6632 &exception);
6633 if (exception.retry)
Trond Myklebustd00c5d42011-10-19 12:17:29 -07006634 rpc_restart_call_prepare(task);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006635 }
Trond Myklebust2b1bc302012-10-29 18:53:23 -04006636 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006637}
6638
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01006639static void nfs4_locku_prepare(struct rpc_task *task, void *data)
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006640{
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01006641 struct nfs4_unlockdata *calldata = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006642
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04006643 if (test_bit(NFS_CONTEXT_UNLOCK, &calldata->l_ctx->open_context->flags) &&
6644 nfs_async_iocounter_wait(task, calldata->l_ctx))
6645 return;
6646
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006647 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05006648 goto out_wait;
Trond Myklebust795a88c2012-09-10 13:26:49 -04006649 if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006650 /* Note: exit _without_ running nfs4_locku_done */
Trond Myklebustc8da19b2013-02-11 19:01:21 -05006651 goto out_no_action;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006652 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01006653 calldata->timestamp = jiffies;
Anna Schumaker42e1cca2017-01-09 15:48:22 -05006654 if (nfs4_setup_sequence(calldata->server->nfs_client,
Andy Adamsona8936932009-04-01 09:22:23 -04006655 &calldata->arg.seq_args,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04006656 &calldata->res.seq_res,
6657 task) != 0)
6658 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05006659 return;
6660out_no_action:
6661 task->tk_action = NULL;
6662out_wait:
6663 nfs4_sequence_done(task, &calldata->res.seq_res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07006664}
6665
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006666static const struct rpc_call_ops nfs4_locku_ops = {
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01006667 .rpc_call_prepare = nfs4_locku_prepare,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006668 .rpc_call_done = nfs4_locku_done,
Trond Myklebust06f814a2006-01-03 09:55:07 +01006669 .rpc_release = nfs4_locku_release_calldata,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01006670};
6671
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006672static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
6673 struct nfs_open_context *ctx,
6674 struct nfs4_lock_state *lsp,
6675 struct nfs_seqid *seqid)
6676{
6677 struct nfs4_unlockdata *data;
Trond Myklebust5138fde2007-07-14 15:40:01 -04006678 struct rpc_message msg = {
6679 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU],
6680 .rpc_cred = ctx->cred,
6681 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04006682 struct rpc_task_setup task_setup_data = {
6683 .rpc_client = NFS_CLIENT(lsp->ls_state->inode),
Trond Myklebust5138fde2007-07-14 15:40:01 -04006684 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006685 .callback_ops = &nfs4_locku_ops,
Trond Myklebust101070c2008-02-19 20:04:23 -05006686 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006687 .flags = RPC_TASK_ASYNC,
6688 };
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006689
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04006690 nfs4_state_protect(NFS_SERVER(lsp->ls_state->inode)->nfs_client,
6691 NFS_SP4_MACH_CRED_CLEANUP, &task_setup_data.rpc_client, &msg);
6692
Frank Filz137d6ac2007-07-09 15:32:29 -07006693 /* Ensure this is an unlock - when canceling a lock, the
6694 * canceled lock is passed in, and it won't be an unlock.
6695 */
6696 fl->fl_type = F_UNLCK;
Benjamin Coddingtonf30cb752017-04-11 12:50:12 -04006697 if (fl->fl_flags & FL_CLOSE)
6698 set_bit(NFS_CONTEXT_UNLOCK, &ctx->flags);
Frank Filz137d6ac2007-07-09 15:32:29 -07006699
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006700 data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
6701 if (data == NULL) {
6702 nfs_free_seqid(seqid);
6703 return ERR_PTR(-ENOMEM);
6704 }
6705
Anna Schumakerfba83f32018-05-04 16:22:50 -04006706 nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1, 0);
Trond Myklebust1174dd12010-12-21 10:52:24 -05006707 msg.rpc_argp = &data->arg;
6708 msg.rpc_resp = &data->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04006709 task_setup_data.callback_data = data;
6710 return rpc_run_task(&task_setup_data);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006711}
6712
Linus Torvalds1da177e2005-04-16 15:20:36 -07006713static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
6714{
Trond Myklebust65b62a22013-02-07 10:54:07 -05006715 struct inode *inode = state->inode;
6716 struct nfs4_state_owner *sp = state->owner;
6717 struct nfs_inode *nfsi = NFS_I(inode);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006718 struct nfs_seqid *seqid;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006719 struct nfs4_lock_state *lsp;
Trond Myklebust06f814a2006-01-03 09:55:07 +01006720 struct rpc_task *task;
Trond Myklebustb4019c02015-01-24 14:19:19 -05006721 struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
Trond Myklebust06f814a2006-01-03 09:55:07 +01006722 int status = 0;
Trond Myklebust536ff0f2008-04-04 15:08:02 -04006723 unsigned char fl_flags = request->fl_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006724
Trond Myklebust9b073572006-06-29 16:38:34 -04006725 status = nfs4_set_lock_state(state, request);
6726 /* Unlock _before_ we do the RPC call */
6727 request->fl_flags |= FL_EXISTS;
Trond Myklebust65b62a22013-02-07 10:54:07 -05006728 /* Exclude nfs_delegation_claim_locks() */
6729 mutex_lock(&sp->so_delegreturn_mutex);
6730 /* Exclude nfs4_reclaim_open_stateid() - note nesting! */
Trond Myklebust19e03c52008-12-23 15:21:44 -05006731 down_read(&nfsi->rwsem);
Jeff Layton75575dd2016-09-17 18:17:32 -04006732 if (locks_lock_inode_wait(inode, request) == -ENOENT) {
Trond Myklebust19e03c52008-12-23 15:21:44 -05006733 up_read(&nfsi->rwsem);
Trond Myklebust65b62a22013-02-07 10:54:07 -05006734 mutex_unlock(&sp->so_delegreturn_mutex);
Trond Myklebust9b073572006-06-29 16:38:34 -04006735 goto out;
Trond Myklebust19e03c52008-12-23 15:21:44 -05006736 }
6737 up_read(&nfsi->rwsem);
Trond Myklebust65b62a22013-02-07 10:54:07 -05006738 mutex_unlock(&sp->so_delegreturn_mutex);
Trond Myklebust9b073572006-06-29 16:38:34 -04006739 if (status != 0)
6740 goto out;
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05006741 /* Is this a delegated lock? */
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006742 lsp = request->fl_u.nfs4_fl.owner;
Trond Myklebustc5a2a152013-04-30 12:43:42 -04006743 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) == 0)
6744 goto out;
Trond Myklebustb4019c02015-01-24 14:19:19 -05006745 alloc_seqid = NFS_SERVER(inode)->nfs_client->cl_mvops->alloc_seqid;
6746 seqid = alloc_seqid(&lsp->ls_seqid, GFP_KERNEL);
Trond Myklebust9b073572006-06-29 16:38:34 -04006747 status = -ENOMEM;
Trond Myklebustbadc76d2015-01-23 18:48:00 -05006748 if (IS_ERR(seqid))
Trond Myklebust9b073572006-06-29 16:38:34 -04006749 goto out;
Trond Myklebustcd3758e2007-08-10 17:44:32 -04006750 task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006751 status = PTR_ERR(task);
6752 if (IS_ERR(task))
Trond Myklebust9b073572006-06-29 16:38:34 -04006753 goto out;
Anna Schumaker820bf852017-01-11 15:01:43 -05006754 status = rpc_wait_for_completion_task(task);
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05006755 rpc_put_task(task);
Trond Myklebust9b073572006-06-29 16:38:34 -04006756out:
Trond Myklebust536ff0f2008-04-04 15:08:02 -04006757 request->fl_flags = fl_flags;
Trond Myklebustd1b748a2013-08-12 16:35:20 -04006758 trace_nfs4_unlock(request, state, F_SETLK, status);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07006759 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006760}
6761
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006762struct nfs4_lockdata {
6763 struct nfs_lock_args arg;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01006764 struct nfs_lock_res res;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006765 struct nfs4_lock_state *lsp;
6766 struct nfs_open_context *ctx;
6767 struct file_lock fl;
Trond Myklebust26e976a2006-01-03 09:55:21 +01006768 unsigned long timestamp;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006769 int rpc_status;
6770 int cancelled;
Andy Adamson66179ef2009-04-01 09:22:22 -04006771 struct nfs_server *server;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006772};
6773
6774static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006775 struct nfs_open_context *ctx, struct nfs4_lock_state *lsp,
6776 gfp_t gfp_mask)
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006777{
6778 struct nfs4_lockdata *p;
6779 struct inode *inode = lsp->ls_state->inode;
6780 struct nfs_server *server = NFS_SERVER(inode);
Trond Myklebustb4019c02015-01-24 14:19:19 -05006781 struct nfs_seqid *(*alloc_seqid)(struct nfs_seqid_counter *, gfp_t);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006782
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006783 p = kzalloc(sizeof(*p), gfp_mask);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006784 if (p == NULL)
6785 return NULL;
6786
6787 p->arg.fh = NFS_FH(inode);
6788 p->arg.fl = &p->fl;
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006789 p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask);
Trond Myklebustbadc76d2015-01-23 18:48:00 -05006790 if (IS_ERR(p->arg.open_seqid))
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006791 goto out_free;
Trond Myklebustb4019c02015-01-24 14:19:19 -05006792 alloc_seqid = server->nfs_client->cl_mvops->alloc_seqid;
6793 p->arg.lock_seqid = alloc_seqid(&lsp->ls_seqid, gfp_mask);
Trond Myklebustbadc76d2015-01-23 18:48:00 -05006794 if (IS_ERR(p->arg.lock_seqid))
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006795 goto out_free_seqid;
David Howells7539bba2006-08-22 20:06:09 -04006796 p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
Trond Myklebust48c22eb2012-01-17 22:04:25 -05006797 p->arg.lock_owner.id = lsp->ls_seqid.owner_id;
Trond Myklebustd035c362010-12-21 10:45:27 -05006798 p->arg.lock_owner.s_dev = server->s_dev;
Trond Myklebustc1d51932008-04-07 13:20:54 -04006799 p->res.lock_seqid = p->arg.lock_seqid;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006800 p->lsp = lsp;
Andy Adamson66179ef2009-04-01 09:22:22 -04006801 p->server = server;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006802 p->ctx = get_nfs_open_context(ctx);
NeilBrown7b587e12018-11-30 10:04:08 +11006803 locks_init_lock(&p->fl);
6804 locks_copy_lock(&p->fl, fl);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006805 return p;
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006806out_free_seqid:
6807 nfs_free_seqid(p->arg.open_seqid);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006808out_free:
6809 kfree(p);
6810 return NULL;
6811}
6812
6813static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
6814{
6815 struct nfs4_lockdata *data = calldata;
6816 struct nfs4_state *state = data->lsp->ls_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006817
Harvey Harrison3110ff82008-05-02 13:42:44 -07006818 dprintk("%s: begin!\n", __func__);
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006819 if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05006820 goto out_wait;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006821 /* Do we need to do an open_to_lock_owner? */
Trond Myklebust6b447532015-01-24 18:38:15 -05006822 if (!test_bit(NFS_LOCK_INITIALIZED, &data->lsp->ls_flags)) {
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006823 if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
Trond Myklebust2240a9e2012-10-29 18:37:40 -04006824 goto out_release_lock_seqid;
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006825 }
Trond Myklebust425c1d42015-01-24 14:57:53 -05006826 nfs4_stateid_copy(&data->arg.open_stateid,
6827 &state->open_stateid);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006828 data->arg.new_lock_owner = 1;
Trond Myklebustc1d51932008-04-07 13:20:54 -04006829 data->res.open_seqid = data->arg.open_seqid;
Trond Myklebust425c1d42015-01-24 14:57:53 -05006830 } else {
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006831 data->arg.new_lock_owner = 0;
Trond Myklebust425c1d42015-01-24 14:57:53 -05006832 nfs4_stateid_copy(&data->arg.lock_stateid,
6833 &data->lsp->ls_stateid);
6834 }
Trond Myklebust5d422302013-03-14 16:57:48 -04006835 if (!nfs4_valid_open_stateid(state)) {
6836 data->rpc_status = -EBADF;
6837 task->tk_action = NULL;
6838 goto out_release_open_seqid;
6839 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01006840 data->timestamp = jiffies;
Anna Schumaker42e1cca2017-01-09 15:48:22 -05006841 if (nfs4_setup_sequence(data->server->nfs_client,
Trond Myklebust035168ab2010-06-16 09:52:26 -04006842 &data->arg.seq_args,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04006843 &data->res.seq_res,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04006844 task) == 0)
Andy Adamson66179ef2009-04-01 09:22:22 -04006845 return;
Trond Myklebust5d422302013-03-14 16:57:48 -04006846out_release_open_seqid:
Trond Myklebust2240a9e2012-10-29 18:37:40 -04006847 nfs_release_seqid(data->arg.open_seqid);
6848out_release_lock_seqid:
6849 nfs_release_seqid(data->arg.lock_seqid);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05006850out_wait:
6851 nfs4_sequence_done(task, &data->res.seq_res);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006852 dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08006853}
6854
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006855static void nfs4_lock_done(struct rpc_task *task, void *calldata)
6856{
6857 struct nfs4_lockdata *data = calldata;
Trond Myklebust39071e62015-01-24 15:07:56 -05006858 struct nfs4_lock_state *lsp = data->lsp;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006859
Harvey Harrison3110ff82008-05-02 13:42:44 -07006860 dprintk("%s: begin!\n", __func__);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006861
Trond Myklebust14516c32010-07-31 14:29:06 -04006862 if (!nfs4_sequence_done(task, &data->res.seq_res))
6863 return;
Andy Adamson66179ef2009-04-01 09:22:22 -04006864
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006865 data->rpc_status = task->tk_status;
Trond Myklebust425c1d42015-01-24 14:57:53 -05006866 switch (task->tk_status) {
6867 case 0:
David Howells2b0143b2015-03-17 22:25:59 +00006868 renew_lease(NFS_SERVER(d_inode(data->ctx->dentry)),
Trond Myklebust39071e62015-01-24 15:07:56 -05006869 data->timestamp);
Benjamin Coddingtona3cf9bc2018-05-03 07:12:57 -04006870 if (data->arg.new_lock && !data->cancelled) {
Trond Myklebustc69899a2015-01-24 16:03:52 -05006871 data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
Benjamin Coddingtona3cf9bc2018-05-03 07:12:57 -04006872 if (locks_lock_inode_wait(lsp->ls_state->inode, &data->fl) < 0)
Trond Myklebust6ea76bf2018-07-29 22:21:22 -04006873 goto out_restart;
Trond Myklebustc69899a2015-01-24 16:03:52 -05006874 }
Trond Myklebust39071e62015-01-24 15:07:56 -05006875 if (data->arg.new_lock_owner != 0) {
6876 nfs_confirm_seqid(&lsp->ls_seqid, 0);
6877 nfs4_stateid_copy(&lsp->ls_stateid, &data->res.stateid);
6878 set_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
Trond Myklebust6ea76bf2018-07-29 22:21:22 -04006879 } else if (!nfs4_update_lock_stateid(lsp, &data->res.stateid))
6880 goto out_restart;
Trond Myklebust425c1d42015-01-24 14:57:53 -05006881 break;
6882 case -NFS4ERR_BAD_STATEID:
6883 case -NFS4ERR_OLD_STATEID:
6884 case -NFS4ERR_STALE_STATEID:
6885 case -NFS4ERR_EXPIRED:
6886 if (data->arg.new_lock_owner != 0) {
Trond Myklebust6ea76bf2018-07-29 22:21:22 -04006887 if (!nfs4_stateid_match(&data->arg.open_stateid,
Trond Myklebust425c1d42015-01-24 14:57:53 -05006888 &lsp->ls_state->open_stateid))
Trond Myklebust6ea76bf2018-07-29 22:21:22 -04006889 goto out_restart;
6890 } else if (!nfs4_stateid_match(&data->arg.lock_stateid,
Trond Myklebust425c1d42015-01-24 14:57:53 -05006891 &lsp->ls_stateid))
Trond Myklebust6ea76bf2018-07-29 22:21:22 -04006892 goto out_restart;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006893 }
Benjamin Coddingtona3cf9bc2018-05-03 07:12:57 -04006894out_done:
Harvey Harrison3110ff82008-05-02 13:42:44 -07006895 dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status);
Trond Myklebust6ea76bf2018-07-29 22:21:22 -04006896 return;
6897out_restart:
6898 if (!data->cancelled)
6899 rpc_restart_call_prepare(task);
6900 goto out_done;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006901}
6902
6903static void nfs4_lock_release(void *calldata)
6904{
6905 struct nfs4_lockdata *data = calldata;
6906
Harvey Harrison3110ff82008-05-02 13:42:44 -07006907 dprintk("%s: begin!\n", __func__);
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05006908 nfs_free_seqid(data->arg.open_seqid);
Trond Myklebust6ea76bf2018-07-29 22:21:22 -04006909 if (data->cancelled && data->rpc_status == 0) {
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006910 struct rpc_task *task;
6911 task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
6912 data->arg.lock_seqid);
6913 if (!IS_ERR(task))
Trond Myklebustbf294b42011-02-21 11:05:41 -08006914 rpc_put_task_async(task);
Harvey Harrison3110ff82008-05-02 13:42:44 -07006915 dprintk("%s: cancelling lock!\n", __func__);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006916 } else
6917 nfs_free_seqid(data->arg.lock_seqid);
6918 nfs4_put_lock_state(data->lsp);
6919 put_nfs_open_context(data->ctx);
6920 kfree(data);
Harvey Harrison3110ff82008-05-02 13:42:44 -07006921 dprintk("%s: done!\n", __func__);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006922}
6923
6924static const struct rpc_call_ops nfs4_lock_ops = {
6925 .rpc_call_prepare = nfs4_lock_prepare,
6926 .rpc_call_done = nfs4_lock_done,
6927 .rpc_release = nfs4_lock_release,
6928};
6929
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006930static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
6931{
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006932 switch (error) {
6933 case -NFS4ERR_ADMIN_REVOKED:
Trond Myklebustd7f3e4b2016-09-22 13:39:09 -04006934 case -NFS4ERR_EXPIRED:
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006935 case -NFS4ERR_BAD_STATEID:
Trond Myklebustecac7992011-03-09 16:00:56 -05006936 lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006937 if (new_lock_owner != 0 ||
Trond Myklebust795a88c2012-09-10 13:26:49 -04006938 test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0)
Trond Myklebustecac7992011-03-09 16:00:56 -05006939 nfs4_schedule_stateid_recovery(server, lsp->ls_state);
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -05006940 break;
6941 case -NFS4ERR_STALE_STATEID:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -05006942 lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
Trond Myklebustecac7992011-03-09 16:00:56 -05006943 nfs4_schedule_lease_recovery(server->nfs_client);
zhengbin8b98a532019-12-19 18:34:47 +08006944 }
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006945}
6946
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08006947static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type)
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006948{
6949 struct nfs4_lockdata *data;
6950 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04006951 struct rpc_message msg = {
6952 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK],
6953 .rpc_cred = state->owner->so_cred,
6954 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04006955 struct rpc_task_setup task_setup_data = {
6956 .rpc_client = NFS_CLIENT(state->inode),
Trond Myklebust5138fde2007-07-14 15:40:01 -04006957 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006958 .callback_ops = &nfs4_lock_ops,
Trond Myklebust101070c2008-02-19 20:04:23 -05006959 .workqueue = nfsiod_workqueue,
Trond Myklebust61296502020-02-07 19:38:12 -05006960 .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF,
Trond Myklebustc970aa82007-07-14 15:39:59 -04006961 };
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006962 int ret;
6963
Harvey Harrison3110ff82008-05-02 13:42:44 -07006964 dprintk("%s: begin!\n", __func__);
Trond Myklebustcd3758e2007-08-10 17:44:32 -04006965 data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006966 fl->fl_u.nfs4_fl.owner,
6967 recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006968 if (data == NULL)
6969 return -ENOMEM;
6970 if (IS_SETLKW(cmd))
6971 data->arg.block = 1;
Anna Schumakerfba83f32018-05-04 16:22:50 -04006972 nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1,
6973 recovery_type > NFS_LOCK_NEW);
Trond Myklebust1174dd12010-12-21 10:52:24 -05006974 msg.rpc_argp = &data->arg;
6975 msg.rpc_resp = &data->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04006976 task_setup_data.callback_data = data;
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006977 if (recovery_type > NFS_LOCK_NEW) {
6978 if (recovery_type == NFS_LOCK_RECLAIM)
6979 data->arg.reclaim = NFS_LOCK_RECLAIM;
Trond Myklebustc69899a2015-01-24 16:03:52 -05006980 } else
6981 data->arg.new_lock = 1;
Trond Myklebustc970aa82007-07-14 15:39:59 -04006982 task = rpc_run_task(&task_setup_data);
Trond Myklebust7a1218a2006-03-20 18:11:10 -05006983 if (IS_ERR(task))
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006984 return PTR_ERR(task);
Anna Schumaker820bf852017-01-11 15:01:43 -05006985 ret = rpc_wait_for_completion_task(task);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006986 if (ret == 0) {
6987 ret = data->rpc_status;
Trond Myklebust2bee72a2010-01-26 15:42:21 -05006988 if (ret)
6989 nfs4_handle_setlk_error(data->server, data->lsp,
6990 data->arg.new_lock_owner, ret);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006991 } else
Benjamin Coddingtona7a3b1e2017-06-20 08:33:44 -04006992 data->cancelled = true;
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05006993 rpc_put_task(task);
Harvey Harrison3110ff82008-05-02 13:42:44 -07006994 dprintk("%s: done, ret = %d!\n", __func__, ret);
Olga Kornievskaia48c95792015-11-24 13:29:41 -05006995 trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01006996 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07006997}
6998
6999static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
7000{
Trond Myklebust202b50d2005-06-22 17:16:29 +00007001 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust05ffe242012-04-18 12:20:10 -04007002 struct nfs4_exception exception = {
7003 .inode = state->inode,
7004 };
Trond Myklebust202b50d2005-06-22 17:16:29 +00007005 int err;
7006
7007 do {
Trond Myklebust42a2d132006-06-29 16:38:36 -04007008 /* Cache the lock if possible... */
7009 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
7010 return 0;
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08007011 err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
Trond Myklebust168667c2010-10-19 19:47:49 -04007012 if (err != -NFS4ERR_DELAY)
Trond Myklebust202b50d2005-06-22 17:16:29 +00007013 break;
7014 nfs4_handle_exception(server, err, &exception);
7015 } while (exception.retry);
7016 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007017}
7018
7019static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request)
7020{
Trond Myklebust202b50d2005-06-22 17:16:29 +00007021 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust05ffe242012-04-18 12:20:10 -04007022 struct nfs4_exception exception = {
7023 .inode = state->inode,
7024 };
Trond Myklebust202b50d2005-06-22 17:16:29 +00007025 int err;
7026
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05007027 err = nfs4_set_lock_state(state, request);
7028 if (err != 0)
7029 return err;
Trond Myklebustf6de7a32013-09-04 10:08:54 -04007030 if (!recover_lost_locks) {
NeilBrownef1820f2013-09-04 17:04:49 +10007031 set_bit(NFS_LOCK_LOST, &request->fl_u.nfs4_fl.owner->ls_flags);
7032 return 0;
7033 }
Trond Myklebust202b50d2005-06-22 17:16:29 +00007034 do {
Trond Myklebust42a2d132006-06-29 16:38:36 -04007035 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
7036 return 0;
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08007037 err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05007038 switch (err) {
7039 default:
7040 goto out;
7041 case -NFS4ERR_GRACE:
7042 case -NFS4ERR_DELAY:
7043 nfs4_handle_exception(server, err, &exception);
7044 err = 0;
7045 }
Trond Myklebust202b50d2005-06-22 17:16:29 +00007046 } while (exception.retry);
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05007047out:
Trond Myklebust202b50d2005-06-22 17:16:29 +00007048 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007049}
7050
Bryan Schumakerf062eb62011-06-02 14:59:10 -04007051#if defined(CONFIG_NFS_V4_1)
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05007052static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
7053{
Trond Myklebustc5896fc2016-09-22 13:39:03 -04007054 struct nfs4_lock_state *lsp;
7055 int status;
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05007056
Trond Myklebustc5896fc2016-09-22 13:39:03 -04007057 status = nfs4_set_lock_state(state, request);
7058 if (status != 0)
7059 return status;
7060 lsp = request->fl_u.nfs4_fl.owner;
7061 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) ||
7062 test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
7063 return 0;
Anna Schumaker81b68de2017-01-11 16:41:34 -05007064 return nfs4_lock_expired(state, request);
Bryan Schumakerf062eb62011-06-02 14:59:10 -04007065}
7066#endif
7067
Linus Torvalds1da177e2005-04-16 15:20:36 -07007068static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7069{
Trond Myklebust19e03c52008-12-23 15:21:44 -05007070 struct nfs_inode *nfsi = NFS_I(state->inode);
Chuck Lever11476e92016-04-11 16:20:22 -04007071 struct nfs4_state_owner *sp = state->owner;
Trond Myklebust01c3b862006-06-29 16:38:39 -04007072 unsigned char fl_flags = request->fl_flags;
Jeff Layton1ea67db2016-09-17 18:17:37 -04007073 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007074
Trond Myklebust01c3b862006-06-29 16:38:39 -04007075 request->fl_flags |= FL_ACCESS;
Jeff Layton75575dd2016-09-17 18:17:32 -04007076 status = locks_lock_inode_wait(state->inode, request);
Trond Myklebust01c3b862006-06-29 16:38:39 -04007077 if (status < 0)
7078 goto out;
Chuck Lever11476e92016-04-11 16:20:22 -04007079 mutex_lock(&sp->so_delegreturn_mutex);
Trond Myklebust19e03c52008-12-23 15:21:44 -05007080 down_read(&nfsi->rwsem);
Trond Myklebust01c3b862006-06-29 16:38:39 -04007081 if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
Trond Myklebust01c3b862006-06-29 16:38:39 -04007082 /* Yes: cache locks! */
Trond Myklebust01c3b862006-06-29 16:38:39 -04007083 /* ...but avoid races with delegation recall... */
Trond Myklebust19e03c52008-12-23 15:21:44 -05007084 request->fl_flags = fl_flags & ~FL_SLEEP;
Jeff Layton75575dd2016-09-17 18:17:32 -04007085 status = locks_lock_inode_wait(state->inode, request);
Trond Myklebustc69899a2015-01-24 16:03:52 -05007086 up_read(&nfsi->rwsem);
Chuck Lever11476e92016-04-11 16:20:22 -04007087 mutex_unlock(&sp->so_delegreturn_mutex);
Trond Myklebustc69899a2015-01-24 16:03:52 -05007088 goto out;
Trond Myklebust01c3b862006-06-29 16:38:39 -04007089 }
Trond Myklebust9a99af42013-02-04 20:17:49 -05007090 up_read(&nfsi->rwsem);
Chuck Lever11476e92016-04-11 16:20:22 -04007091 mutex_unlock(&sp->so_delegreturn_mutex);
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08007092 status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
Trond Myklebust01c3b862006-06-29 16:38:39 -04007093out:
7094 request->fl_flags = fl_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007095 return status;
7096}
7097
7098static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7099{
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -05007100 struct nfs4_exception exception = {
7101 .state = state,
Trond Myklebust05ffe242012-04-18 12:20:10 -04007102 .inode = state->inode,
Trond Myklebust0688e642019-04-07 13:59:09 -04007103 .interruptible = true,
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -05007104 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07007105 int err;
7106
7107 do {
Trond Myklebust965b5d62009-06-17 13:22:59 -07007108 err = _nfs4_proc_setlk(state, cmd, request);
7109 if (err == -NFS4ERR_DENIED)
7110 err = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007111 err = nfs4_handle_exception(NFS_SERVER(state->inode),
Trond Myklebust965b5d62009-06-17 13:22:59 -07007112 err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007113 } while (exception.retry);
7114 return err;
7115}
7116
Jeff Laytond2f3a7f2016-09-17 18:17:38 -04007117#define NFS4_LOCK_MINTIMEOUT (1 * HZ)
7118#define NFS4_LOCK_MAXTIMEOUT (30 * HZ)
7119
7120static int
Jeff Laytona1d617d82016-09-17 18:17:39 -04007121nfs4_retry_setlk_simple(struct nfs4_state *state, int cmd,
7122 struct file_lock *request)
Jeff Laytond2f3a7f2016-09-17 18:17:38 -04007123{
7124 int status = -ERESTARTSYS;
7125 unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
7126
7127 while(!signalled()) {
7128 status = nfs4_proc_setlk(state, cmd, request);
7129 if ((status != -EAGAIN) || IS_SETLK(cmd))
7130 break;
7131 freezable_schedule_timeout_interruptible(timeout);
7132 timeout *= 2;
7133 timeout = min_t(unsigned long, NFS4_LOCK_MAXTIMEOUT, timeout);
7134 status = -ERESTARTSYS;
7135 }
7136 return status;
7137}
7138
Jeff Laytona1d617d82016-09-17 18:17:39 -04007139#ifdef CONFIG_NFS_V4_1
7140struct nfs4_lock_waiter {
7141 struct task_struct *task;
7142 struct inode *inode;
7143 struct nfs_lowner *owner;
Jeff Laytona1d617d82016-09-17 18:17:39 -04007144};
7145
7146static int
Ingo Molnarac6424b2017-06-20 12:06:13 +02007147nfs4_wake_lock_waiter(wait_queue_entry_t *wait, unsigned int mode, int flags, void *key)
Jeff Laytona1d617d82016-09-17 18:17:39 -04007148{
7149 int ret;
Jeff Laytona1d617d82016-09-17 18:17:39 -04007150 struct nfs4_lock_waiter *waiter = wait->private;
Jeff Laytona1d617d82016-09-17 18:17:39 -04007151
Jeff Layton57174592018-03-18 08:37:03 -04007152 /* NULL key means to wake up everyone */
7153 if (key) {
7154 struct cb_notify_lock_args *cbnl = key;
7155 struct nfs_lowner *lowner = &cbnl->cbnl_owner,
7156 *wowner = waiter->owner;
Jeff Laytona1d617d82016-09-17 18:17:39 -04007157
Jeff Layton57174592018-03-18 08:37:03 -04007158 /* Only wake if the callback was for the same owner. */
7159 if (lowner->id != wowner->id || lowner->s_dev != wowner->s_dev)
7160 return 0;
Jeff Laytona1d617d82016-09-17 18:17:39 -04007161
Jeff Layton57174592018-03-18 08:37:03 -04007162 /* Make sure it's for the right inode */
7163 if (nfs_compare_fh(NFS_FH(waiter->inode), &cbnl->cbnl_fh))
7164 return 0;
Jeff Layton57174592018-03-18 08:37:03 -04007165 }
Jeff Laytona1d617d82016-09-17 18:17:39 -04007166
7167 /* override "private" so we can use default_wake_function */
7168 wait->private = waiter->task;
Yihao Wu52b042a2019-05-22 01:57:10 +08007169 ret = woken_wake_function(wait, mode, flags, key);
7170 if (ret)
7171 list_del_init(&wait->entry);
Jeff Laytona1d617d82016-09-17 18:17:39 -04007172 wait->private = waiter;
7173 return ret;
7174}
7175
7176static int
7177nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7178{
7179 int status = -ERESTARTSYS;
Jeff Laytona1d617d82016-09-17 18:17:39 -04007180 struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner;
7181 struct nfs_server *server = NFS_SERVER(state->inode);
7182 struct nfs_client *clp = server->nfs_client;
7183 wait_queue_head_t *q = &clp->cl_lock_waitq;
7184 struct nfs_lowner owner = { .clientid = clp->cl_clientid,
7185 .id = lsp->ls_seqid.owner_id,
7186 .s_dev = server->s_dev };
7187 struct nfs4_lock_waiter waiter = { .task = current,
7188 .inode = state->inode,
Yihao Wu52b042a2019-05-22 01:57:10 +08007189 .owner = &owner};
Ingo Molnarac6424b2017-06-20 12:06:13 +02007190 wait_queue_entry_t wait;
Jeff Laytona1d617d82016-09-17 18:17:39 -04007191
7192 /* Don't bother with waitqueue if we don't expect a callback */
7193 if (!test_bit(NFS_STATE_MAY_NOTIFY_LOCK, &state->flags))
7194 return nfs4_retry_setlk_simple(state, cmd, request);
7195
7196 init_wait(&wait);
7197 wait.private = &waiter;
7198 wait.func = nfs4_wake_lock_waiter;
Jeff Laytona1d617d82016-09-17 18:17:39 -04007199
7200 while(!signalled()) {
Yihao Wuba851a32019-05-13 14:58:22 +08007201 add_wait_queue(q, &wait);
Jeff Laytona1d617d82016-09-17 18:17:39 -04007202 status = nfs4_proc_setlk(state, cmd, request);
Yihao Wuba851a32019-05-13 14:58:22 +08007203 if ((status != -EAGAIN) || IS_SETLK(cmd)) {
7204 finish_wait(q, &wait);
Jeff Laytona1d617d82016-09-17 18:17:39 -04007205 break;
Yihao Wuba851a32019-05-13 14:58:22 +08007206 }
Jeff Laytona1d617d82016-09-17 18:17:39 -04007207
7208 status = -ERESTARTSYS;
Yihao Wu52b042a2019-05-22 01:57:10 +08007209 freezer_do_not_count();
7210 wait_woken(&wait, TASK_INTERRUPTIBLE, NFS4_LOCK_MAXTIMEOUT);
7211 freezer_count();
Yihao Wuba851a32019-05-13 14:58:22 +08007212 finish_wait(q, &wait);
Jeff Laytona1d617d82016-09-17 18:17:39 -04007213 }
7214
Jeff Laytona1d617d82016-09-17 18:17:39 -04007215 return status;
7216}
7217#else /* !CONFIG_NFS_V4_1 */
7218static inline int
7219nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7220{
7221 return nfs4_retry_setlk_simple(state, cmd, request);
7222}
7223#endif
7224
Linus Torvalds1da177e2005-04-16 15:20:36 -07007225static int
7226nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
7227{
7228 struct nfs_open_context *ctx;
7229 struct nfs4_state *state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07007230 int status;
7231
7232 /* verify open state */
Trond Myklebustcd3758e2007-08-10 17:44:32 -04007233 ctx = nfs_file_open_context(filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007234 state = ctx->state;
7235
Trond Myklebustd9531262009-07-21 19:22:38 -04007236 if (IS_GETLK(cmd)) {
7237 if (state != NULL)
7238 return nfs4_proc_getlk(state, F_GETLK, request);
7239 return 0;
7240 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007241
7242 if (!(IS_SETLK(cmd) || IS_SETLKW(cmd)))
7243 return -EINVAL;
7244
Trond Myklebustd9531262009-07-21 19:22:38 -04007245 if (request->fl_type == F_UNLCK) {
7246 if (state != NULL)
7247 return nfs4_proc_unlck(state, cmd, request);
7248 return 0;
7249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07007250
Trond Myklebustd9531262009-07-21 19:22:38 -04007251 if (state == NULL)
7252 return -ENOLCK;
Jeff Layton1ea67db2016-09-17 18:17:37 -04007253
7254 if ((request->fl_flags & FL_POSIX) &&
7255 !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags))
7256 return -ENOLCK;
7257
Benjamin Coddingtonfcfa4472017-11-10 06:27:49 -05007258 /*
7259 * Don't rely on the VFS having checked the file open mode,
7260 * since it won't do this for flock() locks.
7261 */
7262 switch (request->fl_type) {
7263 case F_RDLCK:
7264 if (!(filp->f_mode & FMODE_READ))
7265 return -EBADF;
7266 break;
7267 case F_WRLCK:
7268 if (!(filp->f_mode & FMODE_WRITE))
7269 return -EBADF;
7270 }
7271
Jeff Layton1ea67db2016-09-17 18:17:37 -04007272 status = nfs4_set_lock_state(state, request);
7273 if (status != 0)
7274 return status;
7275
Jeff Laytond2f3a7f2016-09-17 18:17:38 -04007276 return nfs4_retry_setlk(state, cmd, request);
Linus Torvalds1da177e2005-04-16 15:20:36 -07007277}
7278
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04007279int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid)
Trond Myklebust888e6942005-11-04 15:38:11 -05007280{
7281 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust888e6942005-11-04 15:38:11 -05007282 int err;
7283
7284 err = nfs4_set_lock_state(state, fl);
7285 if (err != 0)
Trond Myklebustdb4f2e62013-04-01 15:56:46 -04007286 return err;
Trond Myklebust4a706fa2013-04-01 14:47:22 -04007287 err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
NeilBrowndce26302017-12-13 09:57:09 +11007288 return nfs4_handle_delegation_recall_error(server, state, stateid, fl, err);
Trond Myklebust888e6942005-11-04 15:38:11 -05007289}
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007290
Trond Myklebustcf470c32012-03-07 13:49:12 -05007291struct nfs_release_lockowner_data {
7292 struct nfs4_lock_state *lsp;
Trond Myklebust5ae67c42012-03-19 16:17:18 -04007293 struct nfs_server *server;
Trond Myklebustcf470c32012-03-07 13:49:12 -05007294 struct nfs_release_lockowner_args args;
Trond Myklebustb7e63a12014-02-26 11:19:14 -08007295 struct nfs_release_lockowner_res res;
Chuck Lever60ea6812013-10-17 14:13:47 -04007296 unsigned long timestamp;
Trond Myklebustcf470c32012-03-07 13:49:12 -05007297};
7298
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04007299static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata)
7300{
7301 struct nfs_release_lockowner_data *data = calldata;
Kinglong Mee5b53dc82014-08-04 16:18:16 +08007302 struct nfs_server *server = data->server;
Anna Schumaker7981c8a2017-01-10 11:39:53 -05007303 nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
7304 &data->res.seq_res, task);
Kinglong Mee5b53dc82014-08-04 16:18:16 +08007305 data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
Chuck Lever60ea6812013-10-17 14:13:47 -04007306 data->timestamp = jiffies;
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04007307}
7308
7309static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
7310{
7311 struct nfs_release_lockowner_data *data = calldata;
Chuck Lever60ea6812013-10-17 14:13:47 -04007312 struct nfs_server *server = data->server;
7313
Trond Myklebustb7e63a12014-02-26 11:19:14 -08007314 nfs40_sequence_done(task, &data->res.seq_res);
Chuck Lever60ea6812013-10-17 14:13:47 -04007315
7316 switch (task->tk_status) {
7317 case 0:
7318 renew_lease(server, data->timestamp);
7319 break;
7320 case -NFS4ERR_STALE_CLIENTID:
7321 case -NFS4ERR_EXPIRED:
Kinglong Mee5b53dc82014-08-04 16:18:16 +08007322 nfs4_schedule_lease_recovery(server->nfs_client);
7323 break;
Chuck Lever60ea6812013-10-17 14:13:47 -04007324 case -NFS4ERR_LEASE_MOVED:
7325 case -NFS4ERR_DELAY:
NeilBrown8478eaa2014-09-18 16:09:27 +10007326 if (nfs4_async_handle_error(task, server,
7327 NULL, NULL) == -EAGAIN)
Chuck Lever60ea6812013-10-17 14:13:47 -04007328 rpc_restart_call_prepare(task);
7329 }
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04007330}
7331
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04007332static void nfs4_release_lockowner_release(void *calldata)
7333{
Trond Myklebustcf470c32012-03-07 13:49:12 -05007334 struct nfs_release_lockowner_data *data = calldata;
Trond Myklebust5ae67c42012-03-19 16:17:18 -04007335 nfs4_free_lock_state(data->server, data->lsp);
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04007336 kfree(calldata);
7337}
7338
Trond Myklebust17280172012-03-11 13:11:00 -04007339static const struct rpc_call_ops nfs4_release_lockowner_ops = {
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04007340 .rpc_call_prepare = nfs4_release_lockowner_prepare,
7341 .rpc_call_done = nfs4_release_lockowner_done,
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04007342 .rpc_release = nfs4_release_lockowner_release,
7343};
7344
Jeff Laytonf1cdae82014-05-01 06:28:47 -04007345static void
7346nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04007347{
Trond Myklebustcf470c32012-03-07 13:49:12 -05007348 struct nfs_release_lockowner_data *data;
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04007349 struct rpc_message msg = {
7350 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
7351 };
7352
7353 if (server->nfs_client->cl_mvops->minor_version != 0)
Jeff Laytonf1cdae82014-05-01 06:28:47 -04007354 return;
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04007355
Trond Myklebustcf470c32012-03-07 13:49:12 -05007356 data = kmalloc(sizeof(*data), GFP_NOFS);
7357 if (!data)
Jeff Laytonf1cdae82014-05-01 06:28:47 -04007358 return;
Trond Myklebustcf470c32012-03-07 13:49:12 -05007359 data->lsp = lsp;
Trond Myklebust5ae67c42012-03-19 16:17:18 -04007360 data->server = server;
Trond Myklebustcf470c32012-03-07 13:49:12 -05007361 data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
7362 data->args.lock_owner.id = lsp->ls_seqid.owner_id;
7363 data->args.lock_owner.s_dev = server->s_dev;
Chuck Leverfbd4bfd2013-08-09 12:49:38 -04007364
Trond Myklebustcf470c32012-03-07 13:49:12 -05007365 msg.rpc_argp = &data->args;
Trond Myklebustb7e63a12014-02-26 11:19:14 -08007366 msg.rpc_resp = &data->res;
Anna Schumakerfba83f32018-05-04 16:22:50 -04007367 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0);
Trond Myklebustcf470c32012-03-07 13:49:12 -05007368 rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04007369}
7370
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00007371#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
7372
Andreas Gruenbacherd9a82a02015-10-04 19:18:51 +02007373static int nfs4_xattr_set_nfs4_acl(const struct xattr_handler *handler,
Al Viro59301222016-05-27 10:19:30 -04007374 struct dentry *unused, struct inode *inode,
7375 const char *key, const void *buf,
7376 size_t buflen, int flags)
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007377{
Al Viro59301222016-05-27 10:19:30 -04007378 return nfs4_proc_set_acl(inode, buf, buflen);
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007379}
7380
Andreas Gruenbacherd9a82a02015-10-04 19:18:51 +02007381static int nfs4_xattr_get_nfs4_acl(const struct xattr_handler *handler,
Al Virob2968212016-04-10 20:48:24 -04007382 struct dentry *unused, struct inode *inode,
7383 const char *key, void *buf, size_t buflen)
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007384{
Al Virob2968212016-04-10 20:48:24 -04007385 return nfs4_proc_get_acl(inode, buf, buflen);
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007386}
7387
Andreas Gruenbacher764a5c62015-12-02 14:44:43 +01007388static bool nfs4_xattr_list_nfs4_acl(struct dentry *dentry)
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007389{
Andreas Gruenbacher764a5c62015-12-02 14:44:43 +01007390 return nfs4_server_supports_acls(NFS_SERVER(d_inode(dentry)));
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007391}
7392
David Quigleyc9bccef2013-05-22 12:50:45 -04007393#ifdef CONFIG_NFS_V4_SECURITY_LABEL
David Quigleyc9bccef2013-05-22 12:50:45 -04007394
Andreas Gruenbacherd9a82a02015-10-04 19:18:51 +02007395static int nfs4_xattr_set_nfs4_label(const struct xattr_handler *handler,
Al Viro59301222016-05-27 10:19:30 -04007396 struct dentry *unused, struct inode *inode,
7397 const char *key, const void *buf,
7398 size_t buflen, int flags)
David Quigleyc9bccef2013-05-22 12:50:45 -04007399{
7400 if (security_ismaclabel(key))
Al Viro59301222016-05-27 10:19:30 -04007401 return nfs4_set_security_label(inode, buf, buflen);
David Quigleyc9bccef2013-05-22 12:50:45 -04007402
7403 return -EOPNOTSUPP;
7404}
7405
Andreas Gruenbacherd9a82a02015-10-04 19:18:51 +02007406static int nfs4_xattr_get_nfs4_label(const struct xattr_handler *handler,
Al Virob2968212016-04-10 20:48:24 -04007407 struct dentry *unused, struct inode *inode,
7408 const char *key, void *buf, size_t buflen)
David Quigleyc9bccef2013-05-22 12:50:45 -04007409{
7410 if (security_ismaclabel(key))
Al Virob2968212016-04-10 20:48:24 -04007411 return nfs4_get_security_label(inode, buf, buflen);
David Quigleyc9bccef2013-05-22 12:50:45 -04007412 return -EOPNOTSUPP;
7413}
7414
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01007415static ssize_t
7416nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
David Quigleyc9bccef2013-05-22 12:50:45 -04007417{
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01007418 int len = 0;
David Quigleyc9bccef2013-05-22 12:50:45 -04007419
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01007420 if (nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) {
7421 len = security_inode_listsecurity(inode, list, list_len);
7422 if (list_len && len > list_len)
7423 return -ERANGE;
David Quigleyc9bccef2013-05-22 12:50:45 -04007424 }
7425 return len;
7426}
7427
7428static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
7429 .prefix = XATTR_SECURITY_PREFIX,
David Quigleyc9bccef2013-05-22 12:50:45 -04007430 .get = nfs4_xattr_get_nfs4_label,
7431 .set = nfs4_xattr_set_nfs4_label,
7432};
David Quigleyc9bccef2013-05-22 12:50:45 -04007433
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +01007434#else
7435
7436static ssize_t
7437nfs4_listxattr_nfs4_label(struct inode *inode, char *list, size_t list_len)
7438{
7439 return 0;
7440}
7441
7442#endif
David Quigleyc9bccef2013-05-22 12:50:45 -04007443
Frank van der Linden012a2112020-06-23 22:39:03 +00007444#ifdef CONFIG_NFS_V4_2
7445static int nfs4_xattr_set_nfs4_user(const struct xattr_handler *handler,
7446 struct dentry *unused, struct inode *inode,
7447 const char *key, const void *buf,
7448 size_t buflen, int flags)
7449{
7450 struct nfs_access_entry cache;
Frank van der Linden95ad37f2020-06-23 22:39:04 +00007451 int ret;
Frank van der Linden012a2112020-06-23 22:39:03 +00007452
7453 if (!nfs_server_capable(inode, NFS_CAP_XATTR))
7454 return -EOPNOTSUPP;
7455
7456 /*
7457 * There is no mapping from the MAY_* flags to the NFS_ACCESS_XA*
7458 * flags right now. Handling of xattr operations use the normal
7459 * file read/write permissions.
7460 *
7461 * Just in case the server has other ideas (which RFC 8276 allows),
7462 * do a cached access check for the XA* flags to possibly avoid
7463 * doing an RPC and getting EACCES back.
7464 */
7465 if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
7466 if (!(cache.mask & NFS_ACCESS_XAWRITE))
7467 return -EACCES;
7468 }
7469
Frank van der Linden95ad37f2020-06-23 22:39:04 +00007470 if (buf == NULL) {
7471 ret = nfs42_proc_removexattr(inode, key);
7472 if (!ret)
7473 nfs4_xattr_cache_remove(inode, key);
7474 } else {
7475 ret = nfs42_proc_setxattr(inode, key, buf, buflen, flags);
7476 if (!ret)
7477 nfs4_xattr_cache_add(inode, key, buf, NULL, buflen);
7478 }
7479
7480 return ret;
Frank van der Linden012a2112020-06-23 22:39:03 +00007481}
7482
7483static int nfs4_xattr_get_nfs4_user(const struct xattr_handler *handler,
7484 struct dentry *unused, struct inode *inode,
7485 const char *key, void *buf, size_t buflen)
7486{
7487 struct nfs_access_entry cache;
Frank van der Linden95ad37f2020-06-23 22:39:04 +00007488 ssize_t ret;
Frank van der Linden012a2112020-06-23 22:39:03 +00007489
7490 if (!nfs_server_capable(inode, NFS_CAP_XATTR))
7491 return -EOPNOTSUPP;
7492
7493 if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
7494 if (!(cache.mask & NFS_ACCESS_XAREAD))
7495 return -EACCES;
7496 }
7497
Frank van der Linden95ad37f2020-06-23 22:39:04 +00007498 ret = nfs_revalidate_inode(NFS_SERVER(inode), inode);
7499 if (ret)
7500 return ret;
7501
7502 ret = nfs4_xattr_cache_get(inode, key, buf, buflen);
7503 if (ret >= 0 || (ret < 0 && ret != -ENOENT))
7504 return ret;
7505
7506 ret = nfs42_proc_getxattr(inode, key, buf, buflen);
7507
7508 return ret;
Frank van der Linden012a2112020-06-23 22:39:03 +00007509}
7510
7511static ssize_t
7512nfs4_listxattr_nfs4_user(struct inode *inode, char *list, size_t list_len)
7513{
7514 u64 cookie;
7515 bool eof;
Frank van der Linden95ad37f2020-06-23 22:39:04 +00007516 ssize_t ret, size;
Frank van der Linden012a2112020-06-23 22:39:03 +00007517 char *buf;
7518 size_t buflen;
7519 struct nfs_access_entry cache;
7520
7521 if (!nfs_server_capable(inode, NFS_CAP_XATTR))
7522 return 0;
7523
7524 if (!nfs_access_get_cached(inode, current_cred(), &cache, true)) {
7525 if (!(cache.mask & NFS_ACCESS_XALIST))
7526 return 0;
7527 }
7528
Frank van der Linden95ad37f2020-06-23 22:39:04 +00007529 ret = nfs_revalidate_inode(NFS_SERVER(inode), inode);
7530 if (ret)
7531 return ret;
7532
7533 ret = nfs4_xattr_cache_list(inode, list, list_len);
7534 if (ret >= 0 || (ret < 0 && ret != -ENOENT))
7535 return ret;
7536
Frank van der Linden012a2112020-06-23 22:39:03 +00007537 cookie = 0;
7538 eof = false;
7539 buflen = list_len ? list_len : XATTR_LIST_MAX;
7540 buf = list_len ? list : NULL;
7541 size = 0;
7542
7543 while (!eof) {
7544 ret = nfs42_proc_listxattrs(inode, buf, buflen,
7545 &cookie, &eof);
7546 if (ret < 0)
7547 return ret;
7548
7549 if (list_len) {
7550 buf += ret;
7551 buflen -= ret;
7552 }
7553 size += ret;
7554 }
7555
Frank van der Linden95ad37f2020-06-23 22:39:04 +00007556 if (list_len)
7557 nfs4_xattr_cache_set_list(inode, list, size);
7558
Frank van der Linden012a2112020-06-23 22:39:03 +00007559 return size;
7560}
7561
7562#else
7563
7564static ssize_t
7565nfs4_listxattr_nfs4_user(struct inode *inode, char *list, size_t list_len)
7566{
7567 return 0;
7568}
7569#endif /* CONFIG_NFS_V4_2 */
7570
Andy Adamson533eb462011-06-13 18:25:56 -04007571/*
7572 * nfs_fhget will use either the mounted_on_fileid or the fileid
7573 */
Trond Myklebust69aaaae2009-03-11 14:10:28 -04007574static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
7575{
Andy Adamson533eb462011-06-13 18:25:56 -04007576 if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) ||
7577 (fattr->valid & NFS_ATTR_FATTR_FILEID)) &&
7578 (fattr->valid & NFS_ATTR_FATTR_FSID) &&
Chuck Lever81934dd2012-03-01 17:01:57 -05007579 (fattr->valid & NFS_ATTR_FATTR_V4_LOCATIONS)))
Trond Myklebust69aaaae2009-03-11 14:10:28 -04007580 return;
7581
7582 fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
Chuck Lever81934dd2012-03-01 17:01:57 -05007583 NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_V4_REFERRAL;
Trond Myklebust69aaaae2009-03-11 14:10:28 -04007584 fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
7585 fattr->nlink = 2;
7586}
7587
Bryan Schumakerf05d1472012-04-27 13:27:41 -04007588static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
7589 const struct qstr *name,
7590 struct nfs4_fs_locations *fs_locations,
7591 struct page *page)
Trond Myklebust683b57b2006-06-09 09:34:22 -04007592{
7593 struct nfs_server *server = NFS_SERVER(dir);
Chuck Leverc05cefc2017-11-05 15:45:22 -05007594 u32 bitmask[3];
Trond Myklebust683b57b2006-06-09 09:34:22 -04007595 struct nfs4_fs_locations_arg args = {
7596 .dir_fh = NFS_FH(dir),
Trond Myklebustc228fd32007-01-13 02:28:11 -05007597 .name = name,
Trond Myklebust683b57b2006-06-09 09:34:22 -04007598 .page = page,
7599 .bitmask = bitmask,
7600 };
Benny Halevy22958462009-04-01 09:22:02 -04007601 struct nfs4_fs_locations_res res = {
7602 .fs_locations = fs_locations,
7603 };
Trond Myklebust683b57b2006-06-09 09:34:22 -04007604 struct rpc_message msg = {
7605 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
7606 .rpc_argp = &args,
Benny Halevy22958462009-04-01 09:22:02 -04007607 .rpc_resp = &res,
Trond Myklebust683b57b2006-06-09 09:34:22 -04007608 };
7609 int status;
7610
Harvey Harrison3110ff82008-05-02 13:42:44 -07007611 dprintk("%s: start\n", __func__);
Andy Adamson533eb462011-06-13 18:25:56 -04007612
Chuck Leverc05cefc2017-11-05 15:45:22 -05007613 bitmask[0] = nfs4_fattr_bitmap[0] | FATTR4_WORD0_FS_LOCATIONS;
7614 bitmask[1] = nfs4_fattr_bitmap[1];
7615
Andy Adamson533eb462011-06-13 18:25:56 -04007616 /* Ask for the fileid of the absent filesystem if mounted_on_fileid
7617 * is not supported */
7618 if (NFS_SERVER(dir)->attr_bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
Chuck Leverc05cefc2017-11-05 15:45:22 -05007619 bitmask[0] &= ~FATTR4_WORD0_FILEID;
Andy Adamson533eb462011-06-13 18:25:56 -04007620 else
Chuck Leverc05cefc2017-11-05 15:45:22 -05007621 bitmask[1] &= ~FATTR4_WORD1_MOUNTED_ON_FILEID;
Andy Adamson533eb462011-06-13 18:25:56 -04007622
Trond Myklebustc228fd32007-01-13 02:28:11 -05007623 nfs_fattr_init(&fs_locations->fattr);
Trond Myklebust683b57b2006-06-09 09:34:22 -04007624 fs_locations->server = server;
Manoj Naik830b8e32006-06-09 09:34:25 -04007625 fs_locations->nlocations = 0;
Bryan Schumakerf05d1472012-04-27 13:27:41 -04007626 status = nfs4_call_sync(client, server, &msg, &args.seq_args, &res.seq_res, 0);
Harvey Harrison3110ff82008-05-02 13:42:44 -07007627 dprintk("%s: returned status = %d\n", __func__, status);
Trond Myklebust683b57b2006-06-09 09:34:22 -04007628 return status;
7629}
7630
Bryan Schumakerf05d1472012-04-27 13:27:41 -04007631int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
7632 const struct qstr *name,
7633 struct nfs4_fs_locations *fs_locations,
7634 struct page *page)
Bryan Schumakerdb0a9592012-04-27 13:27:39 -04007635{
Trond Myklebust0688e642019-04-07 13:59:09 -04007636 struct nfs4_exception exception = {
7637 .interruptible = true,
7638 };
Bryan Schumakerdb0a9592012-04-27 13:27:39 -04007639 int err;
7640 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04007641 err = _nfs4_proc_fs_locations(client, dir, name,
7642 fs_locations, page);
7643 trace_nfs4_get_fs_locations(dir, name, err);
7644 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Bryan Schumakerdb0a9592012-04-27 13:27:39 -04007645 &exception);
7646 } while (exception.retry);
7647 return err;
7648}
7649
Chuck Leverb03d7352013-10-17 14:12:50 -04007650/*
7651 * This operation also signals the server that this client is
7652 * performing migration recovery. The server can stop returning
7653 * NFS4ERR_LEASE_MOVED to this client. A RENEW operation is
7654 * appended to this compound to identify the client ID which is
7655 * performing recovery.
7656 */
7657static int _nfs40_proc_get_locations(struct inode *inode,
7658 struct nfs4_fs_locations *locations,
NeilBrowna52458b2018-12-03 11:30:31 +11007659 struct page *page, const struct cred *cred)
Chuck Leverb03d7352013-10-17 14:12:50 -04007660{
7661 struct nfs_server *server = NFS_SERVER(inode);
7662 struct rpc_clnt *clnt = server->client;
7663 u32 bitmask[2] = {
7664 [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
7665 };
7666 struct nfs4_fs_locations_arg args = {
7667 .clientid = server->nfs_client->cl_clientid,
7668 .fh = NFS_FH(inode),
7669 .page = page,
7670 .bitmask = bitmask,
7671 .migration = 1, /* skip LOOKUP */
7672 .renew = 1, /* append RENEW */
7673 };
7674 struct nfs4_fs_locations_res res = {
7675 .fs_locations = locations,
7676 .migration = 1,
7677 .renew = 1,
7678 };
7679 struct rpc_message msg = {
7680 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
7681 .rpc_argp = &args,
7682 .rpc_resp = &res,
7683 .rpc_cred = cred,
7684 };
7685 unsigned long now = jiffies;
7686 int status;
7687
7688 nfs_fattr_init(&locations->fattr);
7689 locations->server = server;
7690 locations->nlocations = 0;
7691
Anna Schumakerfba83f32018-05-04 16:22:50 -04007692 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1);
Chuck Leverb03d7352013-10-17 14:12:50 -04007693 status = nfs4_call_sync_sequence(clnt, server, &msg,
7694 &args.seq_args, &res.seq_res);
7695 if (status)
7696 return status;
7697
7698 renew_lease(server, now);
7699 return 0;
7700}
7701
7702#ifdef CONFIG_NFS_V4_1
7703
7704/*
7705 * This operation also signals the server that this client is
7706 * performing migration recovery. The server can stop asserting
7707 * SEQ4_STATUS_LEASE_MOVED for this client. The client ID
7708 * performing this operation is identified in the SEQUENCE
7709 * operation in this compound.
7710 *
7711 * When the client supports GETATTR(fs_locations_info), it can
7712 * be plumbed in here.
7713 */
7714static int _nfs41_proc_get_locations(struct inode *inode,
7715 struct nfs4_fs_locations *locations,
NeilBrowna52458b2018-12-03 11:30:31 +11007716 struct page *page, const struct cred *cred)
Chuck Leverb03d7352013-10-17 14:12:50 -04007717{
7718 struct nfs_server *server = NFS_SERVER(inode);
7719 struct rpc_clnt *clnt = server->client;
7720 u32 bitmask[2] = {
7721 [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
7722 };
7723 struct nfs4_fs_locations_arg args = {
7724 .fh = NFS_FH(inode),
7725 .page = page,
7726 .bitmask = bitmask,
7727 .migration = 1, /* skip LOOKUP */
7728 };
7729 struct nfs4_fs_locations_res res = {
7730 .fs_locations = locations,
7731 .migration = 1,
7732 };
7733 struct rpc_message msg = {
7734 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
7735 .rpc_argp = &args,
7736 .rpc_resp = &res,
7737 .rpc_cred = cred,
7738 };
7739 int status;
7740
7741 nfs_fattr_init(&locations->fattr);
7742 locations->server = server;
7743 locations->nlocations = 0;
7744
Anna Schumakerfba83f32018-05-04 16:22:50 -04007745 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1);
Chuck Leverb03d7352013-10-17 14:12:50 -04007746 status = nfs4_call_sync_sequence(clnt, server, &msg,
7747 &args.seq_args, &res.seq_res);
7748 if (status == NFS4_OK &&
7749 res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED)
7750 status = -NFS4ERR_LEASE_MOVED;
7751 return status;
7752}
7753
7754#endif /* CONFIG_NFS_V4_1 */
7755
7756/**
7757 * nfs4_proc_get_locations - discover locations for a migrated FSID
7758 * @inode: inode on FSID that is migrating
7759 * @locations: result of query
7760 * @page: buffer
7761 * @cred: credential to use for this operation
7762 *
7763 * Returns NFS4_OK on success, a negative NFS4ERR status code if the
7764 * operation failed, or a negative errno if a local error occurred.
7765 *
7766 * On success, "locations" is filled in, but if the server has
7767 * no locations information, NFS_ATTR_FATTR_V4_LOCATIONS is not
7768 * asserted.
7769 *
7770 * -NFS4ERR_LEASE_MOVED is returned if the server still has leases
7771 * from this client that require migration recovery.
7772 */
7773int nfs4_proc_get_locations(struct inode *inode,
7774 struct nfs4_fs_locations *locations,
NeilBrowna52458b2018-12-03 11:30:31 +11007775 struct page *page, const struct cred *cred)
Chuck Leverb03d7352013-10-17 14:12:50 -04007776{
7777 struct nfs_server *server = NFS_SERVER(inode);
7778 struct nfs_client *clp = server->nfs_client;
7779 const struct nfs4_mig_recovery_ops *ops =
7780 clp->cl_mvops->mig_recovery_ops;
Trond Myklebust0688e642019-04-07 13:59:09 -04007781 struct nfs4_exception exception = {
7782 .interruptible = true,
7783 };
Chuck Leverb03d7352013-10-17 14:12:50 -04007784 int status;
7785
7786 dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
7787 (unsigned long long)server->fsid.major,
7788 (unsigned long long)server->fsid.minor,
7789 clp->cl_hostname);
7790 nfs_display_fhandle(NFS_FH(inode), __func__);
7791
7792 do {
7793 status = ops->get_locations(inode, locations, page, cred);
7794 if (status != -NFS4ERR_DELAY)
7795 break;
7796 nfs4_handle_exception(server, status, &exception);
7797 } while (exception.retry);
7798 return status;
7799}
7800
Chuck Lever44c99932013-10-17 14:13:30 -04007801/*
7802 * This operation also signals the server that this client is
7803 * performing "lease moved" recovery. The server can stop
7804 * returning NFS4ERR_LEASE_MOVED to this client. A RENEW operation
7805 * is appended to this compound to identify the client ID which is
7806 * performing recovery.
7807 */
NeilBrowna52458b2018-12-03 11:30:31 +11007808static int _nfs40_proc_fsid_present(struct inode *inode, const struct cred *cred)
Chuck Lever44c99932013-10-17 14:13:30 -04007809{
7810 struct nfs_server *server = NFS_SERVER(inode);
7811 struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
7812 struct rpc_clnt *clnt = server->client;
7813 struct nfs4_fsid_present_arg args = {
7814 .fh = NFS_FH(inode),
7815 .clientid = clp->cl_clientid,
7816 .renew = 1, /* append RENEW */
7817 };
7818 struct nfs4_fsid_present_res res = {
7819 .renew = 1,
7820 };
7821 struct rpc_message msg = {
7822 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSID_PRESENT],
7823 .rpc_argp = &args,
7824 .rpc_resp = &res,
7825 .rpc_cred = cred,
7826 };
7827 unsigned long now = jiffies;
7828 int status;
7829
7830 res.fh = nfs_alloc_fhandle();
7831 if (res.fh == NULL)
7832 return -ENOMEM;
7833
Anna Schumakerfba83f32018-05-04 16:22:50 -04007834 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1);
Chuck Lever44c99932013-10-17 14:13:30 -04007835 status = nfs4_call_sync_sequence(clnt, server, &msg,
7836 &args.seq_args, &res.seq_res);
7837 nfs_free_fhandle(res.fh);
7838 if (status)
7839 return status;
7840
7841 do_renew_lease(clp, now);
7842 return 0;
7843}
7844
7845#ifdef CONFIG_NFS_V4_1
7846
7847/*
7848 * This operation also signals the server that this client is
7849 * performing "lease moved" recovery. The server can stop asserting
7850 * SEQ4_STATUS_LEASE_MOVED for this client. The client ID performing
7851 * this operation is identified in the SEQUENCE operation in this
7852 * compound.
7853 */
NeilBrowna52458b2018-12-03 11:30:31 +11007854static int _nfs41_proc_fsid_present(struct inode *inode, const struct cred *cred)
Chuck Lever44c99932013-10-17 14:13:30 -04007855{
7856 struct nfs_server *server = NFS_SERVER(inode);
7857 struct rpc_clnt *clnt = server->client;
7858 struct nfs4_fsid_present_arg args = {
7859 .fh = NFS_FH(inode),
7860 };
7861 struct nfs4_fsid_present_res res = {
7862 };
7863 struct rpc_message msg = {
7864 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSID_PRESENT],
7865 .rpc_argp = &args,
7866 .rpc_resp = &res,
7867 .rpc_cred = cred,
7868 };
7869 int status;
7870
7871 res.fh = nfs_alloc_fhandle();
7872 if (res.fh == NULL)
7873 return -ENOMEM;
7874
Anna Schumakerfba83f32018-05-04 16:22:50 -04007875 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1);
Chuck Lever44c99932013-10-17 14:13:30 -04007876 status = nfs4_call_sync_sequence(clnt, server, &msg,
7877 &args.seq_args, &res.seq_res);
7878 nfs_free_fhandle(res.fh);
7879 if (status == NFS4_OK &&
7880 res.seq_res.sr_status_flags & SEQ4_STATUS_LEASE_MOVED)
7881 status = -NFS4ERR_LEASE_MOVED;
7882 return status;
7883}
7884
7885#endif /* CONFIG_NFS_V4_1 */
7886
7887/**
7888 * nfs4_proc_fsid_present - Is this FSID present or absent on server?
7889 * @inode: inode on FSID to check
7890 * @cred: credential to use for this operation
7891 *
7892 * Server indicates whether the FSID is present, moved, or not
7893 * recognized. This operation is necessary to clear a LEASE_MOVED
7894 * condition for this client ID.
7895 *
7896 * Returns NFS4_OK if the FSID is present on this server,
7897 * -NFS4ERR_MOVED if the FSID is no longer present, a negative
7898 * NFS4ERR code if some error occurred on the server, or a
7899 * negative errno if a local failure occurred.
7900 */
NeilBrowna52458b2018-12-03 11:30:31 +11007901int nfs4_proc_fsid_present(struct inode *inode, const struct cred *cred)
Chuck Lever44c99932013-10-17 14:13:30 -04007902{
7903 struct nfs_server *server = NFS_SERVER(inode);
7904 struct nfs_client *clp = server->nfs_client;
7905 const struct nfs4_mig_recovery_ops *ops =
7906 clp->cl_mvops->mig_recovery_ops;
Trond Myklebust0688e642019-04-07 13:59:09 -04007907 struct nfs4_exception exception = {
7908 .interruptible = true,
7909 };
Chuck Lever44c99932013-10-17 14:13:30 -04007910 int status;
7911
7912 dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
7913 (unsigned long long)server->fsid.major,
7914 (unsigned long long)server->fsid.minor,
7915 clp->cl_hostname);
7916 nfs_display_fhandle(NFS_FH(inode), __func__);
7917
7918 do {
7919 status = ops->fsid_present(inode, cred);
7920 if (status != -NFS4ERR_DELAY)
7921 break;
7922 nfs4_handle_exception(server, status, &exception);
7923 } while (exception.retry);
7924 return status;
7925}
7926
Trond Myklebust302fad72019-02-18 13:32:38 -05007927/*
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007928 * If 'use_integrity' is true and the state managment nfs_client
7929 * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient
7930 * and the machine credential as per RFC3530bis and RFC5661 Security
7931 * Considerations sections. Otherwise, just use the user cred with the
7932 * filesystem's rpc_client.
Andy Adamson5ec16a82013-08-08 10:57:55 -04007933 */
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007934static 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 +00007935{
7936 int status;
Anna Schumaker50493362019-08-14 15:30:16 -04007937 struct rpc_clnt *clnt = NFS_SERVER(dir)->client;
7938 struct nfs_client *clp = NFS_SERVER(dir)->nfs_client;
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007939 struct nfs4_secinfo_arg args = {
7940 .dir_fh = NFS_FH(dir),
7941 .name = name,
7942 };
7943 struct nfs4_secinfo_res res = {
7944 .flavors = flavors,
7945 };
7946 struct rpc_message msg = {
7947 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO],
7948 .rpc_argp = &args,
7949 .rpc_resp = &res,
7950 };
Anna Schumaker50493362019-08-14 15:30:16 -04007951 struct nfs4_call_sync_data data = {
7952 .seq_server = NFS_SERVER(dir),
7953 .seq_args = &args.seq_args,
7954 .seq_res = &res.seq_res,
7955 };
7956 struct rpc_task_setup task_setup = {
7957 .rpc_client = clnt,
7958 .rpc_message = &msg,
7959 .callback_ops = clp->cl_mvops->call_sync_ops,
7960 .callback_data = &data,
7961 .flags = RPC_TASK_NO_ROUND_ROBIN,
7962 };
NeilBrowna52458b2018-12-03 11:30:31 +11007963 const struct cred *cred = NULL;
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007964
7965 if (use_integrity) {
Anna Schumaker50493362019-08-14 15:30:16 -04007966 clnt = clp->cl_rpcclient;
7967 task_setup.rpc_client = clnt;
7968
7969 cred = nfs4_get_clid_cred(clp);
Weston Andros Adamson7cb852d2013-09-10 18:44:31 -04007970 msg.rpc_cred = cred;
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007971 }
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007972
7973 dprintk("NFS call secinfo %s\n", name->name);
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04007974
Anna Schumaker50493362019-08-14 15:30:16 -04007975 nfs4_state_protect(clp, NFS_SP4_MACH_CRED_SECINFO, &clnt, &msg);
7976 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
7977 status = nfs4_call_sync_custom(&task_setup);
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04007978
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007979 dprintk("NFS reply secinfo: %d\n", status);
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007980
NeilBrowna52458b2018-12-03 11:30:31 +11007981 put_cred(cred);
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007982 return status;
7983}
7984
Bryan Schumaker72de53e2012-04-27 13:27:40 -04007985int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
7986 struct nfs4_secinfo_flavors *flavors)
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007987{
Trond Myklebust0688e642019-04-07 13:59:09 -04007988 struct nfs4_exception exception = {
7989 .interruptible = true,
7990 };
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00007991 int err;
7992 do {
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04007993 err = -NFS4ERR_WRONGSEC;
7994
7995 /* try to use integrity protection with machine cred */
7996 if (_nfs4_is_integrity_protected(NFS_SERVER(dir)->nfs_client))
7997 err = _nfs4_proc_secinfo(dir, name, flavors, true);
7998
7999 /*
8000 * if unable to use integrity protection, or SECINFO with
8001 * integrity protection returns NFS4ERR_WRONGSEC (which is
8002 * disallowed by spec, but exists in deployed servers) use
8003 * the current filesystem's rpc_client and the user cred.
8004 */
8005 if (err == -NFS4ERR_WRONGSEC)
8006 err = _nfs4_proc_secinfo(dir, name, flavors, false);
8007
Trond Myklebust078ea3d2013-08-12 16:45:55 -04008008 trace_nfs4_secinfo(dir, name, err);
8009 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00008010 &exception);
8011 } while (exception.retry);
8012 return err;
8013}
8014
Andy Adamson557134a2009-04-01 09:21:53 -04008015#ifdef CONFIG_NFS_V4_1
Benny Halevy99fe60d2009-04-01 09:22:29 -04008016/*
Andy Adamson357f54d2010-12-14 10:11:57 -05008017 * Check the exchange flags returned by the server for invalid flags, having
8018 * both PNFS and NON_PNFS flags set, and not having one of NON_PNFS, PNFS, or
8019 * DS flags set.
8020 */
8021static int nfs4_check_cl_exchange_flags(u32 flags)
8022{
8023 if (flags & ~EXCHGID4_FLAG_MASK_R)
8024 goto out_inval;
8025 if ((flags & EXCHGID4_FLAG_USE_PNFS_MDS) &&
8026 (flags & EXCHGID4_FLAG_USE_NON_PNFS))
8027 goto out_inval;
8028 if (!(flags & (EXCHGID4_FLAG_MASK_PNFS)))
8029 goto out_inval;
8030 return NFS_OK;
8031out_inval:
8032 return -NFS4ERR_INVAL;
8033}
8034
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04008035static bool
Chuck Lever79d4e1f2012-05-21 22:44:31 -04008036nfs41_same_server_scope(struct nfs41_server_scope *a,
8037 struct nfs41_server_scope *b)
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04008038{
Anna Schumaker49ad0142017-01-11 16:51:59 -05008039 if (a->server_scope_sz != b->server_scope_sz)
8040 return false;
8041 return memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0;
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04008042}
8043
Andy Adamson02a95de2016-02-05 16:08:37 -05008044static void
8045nfs4_bind_one_conn_to_session_done(struct rpc_task *task, void *calldata)
8046{
Trond Myklebust5c441542019-11-13 08:34:00 +01008047 struct nfs41_bind_conn_to_session_args *args = task->tk_msg.rpc_argp;
Olga Kornievskaiadff58532020-04-24 17:45:50 -04008048 struct nfs41_bind_conn_to_session_res *res = task->tk_msg.rpc_resp;
Trond Myklebust5c441542019-11-13 08:34:00 +01008049 struct nfs_client *clp = args->client;
8050
8051 switch (task->tk_status) {
8052 case -NFS4ERR_BADSESSION:
8053 case -NFS4ERR_DEADSESSION:
8054 nfs4_schedule_session_recovery(clp->cl_session,
8055 task->tk_status);
8056 }
Olga Kornievskaiadff58532020-04-24 17:45:50 -04008057 if (args->dir == NFS4_CDFC4_FORE_OR_BOTH &&
8058 res->dir != NFS4_CDFS4_BOTH) {
8059 rpc_task_close_connection(task);
8060 if (args->retries++ < MAX_BIND_CONN_TO_SESSION_RETRIES)
8061 rpc_restart_call(task);
8062 }
Andy Adamson02a95de2016-02-05 16:08:37 -05008063}
8064
8065static const struct rpc_call_ops nfs4_bind_one_conn_to_session_ops = {
Olga Kornievskaia1c709b72020-04-26 11:30:00 -04008066 .rpc_call_done = nfs4_bind_one_conn_to_session_done,
Andy Adamson02a95de2016-02-05 16:08:37 -05008067};
8068
Andy Adamson357f54d2010-12-14 10:11:57 -05008069/*
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05008070 * nfs4_proc_bind_one_conn_to_session()
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008071 *
8072 * The 4.1 client currently uses the same TCP connection for the
8073 * fore and backchannel.
8074 */
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05008075static
8076int nfs4_proc_bind_one_conn_to_session(struct rpc_clnt *clnt,
8077 struct rpc_xprt *xprt,
8078 struct nfs_client *clp,
NeilBrowna52458b2018-12-03 11:30:31 +11008079 const struct cred *cred)
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008080{
8081 int status;
Trond Myklebust71a097c2015-02-18 09:27:18 -08008082 struct nfs41_bind_conn_to_session_args args = {
8083 .client = clp,
8084 .dir = NFS4_CDFC4_FORE_OR_BOTH,
Olga Kornievskaiadff58532020-04-24 17:45:50 -04008085 .retries = 0,
Trond Myklebust71a097c2015-02-18 09:27:18 -08008086 };
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008087 struct nfs41_bind_conn_to_session_res res;
8088 struct rpc_message msg = {
8089 .rpc_proc =
8090 &nfs4_procedures[NFSPROC4_CLNT_BIND_CONN_TO_SESSION],
Trond Myklebust71a097c2015-02-18 09:27:18 -08008091 .rpc_argp = &args,
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008092 .rpc_resp = &res,
Trond Myklebust2cf047c2012-05-25 17:57:41 -04008093 .rpc_cred = cred,
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008094 };
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05008095 struct rpc_task_setup task_setup_data = {
8096 .rpc_client = clnt,
8097 .rpc_xprt = xprt,
Andy Adamson02a95de2016-02-05 16:08:37 -05008098 .callback_ops = &nfs4_bind_one_conn_to_session_ops,
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05008099 .rpc_message = &msg,
8100 .flags = RPC_TASK_TIMEOUT,
8101 };
8102 struct rpc_task *task;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008103
Trond Myklebust71a097c2015-02-18 09:27:18 -08008104 nfs4_copy_sessionid(&args.sessionid, &clp->cl_session->sess_id);
8105 if (!(clp->cl_session->flags & SESSION4_BACK_CHAN))
8106 args.dir = NFS4_CDFC4_FORE;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008107
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05008108 /* Do not set the backchannel flag unless this is clnt->cl_xprt */
8109 if (xprt != rcu_access_pointer(clnt->cl_xprt))
8110 args.dir = NFS4_CDFC4_FORE;
8111
8112 task = rpc_run_task(&task_setup_data);
8113 if (!IS_ERR(task)) {
8114 status = task->tk_status;
8115 rpc_put_task(task);
8116 } else
8117 status = PTR_ERR(task);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04008118 trace_nfs4_bind_conn_to_session(clp, status);
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008119 if (status == 0) {
Trond Myklebust71a097c2015-02-18 09:27:18 -08008120 if (memcmp(res.sessionid.data,
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008121 clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) {
8122 dprintk("NFS: %s: Session ID mismatch\n", __func__);
Anna Schumakerc7ae7632017-04-07 14:15:21 -04008123 return -EIO;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008124 }
Trond Myklebust71a097c2015-02-18 09:27:18 -08008125 if ((res.dir & args.dir) != res.dir || res.dir == 0) {
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008126 dprintk("NFS: %s: Unexpected direction from server\n",
8127 __func__);
Anna Schumakerc7ae7632017-04-07 14:15:21 -04008128 return -EIO;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008129 }
Trond Myklebust71a097c2015-02-18 09:27:18 -08008130 if (res.use_conn_in_rdma_mode != args.use_conn_in_rdma_mode) {
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008131 dprintk("NFS: %s: Server returned RDMA mode = true\n",
8132 __func__);
Anna Schumakerc7ae7632017-04-07 14:15:21 -04008133 return -EIO;
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008134 }
8135 }
Anna Schumakerc7ae7632017-04-07 14:15:21 -04008136
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008137 return status;
8138}
8139
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05008140struct rpc_bind_conn_calldata {
8141 struct nfs_client *clp;
NeilBrowna52458b2018-12-03 11:30:31 +11008142 const struct cred *cred;
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05008143};
8144
8145static int
8146nfs4_proc_bind_conn_to_session_callback(struct rpc_clnt *clnt,
8147 struct rpc_xprt *xprt,
8148 void *calldata)
8149{
8150 struct rpc_bind_conn_calldata *p = calldata;
8151
8152 return nfs4_proc_bind_one_conn_to_session(clnt, xprt, p->clp, p->cred);
8153}
8154
NeilBrowna52458b2018-12-03 11:30:31 +11008155int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, const struct cred *cred)
Trond Myklebustd9ddbf52016-01-30 22:58:24 -05008156{
8157 struct rpc_bind_conn_calldata data = {
8158 .clp = clp,
8159 .cred = cred,
8160 };
8161 return rpc_clnt_iterate_for_each_xprt(clp->cl_rpcclient,
8162 nfs4_proc_bind_conn_to_session_callback, &data);
8163}
8164
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04008165/*
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04008166 * Minimum set of SP4_MACH_CRED operations from RFC 5661 in the enforce map
8167 * and operations we'd like to see to enable certain features in the allow map
Benny Halevy99fe60d2009-04-01 09:22:29 -04008168 */
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008169static const struct nfs41_state_protection nfs4_sp4_mach_cred_request = {
8170 .how = SP4_MACH_CRED,
8171 .enforce.u.words = {
8172 [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
8173 1 << (OP_EXCHANGE_ID - 32) |
8174 1 << (OP_CREATE_SESSION - 32) |
8175 1 << (OP_DESTROY_SESSION - 32) |
8176 1 << (OP_DESTROY_CLIENTID - 32)
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04008177 },
8178 .allow.u.words = {
8179 [0] = 1 << (OP_CLOSE) |
Andrew Elble99ade3c2015-12-02 09:39:51 -05008180 1 << (OP_OPEN_DOWNGRADE) |
Weston Andros Adamsona0279622013-09-10 18:44:30 -04008181 1 << (OP_LOCKU) |
Andrew Elble99ade3c2015-12-02 09:39:51 -05008182 1 << (OP_DELEGRETURN) |
Weston Andros Adamsona0279622013-09-10 18:44:30 -04008183 1 << (OP_COMMIT),
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04008184 [1] = 1 << (OP_SECINFO - 32) |
Weston Andros Adamson3787d502013-08-13 16:37:36 -04008185 1 << (OP_SECINFO_NO_NAME - 32) |
Andrew Elble99ade3c2015-12-02 09:39:51 -05008186 1 << (OP_LAYOUTRETURN - 32) |
Weston Andros Adamson3787d502013-08-13 16:37:36 -04008187 1 << (OP_TEST_STATEID - 32) |
Weston Andros Adamsona0279622013-09-10 18:44:30 -04008188 1 << (OP_FREE_STATEID - 32) |
8189 1 << (OP_WRITE - 32)
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008190 }
8191};
8192
8193/*
8194 * Select the state protection mode for client `clp' given the server results
8195 * from exchange_id in `sp'.
8196 *
8197 * Returns 0 on success, negative errno otherwise.
8198 */
8199static int nfs4_sp4_select_mode(struct nfs_client *clp,
8200 struct nfs41_state_protection *sp)
8201{
8202 static const u32 supported_enforce[NFS4_OP_MAP_NUM_WORDS] = {
8203 [1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
8204 1 << (OP_EXCHANGE_ID - 32) |
8205 1 << (OP_CREATE_SESSION - 32) |
8206 1 << (OP_DESTROY_SESSION - 32) |
8207 1 << (OP_DESTROY_CLIENTID - 32)
8208 };
Trond Myklebust937e3132017-08-01 07:32:50 -04008209 unsigned long flags = 0;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008210 unsigned int i;
Trond Myklebust937e3132017-08-01 07:32:50 -04008211 int ret = 0;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008212
8213 if (sp->how == SP4_MACH_CRED) {
8214 /* Print state protect result */
8215 dfprintk(MOUNT, "Server SP4_MACH_CRED support:\n");
8216 for (i = 0; i <= LAST_NFS4_OP; i++) {
8217 if (test_bit(i, sp->enforce.u.longs))
8218 dfprintk(MOUNT, " enforce op %d\n", i);
8219 if (test_bit(i, sp->allow.u.longs))
8220 dfprintk(MOUNT, " allow op %d\n", i);
8221 }
8222
8223 /* make sure nothing is on enforce list that isn't supported */
8224 for (i = 0; i < NFS4_OP_MAP_NUM_WORDS; i++) {
8225 if (sp->enforce.u.words[i] & ~supported_enforce[i]) {
8226 dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04008227 ret = -EINVAL;
8228 goto out;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008229 }
8230 }
8231
8232 /*
8233 * Minimal mode - state operations are allowed to use machine
8234 * credential. Note this already happens by default, so the
8235 * client doesn't have to do anything more than the negotiation.
8236 *
8237 * NOTE: we don't care if EXCHANGE_ID is in the list -
8238 * we're already using the machine cred for exchange_id
8239 * and will never use a different cred.
8240 */
8241 if (test_bit(OP_BIND_CONN_TO_SESSION, sp->enforce.u.longs) &&
8242 test_bit(OP_CREATE_SESSION, sp->enforce.u.longs) &&
8243 test_bit(OP_DESTROY_SESSION, sp->enforce.u.longs) &&
8244 test_bit(OP_DESTROY_CLIENTID, sp->enforce.u.longs)) {
8245 dfprintk(MOUNT, "sp4_mach_cred:\n");
8246 dfprintk(MOUNT, " minimal mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04008247 __set_bit(NFS_SP4_MACH_CRED_MINIMAL, &flags);
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008248 } else {
8249 dfprintk(MOUNT, "sp4_mach_cred: disabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04008250 ret = -EINVAL;
8251 goto out;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008252 }
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04008253
8254 if (test_bit(OP_CLOSE, sp->allow.u.longs) &&
Andrew Elble99ade3c2015-12-02 09:39:51 -05008255 test_bit(OP_OPEN_DOWNGRADE, sp->allow.u.longs) &&
8256 test_bit(OP_DELEGRETURN, sp->allow.u.longs) &&
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04008257 test_bit(OP_LOCKU, sp->allow.u.longs)) {
8258 dfprintk(MOUNT, " cleanup mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04008259 __set_bit(NFS_SP4_MACH_CRED_CLEANUP, &flags);
Weston Andros Adamsonfa940722013-08-13 16:37:34 -04008260 }
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04008261
Andrew Elble99ade3c2015-12-02 09:39:51 -05008262 if (test_bit(OP_LAYOUTRETURN, sp->allow.u.longs)) {
8263 dfprintk(MOUNT, " pnfs cleanup mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04008264 __set_bit(NFS_SP4_MACH_CRED_PNFS_CLEANUP, &flags);
Andrew Elble99ade3c2015-12-02 09:39:51 -05008265 }
8266
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04008267 if (test_bit(OP_SECINFO, sp->allow.u.longs) &&
8268 test_bit(OP_SECINFO_NO_NAME, sp->allow.u.longs)) {
8269 dfprintk(MOUNT, " secinfo mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04008270 __set_bit(NFS_SP4_MACH_CRED_SECINFO, &flags);
Weston Andros Adamson8b5bee22013-08-13 16:37:35 -04008271 }
Weston Andros Adamson3787d502013-08-13 16:37:36 -04008272
8273 if (test_bit(OP_TEST_STATEID, sp->allow.u.longs) &&
8274 test_bit(OP_FREE_STATEID, sp->allow.u.longs)) {
8275 dfprintk(MOUNT, " stateid mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04008276 __set_bit(NFS_SP4_MACH_CRED_STATEID, &flags);
Weston Andros Adamson3787d502013-08-13 16:37:36 -04008277 }
Weston Andros Adamson8c21c622013-08-13 16:37:37 -04008278
8279 if (test_bit(OP_WRITE, sp->allow.u.longs)) {
8280 dfprintk(MOUNT, " write mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04008281 __set_bit(NFS_SP4_MACH_CRED_WRITE, &flags);
Weston Andros Adamson8c21c622013-08-13 16:37:37 -04008282 }
8283
8284 if (test_bit(OP_COMMIT, sp->allow.u.longs)) {
8285 dfprintk(MOUNT, " commit mode enabled\n");
Trond Myklebust937e3132017-08-01 07:32:50 -04008286 __set_bit(NFS_SP4_MACH_CRED_COMMIT, &flags);
Weston Andros Adamson8c21c622013-08-13 16:37:37 -04008287 }
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008288 }
Trond Myklebust937e3132017-08-01 07:32:50 -04008289out:
8290 clp->cl_sp4_flags = flags;
Wei Yongjun72bf75c2018-08-02 05:42:04 +00008291 return ret;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008292}
8293
Andy Adamson8d89bd72016-09-09 09:22:18 -04008294struct nfs41_exchange_id_data {
8295 struct nfs41_exchange_id_res res;
8296 struct nfs41_exchange_id_args args;
Andy Adamson8d89bd72016-09-09 09:22:18 -04008297};
8298
Andy Adamson8d89bd72016-09-09 09:22:18 -04008299static void nfs4_exchange_id_release(void *data)
8300{
8301 struct nfs41_exchange_id_data *cdata =
8302 (struct nfs41_exchange_id_data *)data;
8303
Olga Kornievskaia63513232017-03-13 10:36:19 -04008304 nfs_put_client(cdata->args.client);
Andy Adamson8d89bd72016-09-09 09:22:18 -04008305 kfree(cdata->res.impl_id);
8306 kfree(cdata->res.server_scope);
8307 kfree(cdata->res.server_owner);
8308 kfree(cdata);
8309}
8310
8311static const struct rpc_call_ops nfs4_exchange_id_call_ops = {
Andy Adamson8d89bd72016-09-09 09:22:18 -04008312 .rpc_release = nfs4_exchange_id_release,
8313};
8314
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008315/*
8316 * _nfs4_proc_exchange_id()
8317 *
8318 * Wrapper for EXCHANGE_ID operation.
8319 */
Trond Myklebust9c760d12017-07-31 18:38:50 -04008320static struct rpc_task *
NeilBrowna52458b2018-12-03 11:30:31 +11008321nfs4_run_exchange_id(struct nfs_client *clp, const struct cred *cred,
Andy Adamsonad0849a2016-09-09 09:22:28 -04008322 u32 sp4_how, struct rpc_xprt *xprt)
Benny Halevy99fe60d2009-04-01 09:22:29 -04008323{
Benny Halevy99fe60d2009-04-01 09:22:29 -04008324 struct rpc_message msg = {
8325 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID],
Benny Halevy99fe60d2009-04-01 09:22:29 -04008326 .rpc_cred = cred,
8327 };
Andy Adamson8d89bd72016-09-09 09:22:18 -04008328 struct rpc_task_setup task_setup_data = {
8329 .rpc_client = clp->cl_rpcclient,
8330 .callback_ops = &nfs4_exchange_id_call_ops,
8331 .rpc_message = &msg,
NeilBrown5a0c2572019-05-30 10:41:28 +10008332 .flags = RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN,
Andy Adamson8d89bd72016-09-09 09:22:18 -04008333 };
8334 struct nfs41_exchange_id_data *calldata;
Anna Schumakere917f0d2017-04-07 14:15:22 -04008335 int status;
Andy Adamson8d89bd72016-09-09 09:22:18 -04008336
Elena Reshetova212bf412017-10-20 12:53:38 +03008337 if (!refcount_inc_not_zero(&clp->cl_count))
Trond Myklebust9c760d12017-07-31 18:38:50 -04008338 return ERR_PTR(-EIO);
Andy Adamson8d89bd72016-09-09 09:22:18 -04008339
Trond Myklebust9c760d12017-07-31 18:38:50 -04008340 status = -ENOMEM;
Andy Adamson8d89bd72016-09-09 09:22:18 -04008341 calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
Trond Myklebust9c760d12017-07-31 18:38:50 -04008342 if (!calldata)
8343 goto out;
Benny Halevy99fe60d2009-04-01 09:22:29 -04008344
Trond Myklebustfd405592017-08-01 16:02:47 -04008345 nfs4_init_boot_verifier(clp, &calldata->args.verifier);
Jeff Layton873e3852015-06-09 19:44:00 -04008346
8347 status = nfs4_init_uniform_client_string(clp);
8348 if (status)
Andy Adamson8d89bd72016-09-09 09:22:18 -04008349 goto out_calldata;
Jeff Layton3a6bb732015-06-09 19:43:57 -04008350
Andy Adamson8d89bd72016-09-09 09:22:18 -04008351 calldata->res.server_owner = kzalloc(sizeof(struct nfs41_server_owner),
8352 GFP_NOFS);
8353 status = -ENOMEM;
8354 if (unlikely(calldata->res.server_owner == NULL))
8355 goto out_calldata;
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04008356
Andy Adamson8d89bd72016-09-09 09:22:18 -04008357 calldata->res.server_scope = kzalloc(sizeof(struct nfs41_server_scope),
Trond Myklebustbbafffd2012-05-24 16:31:39 -04008358 GFP_NOFS);
Andy Adamson8d89bd72016-09-09 09:22:18 -04008359 if (unlikely(calldata->res.server_scope == NULL))
Chuck Leveracdeb692012-05-21 22:46:16 -04008360 goto out_server_owner;
Benny Halevy99fe60d2009-04-01 09:22:29 -04008361
Andy Adamson8d89bd72016-09-09 09:22:18 -04008362 calldata->res.impl_id = kzalloc(sizeof(struct nfs41_impl_id), GFP_NOFS);
8363 if (unlikely(calldata->res.impl_id == NULL))
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05008364 goto out_server_scope;
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05008365
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008366 switch (sp4_how) {
8367 case SP4_NONE:
Andy Adamson8d89bd72016-09-09 09:22:18 -04008368 calldata->args.state_protect.how = SP4_NONE;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008369 break;
8370
8371 case SP4_MACH_CRED:
Andy Adamson8d89bd72016-09-09 09:22:18 -04008372 calldata->args.state_protect = nfs4_sp4_mach_cred_request;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008373 break;
8374
8375 default:
8376 /* unsupported! */
8377 WARN_ON_ONCE(1);
8378 status = -EINVAL;
Kinglong Mee6b559702015-07-01 11:54:53 +08008379 goto out_impl_id;
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008380 }
Andy Adamsonad0849a2016-09-09 09:22:28 -04008381 if (xprt) {
Andy Adamsonad0849a2016-09-09 09:22:28 -04008382 task_setup_data.rpc_xprt = xprt;
Trond Myklebustd9cb7332017-08-01 16:02:48 -04008383 task_setup_data.flags |= RPC_TASK_SOFTCONN;
Trond Myklebustfd405592017-08-01 16:02:47 -04008384 memcpy(calldata->args.verifier.data, clp->cl_confirm.data,
8385 sizeof(calldata->args.verifier.data));
Andy Adamsonad0849a2016-09-09 09:22:28 -04008386 }
Andy Adamson8d89bd72016-09-09 09:22:18 -04008387 calldata->args.client = clp;
Trond Myklebustbfab2812017-08-01 08:17:34 -04008388 calldata->args.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER |
8389 EXCHGID4_FLAG_BIND_PRINC_STATEID;
Andy Adamson8d89bd72016-09-09 09:22:18 -04008390#ifdef CONFIG_NFS_V4_1_MIGRATION
Trond Myklebustbfab2812017-08-01 08:17:34 -04008391 calldata->args.flags |= EXCHGID4_FLAG_SUPP_MOVED_MIGR;
Andy Adamson8d89bd72016-09-09 09:22:18 -04008392#endif
8393 msg.rpc_argp = &calldata->args;
8394 msg.rpc_resp = &calldata->res;
8395 task_setup_data.callback_data = calldata;
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04008396
Trond Myklebust9c760d12017-07-31 18:38:50 -04008397 return rpc_run_task(&task_setup_data);
Andy Adamson8d89bd72016-09-09 09:22:18 -04008398
8399out_impl_id:
8400 kfree(calldata->res.impl_id);
8401out_server_scope:
8402 kfree(calldata->res.server_scope);
8403out_server_owner:
8404 kfree(calldata->res.server_owner);
8405out_calldata:
8406 kfree(calldata);
Trond Myklebust9c760d12017-07-31 18:38:50 -04008407out:
Olga Kornievskaia63513232017-03-13 10:36:19 -04008408 nfs_put_client(clp);
Trond Myklebust9c760d12017-07-31 18:38:50 -04008409 return ERR_PTR(status);
8410}
8411
8412/*
8413 * _nfs4_proc_exchange_id()
8414 *
8415 * Wrapper for EXCHANGE_ID operation.
8416 */
NeilBrowna52458b2018-12-03 11:30:31 +11008417static int _nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cred,
Trond Myklebust9c760d12017-07-31 18:38:50 -04008418 u32 sp4_how)
8419{
8420 struct rpc_task *task;
8421 struct nfs41_exchange_id_args *argp;
8422 struct nfs41_exchange_id_res *resp;
Robert Milkowski7dc29932020-01-30 09:43:25 +00008423 unsigned long now = jiffies;
Trond Myklebust9c760d12017-07-31 18:38:50 -04008424 int status;
8425
8426 task = nfs4_run_exchange_id(clp, cred, sp4_how, NULL);
8427 if (IS_ERR(task))
8428 return PTR_ERR(task);
8429
8430 argp = task->tk_msg.rpc_argp;
8431 resp = task->tk_msg.rpc_resp;
8432 status = task->tk_status;
8433 if (status != 0)
8434 goto out;
8435
8436 status = nfs4_check_cl_exchange_flags(resp->flags);
8437 if (status != 0)
8438 goto out;
8439
8440 status = nfs4_sp4_select_mode(clp, &resp->state_protect);
8441 if (status != 0)
8442 goto out;
8443
Robert Milkowski7dc29932020-01-30 09:43:25 +00008444 do_renew_lease(clp, now);
8445
Trond Myklebust9c760d12017-07-31 18:38:50 -04008446 clp->cl_clientid = resp->clientid;
8447 clp->cl_exchange_flags = resp->flags;
8448 clp->cl_seqid = resp->seqid;
8449 /* Client ID is not confirmed */
8450 if (!(resp->flags & EXCHGID4_FLAG_CONFIRMED_R))
8451 clear_bit(NFS4_SESSION_ESTABLISHED,
8452 &clp->cl_session->session_state);
8453
8454 if (clp->cl_serverscope != NULL &&
8455 !nfs41_same_server_scope(clp->cl_serverscope,
8456 resp->server_scope)) {
8457 dprintk("%s: server_scope mismatch detected\n",
8458 __func__);
8459 set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state);
8460 }
8461
8462 swap(clp->cl_serverowner, resp->server_owner);
8463 swap(clp->cl_serverscope, resp->server_scope);
8464 swap(clp->cl_implid, resp->impl_id);
8465
8466 /* Save the EXCHANGE_ID verifier session trunk tests */
8467 memcpy(clp->cl_confirm.data, argp->verifier.data,
8468 sizeof(clp->cl_confirm.data));
8469out:
8470 trace_nfs4_exchange_id(clp, status);
8471 rpc_put_task(task);
8472 return status;
Benny Halevy99fe60d2009-04-01 09:22:29 -04008473}
8474
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008475/*
8476 * nfs4_proc_exchange_id()
8477 *
8478 * Returns zero, a negative errno, or a negative NFS4ERR status code.
8479 *
8480 * Since the clientid has expired, all compounds using sessions
8481 * associated with the stale clientid will be returning
8482 * NFS4ERR_BADSESSION in the sequence operation, and will therefore
8483 * be in some phase of session reset.
8484 *
8485 * Will attempt to negotiate SP4_MACH_CRED if krb5i / krb5p auth is used.
8486 */
NeilBrowna52458b2018-12-03 11:30:31 +11008487int nfs4_proc_exchange_id(struct nfs_client *clp, const struct cred *cred)
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008488{
8489 rpc_authflavor_t authflavor = clp->cl_rpcclient->cl_auth->au_flavor;
8490 int status;
8491
8492 /* try SP4_MACH_CRED if krb5i/p */
8493 if (authflavor == RPC_AUTH_GSS_KRB5I ||
8494 authflavor == RPC_AUTH_GSS_KRB5P) {
Trond Myklebust9c760d12017-07-31 18:38:50 -04008495 status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED);
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008496 if (!status)
8497 return 0;
8498 }
8499
8500 /* try SP4_NONE */
Trond Myklebust9c760d12017-07-31 18:38:50 -04008501 return _nfs4_proc_exchange_id(clp, cred, SP4_NONE);
Weston Andros Adamson2031cd12013-08-13 16:37:32 -04008502}
8503
Andy Adamson04fa2c62016-09-09 09:22:29 -04008504/**
8505 * nfs4_test_session_trunk
8506 *
8507 * This is an add_xprt_test() test function called from
8508 * rpc_clnt_setup_test_and_add_xprt.
8509 *
8510 * The rpc_xprt_switch is referrenced by rpc_clnt_setup_test_and_add_xprt
8511 * and is dereferrenced in nfs4_exchange_id_release
8512 *
8513 * Upon success, add the new transport to the rpc_clnt
8514 *
8515 * @clnt: struct rpc_clnt to get new transport
8516 * @xprt: the rpc_xprt to test
8517 * @data: call data for _nfs4_proc_exchange_id.
8518 */
Santosh kumar pradhan10e037d2018-12-19 12:29:57 +05308519void nfs4_test_session_trunk(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
Andy Adamson04fa2c62016-09-09 09:22:29 -04008520 void *data)
8521{
8522 struct nfs4_add_xprt_data *adata = (struct nfs4_add_xprt_data *)data;
Trond Myklebust9c760d12017-07-31 18:38:50 -04008523 struct rpc_task *task;
8524 int status;
8525
Andy Adamson04fa2c62016-09-09 09:22:29 -04008526 u32 sp4_how;
8527
8528 dprintk("--> %s try %s\n", __func__,
8529 xprt->address_strings[RPC_DISPLAY_ADDR]);
8530
8531 sp4_how = (adata->clp->cl_sp4_flags == 0 ? SP4_NONE : SP4_MACH_CRED);
8532
8533 /* Test connection for session trunking. Async exchange_id call */
Trond Myklebust9c760d12017-07-31 18:38:50 -04008534 task = nfs4_run_exchange_id(adata->clp, adata->cred, sp4_how, xprt);
8535 if (IS_ERR(task))
Santosh kumar pradhan10e037d2018-12-19 12:29:57 +05308536 return;
Trond Myklebust9c760d12017-07-31 18:38:50 -04008537
8538 status = task->tk_status;
8539 if (status == 0)
8540 status = nfs4_detect_session_trunking(adata->clp,
8541 task->tk_msg.rpc_resp, xprt);
8542
Santosh kumar pradhan10e037d2018-12-19 12:29:57 +05308543 if (status == 0)
8544 rpc_clnt_xprt_switch_add_xprt(clnt, xprt);
8545
Trond Myklebust9c760d12017-07-31 18:38:50 -04008546 rpc_put_task(task);
Andy Adamson04fa2c62016-09-09 09:22:29 -04008547}
8548EXPORT_SYMBOL_GPL(nfs4_test_session_trunk);
8549
Trond Myklebust66245532012-05-25 17:18:09 -04008550static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
NeilBrowna52458b2018-12-03 11:30:31 +11008551 const struct cred *cred)
Trond Myklebust66245532012-05-25 17:18:09 -04008552{
8553 struct rpc_message msg = {
8554 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_CLIENTID],
8555 .rpc_argp = clp,
8556 .rpc_cred = cred,
8557 };
8558 int status;
8559
NeilBrown5a0c2572019-05-30 10:41:28 +10008560 status = rpc_call_sync(clp->cl_rpcclient, &msg,
8561 RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04008562 trace_nfs4_destroy_clientid(clp, status);
Trond Myklebust66245532012-05-25 17:18:09 -04008563 if (status)
Trond Myklebust02c67522012-06-07 13:45:53 -04008564 dprintk("NFS: Got error %d from the server %s on "
Trond Myklebust66245532012-05-25 17:18:09 -04008565 "DESTROY_CLIENTID.", status, clp->cl_hostname);
8566 return status;
8567}
8568
8569static int nfs4_proc_destroy_clientid(struct nfs_client *clp,
NeilBrowna52458b2018-12-03 11:30:31 +11008570 const struct cred *cred)
Trond Myklebust66245532012-05-25 17:18:09 -04008571{
8572 unsigned int loop;
8573 int ret;
8574
8575 for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
8576 ret = _nfs4_proc_destroy_clientid(clp, cred);
8577 switch (ret) {
8578 case -NFS4ERR_DELAY:
8579 case -NFS4ERR_CLIENTID_BUSY:
8580 ssleep(1);
8581 break;
8582 default:
8583 return ret;
8584 }
8585 }
8586 return 0;
8587}
8588
8589int nfs4_destroy_clientid(struct nfs_client *clp)
8590{
NeilBrowna52458b2018-12-03 11:30:31 +11008591 const struct cred *cred;
Trond Myklebust66245532012-05-25 17:18:09 -04008592 int ret = 0;
8593
8594 if (clp->cl_mvops->minor_version < 1)
8595 goto out;
8596 if (clp->cl_exchange_flags == 0)
8597 goto out;
Chuck Lever05f4c352012-09-14 17:24:32 -04008598 if (clp->cl_preserve_clid)
8599 goto out;
Chuck Lever73d8bde2013-07-24 12:28:37 -04008600 cred = nfs4_get_clid_cred(clp);
Trond Myklebust66245532012-05-25 17:18:09 -04008601 ret = nfs4_proc_destroy_clientid(clp, cred);
NeilBrowna52458b2018-12-03 11:30:31 +11008602 put_cred(cred);
Trond Myklebust66245532012-05-25 17:18:09 -04008603 switch (ret) {
8604 case 0:
8605 case -NFS4ERR_STALE_CLIENTID:
8606 clp->cl_exchange_flags = 0;
8607 }
8608out:
8609 return ret;
8610}
8611
Donald Buczek0efb01b2019-07-07 21:26:08 +02008612#endif /* CONFIG_NFS_V4_1 */
8613
Andy Adamson2050f0c2009-04-01 09:22:30 -04008614struct nfs4_get_lease_time_data {
8615 struct nfs4_get_lease_time_args *args;
8616 struct nfs4_get_lease_time_res *res;
8617 struct nfs_client *clp;
8618};
8619
8620static void nfs4_get_lease_time_prepare(struct rpc_task *task,
8621 void *calldata)
8622{
Andy Adamson2050f0c2009-04-01 09:22:30 -04008623 struct nfs4_get_lease_time_data *data =
8624 (struct nfs4_get_lease_time_data *)calldata;
8625
8626 dprintk("--> %s\n", __func__);
8627 /* just setup sequence, do not trigger session recovery
8628 since we're invoked within one */
Anna Schumaker7981c8a2017-01-10 11:39:53 -05008629 nfs4_setup_sequence(data->clp,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04008630 &data->args->la_seq_args,
8631 &data->res->lr_seq_res,
8632 task);
Andy Adamson2050f0c2009-04-01 09:22:30 -04008633 dprintk("<-- %s\n", __func__);
8634}
8635
8636/*
8637 * Called from nfs4_state_manager thread for session setup, so don't recover
8638 * from sequence operation or clientid errors.
8639 */
8640static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
8641{
8642 struct nfs4_get_lease_time_data *data =
8643 (struct nfs4_get_lease_time_data *)calldata;
8644
8645 dprintk("--> %s\n", __func__);
Donald Buczek0efb01b2019-07-07 21:26:08 +02008646 if (!nfs4_sequence_done(task, &data->res->lr_seq_res))
Trond Myklebust14516c32010-07-31 14:29:06 -04008647 return;
Andy Adamson2050f0c2009-04-01 09:22:30 -04008648 switch (task->tk_status) {
8649 case -NFS4ERR_DELAY:
8650 case -NFS4ERR_GRACE:
8651 dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
8652 rpc_delay(task, NFS4_POLL_RETRY_MIN);
8653 task->tk_status = 0;
Andy Adamsona8a4ae32011-05-03 13:43:03 -04008654 /* fall through */
8655 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebustd00c5d42011-10-19 12:17:29 -07008656 rpc_restart_call_prepare(task);
Andy Adamson2050f0c2009-04-01 09:22:30 -04008657 return;
8658 }
Andy Adamson2050f0c2009-04-01 09:22:30 -04008659 dprintk("<-- %s\n", __func__);
8660}
8661
Trond Myklebust17280172012-03-11 13:11:00 -04008662static const struct rpc_call_ops nfs4_get_lease_time_ops = {
Andy Adamson2050f0c2009-04-01 09:22:30 -04008663 .rpc_call_prepare = nfs4_get_lease_time_prepare,
8664 .rpc_call_done = nfs4_get_lease_time_done,
8665};
8666
8667int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
8668{
Andy Adamson2050f0c2009-04-01 09:22:30 -04008669 struct nfs4_get_lease_time_args args;
8670 struct nfs4_get_lease_time_res res = {
8671 .lr_fsinfo = fsinfo,
8672 };
8673 struct nfs4_get_lease_time_data data = {
8674 .args = &args,
8675 .res = &res,
8676 .clp = clp,
8677 };
8678 struct rpc_message msg = {
8679 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME],
8680 .rpc_argp = &args,
8681 .rpc_resp = &res,
8682 };
8683 struct rpc_task_setup task_setup = {
8684 .rpc_client = clp->cl_rpcclient,
8685 .rpc_message = &msg,
8686 .callback_ops = &nfs4_get_lease_time_ops,
Trond Myklebust1bd714f2011-04-24 14:29:33 -04008687 .callback_data = &data,
8688 .flags = RPC_TASK_TIMEOUT,
Andy Adamson2050f0c2009-04-01 09:22:30 -04008689 };
Andy Adamson2050f0c2009-04-01 09:22:30 -04008690
Anna Schumakerfba83f32018-05-04 16:22:50 -04008691 nfs4_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0, 1);
Anna Schumakerf836b272019-08-19 10:18:28 -04008692 return nfs4_call_sync_custom(&task_setup);
Andy Adamson2050f0c2009-04-01 09:22:30 -04008693}
8694
Donald Buczek0efb01b2019-07-07 21:26:08 +02008695#ifdef CONFIG_NFS_V4_1
8696
Andy Adamsonfc931582009-04-01 09:22:31 -04008697/*
8698 * Initialize the values to be used by the client in CREATE_SESSION
8699 * If nfs4_init_session set the fore channel request and response sizes,
8700 * use them.
8701 *
8702 * Set the back channel max_resp_sz_cached to zero to force the client to
8703 * always set csa_cachethis to FALSE because the current implementation
8704 * of the back channel DRC only supports caching the CB_SEQUENCE operation.
8705 */
Chuck Lever6b26cc82016-05-02 14:40:40 -04008706static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args,
8707 struct rpc_clnt *clnt)
Andy Adamsonfc931582009-04-01 09:22:31 -04008708{
Andy Adamson18aad3d2013-06-26 12:21:49 -04008709 unsigned int max_rqst_sz, max_resp_sz;
Chuck Lever6b26cc82016-05-02 14:40:40 -04008710 unsigned int max_bc_payload = rpc_max_bc_payload(clnt);
Trond Myklebust7402a4f2019-07-16 13:51:29 -04008711 unsigned int max_bc_slots = rpc_num_bc_slots(clnt);
Andy Adamsonfc931582009-04-01 09:22:31 -04008712
Andy Adamson18aad3d2013-06-26 12:21:49 -04008713 max_rqst_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxwrite_overhead;
8714 max_resp_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxread_overhead;
8715
Andy Adamsonfc931582009-04-01 09:22:31 -04008716 /* Fore channel attributes */
Andy Adamson18aad3d2013-06-26 12:21:49 -04008717 args->fc_attrs.max_rqst_sz = max_rqst_sz;
8718 args->fc_attrs.max_resp_sz = max_resp_sz;
Andy Adamsonfc931582009-04-01 09:22:31 -04008719 args->fc_attrs.max_ops = NFS4_MAX_OPS;
Trond Myklebustef159e92012-02-06 19:50:40 -05008720 args->fc_attrs.max_reqs = max_session_slots;
Andy Adamsonfc931582009-04-01 09:22:31 -04008721
8722 dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u "
Mike Sager8e0d46e2009-12-17 12:06:26 -05008723 "max_ops=%u max_reqs=%u\n",
Andy Adamsonfc931582009-04-01 09:22:31 -04008724 __func__,
8725 args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz,
Mike Sager8e0d46e2009-12-17 12:06:26 -05008726 args->fc_attrs.max_ops, args->fc_attrs.max_reqs);
Andy Adamsonfc931582009-04-01 09:22:31 -04008727
8728 /* Back channel attributes */
Chuck Lever6b26cc82016-05-02 14:40:40 -04008729 args->bc_attrs.max_rqst_sz = max_bc_payload;
8730 args->bc_attrs.max_resp_sz = max_bc_payload;
Andy Adamsonfc931582009-04-01 09:22:31 -04008731 args->bc_attrs.max_resp_sz_cached = 0;
8732 args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS;
Trond Myklebust62421cd2018-08-11 11:52:39 -04008733 args->bc_attrs.max_reqs = max_t(unsigned short, max_session_cb_slots, 1);
Trond Myklebust7402a4f2019-07-16 13:51:29 -04008734 if (args->bc_attrs.max_reqs > max_bc_slots)
8735 args->bc_attrs.max_reqs = max_bc_slots;
Andy Adamsonfc931582009-04-01 09:22:31 -04008736
8737 dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u "
8738 "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
8739 __func__,
8740 args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz,
8741 args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops,
8742 args->bc_attrs.max_reqs);
8743}
8744
Trond Myklebust79969dd2015-02-18 11:30:18 -08008745static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args,
8746 struct nfs41_create_session_res *res)
Andy Adamson8d353012009-04-01 09:22:32 -04008747{
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008748 struct nfs4_channel_attrs *sent = &args->fc_attrs;
Trond Myklebust79969dd2015-02-18 11:30:18 -08008749 struct nfs4_channel_attrs *rcvd = &res->fc_attrs;
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008750
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008751 if (rcvd->max_resp_sz > sent->max_resp_sz)
8752 return -EINVAL;
8753 /*
8754 * Our requested max_ops is the minimum we need; we're not
8755 * prepared to break up compounds into smaller pieces than that.
8756 * So, no point even trying to continue if the server won't
8757 * cooperate:
8758 */
8759 if (rcvd->max_ops < sent->max_ops)
8760 return -EINVAL;
8761 if (rcvd->max_reqs == 0)
8762 return -EINVAL;
Vitaliy Gusevb4b9a0c2012-02-15 19:38:25 +04008763 if (rcvd->max_reqs > NFS4_MAX_SLOT_TABLE)
8764 rcvd->max_reqs = NFS4_MAX_SLOT_TABLE;
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008765 return 0;
Andy Adamson8d353012009-04-01 09:22:32 -04008766}
8767
Trond Myklebust79969dd2015-02-18 11:30:18 -08008768static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args,
8769 struct nfs41_create_session_res *res)
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008770{
8771 struct nfs4_channel_attrs *sent = &args->bc_attrs;
Trond Myklebust79969dd2015-02-18 11:30:18 -08008772 struct nfs4_channel_attrs *rcvd = &res->bc_attrs;
Andy Adamson8d353012009-04-01 09:22:32 -04008773
Trond Myklebustb1c0df52015-02-18 11:34:58 -08008774 if (!(res->flags & SESSION4_BACK_CHAN))
8775 goto out;
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008776 if (rcvd->max_rqst_sz > sent->max_rqst_sz)
8777 return -EINVAL;
8778 if (rcvd->max_resp_sz < sent->max_resp_sz)
8779 return -EINVAL;
8780 if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
8781 return -EINVAL;
Trond Myklebust5405fc42016-08-29 20:03:52 -04008782 if (rcvd->max_ops > sent->max_ops)
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008783 return -EINVAL;
Trond Myklebust5405fc42016-08-29 20:03:52 -04008784 if (rcvd->max_reqs > sent->max_reqs)
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008785 return -EINVAL;
Trond Myklebustb1c0df52015-02-18 11:34:58 -08008786out:
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008787 return 0;
8788}
Andy Adamson8d353012009-04-01 09:22:32 -04008789
Andy Adamson8d353012009-04-01 09:22:32 -04008790static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args,
Trond Myklebust79969dd2015-02-18 11:30:18 -08008791 struct nfs41_create_session_res *res)
Andy Adamson8d353012009-04-01 09:22:32 -04008792{
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008793 int ret;
Andy Adamson8d353012009-04-01 09:22:32 -04008794
Trond Myklebust79969dd2015-02-18 11:30:18 -08008795 ret = nfs4_verify_fore_channel_attrs(args, res);
J. Bruce Fields43c2e882010-10-02 15:19:01 -04008796 if (ret)
8797 return ret;
Trond Myklebust79969dd2015-02-18 11:30:18 -08008798 return nfs4_verify_back_channel_attrs(args, res);
8799}
8800
8801static void nfs4_update_session(struct nfs4_session *session,
8802 struct nfs41_create_session_res *res)
8803{
8804 nfs4_copy_sessionid(&session->sess_id, &res->sessionid);
Trond Myklebuste11259f2015-03-03 20:35:31 -05008805 /* Mark client id and session as being confirmed */
8806 session->clp->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R;
8807 set_bit(NFS4_SESSION_ESTABLISHED, &session->session_state);
Trond Myklebust79969dd2015-02-18 11:30:18 -08008808 session->flags = res->flags;
8809 memcpy(&session->fc_attrs, &res->fc_attrs, sizeof(session->fc_attrs));
Trond Myklebustb1c0df52015-02-18 11:34:58 -08008810 if (res->flags & SESSION4_BACK_CHAN)
8811 memcpy(&session->bc_attrs, &res->bc_attrs,
8812 sizeof(session->bc_attrs));
Andy Adamson8d353012009-04-01 09:22:32 -04008813}
8814
Trond Myklebust848f5bd2012-05-25 17:51:23 -04008815static int _nfs4_proc_create_session(struct nfs_client *clp,
NeilBrowna52458b2018-12-03 11:30:31 +11008816 const struct cred *cred)
Andy Adamsonfc931582009-04-01 09:22:31 -04008817{
8818 struct nfs4_session *session = clp->cl_session;
8819 struct nfs41_create_session_args args = {
8820 .client = clp,
Trond Myklebust79969dd2015-02-18 11:30:18 -08008821 .clientid = clp->cl_clientid,
8822 .seqid = clp->cl_seqid,
Andy Adamsonfc931582009-04-01 09:22:31 -04008823 .cb_program = NFS4_CALLBACK,
8824 };
Trond Myklebust79969dd2015-02-18 11:30:18 -08008825 struct nfs41_create_session_res res;
8826
Andy Adamsonfc931582009-04-01 09:22:31 -04008827 struct rpc_message msg = {
8828 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION],
8829 .rpc_argp = &args,
8830 .rpc_resp = &res,
Trond Myklebust848f5bd2012-05-25 17:51:23 -04008831 .rpc_cred = cred,
Andy Adamsonfc931582009-04-01 09:22:31 -04008832 };
8833 int status;
8834
Chuck Lever6b26cc82016-05-02 14:40:40 -04008835 nfs4_init_channel_attrs(&args, clp->cl_rpcclient);
Andy Adamson0f914212009-04-01 09:23:16 -04008836 args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
Andy Adamsonfc931582009-04-01 09:22:31 -04008837
NeilBrown5a0c2572019-05-30 10:41:28 +10008838 status = rpc_call_sync(session->clp->cl_rpcclient, &msg,
8839 RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04008840 trace_nfs4_create_session(clp, status);
Andy Adamsonfc931582009-04-01 09:22:31 -04008841
Trond Myklebustb519d402016-09-11 14:50:01 -04008842 switch (status) {
8843 case -NFS4ERR_STALE_CLIENTID:
8844 case -NFS4ERR_DELAY:
8845 case -ETIMEDOUT:
8846 case -EACCES:
8847 case -EAGAIN:
8848 goto out;
zhengbin8b98a532019-12-19 18:34:47 +08008849 }
Trond Myklebustb519d402016-09-11 14:50:01 -04008850
8851 clp->cl_seqid++;
Trond Myklebust43095d32012-11-20 11:13:12 -05008852 if (!status) {
Andy Adamson8d353012009-04-01 09:22:32 -04008853 /* Verify the session's negotiated channel_attrs values */
Trond Myklebust79969dd2015-02-18 11:30:18 -08008854 status = nfs4_verify_channel_attrs(&args, &res);
Andy Adamsonfc931582009-04-01 09:22:31 -04008855 /* Increment the clientid slot sequence id */
Trond Myklebust79969dd2015-02-18 11:30:18 -08008856 if (status)
8857 goto out;
8858 nfs4_update_session(session, &res);
Andy Adamsonfc931582009-04-01 09:22:31 -04008859 }
Trond Myklebust79969dd2015-02-18 11:30:18 -08008860out:
Andy Adamsonfc931582009-04-01 09:22:31 -04008861 return status;
8862}
8863
8864/*
8865 * Issues a CREATE_SESSION operation to the server.
8866 * It is the responsibility of the caller to verify the session is
8867 * expired before calling this routine.
8868 */
NeilBrowna52458b2018-12-03 11:30:31 +11008869int nfs4_proc_create_session(struct nfs_client *clp, const struct cred *cred)
Andy Adamsonfc931582009-04-01 09:22:31 -04008870{
8871 int status;
8872 unsigned *ptr;
Andy Adamsonfc931582009-04-01 09:22:31 -04008873 struct nfs4_session *session = clp->cl_session;
8874
8875 dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
8876
Trond Myklebust848f5bd2012-05-25 17:51:23 -04008877 status = _nfs4_proc_create_session(clp, cred);
Andy Adamsonfc931582009-04-01 09:22:31 -04008878 if (status)
8879 goto out;
8880
Andy Adamsonaacd5532011-11-09 13:58:21 -05008881 /* Init or reset the session slot tables */
8882 status = nfs4_setup_session_slot_tables(session);
8883 dprintk("slot table setup returned %d\n", status);
Andy Adamsonfc931582009-04-01 09:22:31 -04008884 if (status)
8885 goto out;
8886
8887 ptr = (unsigned *)&session->sess_id.data[0];
8888 dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__,
8889 clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]);
Andy Adamsonfc931582009-04-01 09:22:31 -04008890out:
8891 dprintk("<-- %s\n", __func__);
8892 return status;
8893}
8894
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008895/*
8896 * Issue the over-the-wire RPC DESTROY_SESSION.
8897 * The caller must serialize access to this routine.
8898 */
Trond Myklebust848f5bd2012-05-25 17:51:23 -04008899int nfs4_proc_destroy_session(struct nfs4_session *session,
NeilBrowna52458b2018-12-03 11:30:31 +11008900 const struct cred *cred)
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008901{
Trond Myklebust848f5bd2012-05-25 17:51:23 -04008902 struct rpc_message msg = {
8903 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION],
8904 .rpc_argp = session,
8905 .rpc_cred = cred,
8906 };
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008907 int status = 0;
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008908
8909 dprintk("--> nfs4_proc_destroy_session\n");
8910
8911 /* session is still being setup */
Trond Myklebuste11259f2015-03-03 20:35:31 -05008912 if (!test_and_clear_bit(NFS4_SESSION_ESTABLISHED, &session->session_state))
8913 return 0;
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008914
NeilBrown5a0c2572019-05-30 10:41:28 +10008915 status = rpc_call_sync(session->clp->cl_rpcclient, &msg,
8916 RPC_TASK_TIMEOUT | RPC_TASK_NO_ROUND_ROBIN);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04008917 trace_nfs4_destroy_session(session->clp, status);
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008918
8919 if (status)
Trond Myklebust08106ac2012-06-05 10:08:24 -04008920 dprintk("NFS: Got error %d from the server on DESTROY_SESSION. "
Andy Adamson0f3e66c2009-04-01 09:22:34 -04008921 "Session has been destroyed regardless...\n", status);
8922
8923 dprintk("<-- nfs4_proc_destroy_session\n");
8924 return status;
8925}
8926
Trond Myklebust7b38c362012-05-23 13:23:31 -04008927/*
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008928 * Renew the cl_session lease.
8929 */
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008930struct nfs4_sequence_data {
8931 struct nfs_client *clp;
8932 struct nfs4_sequence_args args;
8933 struct nfs4_sequence_res res;
8934};
8935
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008936static void nfs41_sequence_release(void *data)
8937{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008938 struct nfs4_sequence_data *calldata = data;
8939 struct nfs_client *clp = calldata->clp;
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008940
Elena Reshetova212bf412017-10-20 12:53:38 +03008941 if (refcount_read(&clp->cl_count) > 1)
Alexandros Batsakis71358402010-02-05 03:45:05 -08008942 nfs4_schedule_state_renewal(clp);
8943 nfs_put_client(clp);
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008944 kfree(calldata);
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008945}
8946
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008947static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp)
8948{
8949 switch(task->tk_status) {
8950 case -NFS4ERR_DELAY:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008951 rpc_delay(task, NFS4_POLL_RETRY_MAX);
8952 return -EAGAIN;
8953 default:
Trond Myklebust0400a6b2011-03-09 16:00:53 -05008954 nfs4_schedule_lease_recovery(clp);
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008955 }
8956 return 0;
8957}
8958
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008959static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008960{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008961 struct nfs4_sequence_data *calldata = data;
8962 struct nfs_client *clp = calldata->clp;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008963
Trond Myklebust14516c32010-07-31 14:29:06 -04008964 if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
8965 return;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008966
Trond Myklebustc6d01c62013-08-09 11:51:26 -04008967 trace_nfs4_sequence(clp, task->tk_status);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008968 if (task->tk_status < 0) {
8969 dprintk("%s ERROR %d\n", __func__, task->tk_status);
Elena Reshetova212bf412017-10-20 12:53:38 +03008970 if (refcount_read(&clp->cl_count) == 1)
Alexandros Batsakis71358402010-02-05 03:45:05 -08008971 goto out;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008972
Trond Myklebustaa5190d2010-06-16 09:52:25 -04008973 if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) {
8974 rpc_restart_call_prepare(task);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008975 return;
8976 }
8977 }
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008978 dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
Alexandros Batsakis71358402010-02-05 03:45:05 -08008979out:
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008980 dprintk("<-- %s\n", __func__);
8981}
8982
8983static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
8984{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04008985 struct nfs4_sequence_data *calldata = data;
8986 struct nfs_client *clp = calldata->clp;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008987 struct nfs4_sequence_args *args;
8988 struct nfs4_sequence_res *res;
8989
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008990 args = task->tk_msg.rpc_argp;
8991 res = task->tk_msg.rpc_resp;
8992
Anna Schumaker7981c8a2017-01-10 11:39:53 -05008993 nfs4_setup_sequence(clp, args, res, task);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04008994}
8995
8996static const struct rpc_call_ops nfs41_sequence_ops = {
8997 .rpc_call_done = nfs41_sequence_call_done,
8998 .rpc_call_prepare = nfs41_sequence_prepare,
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08008999 .rpc_release = nfs41_sequence_release,
Andy Adamsonfc01cea2009-04-01 09:22:36 -04009000};
9001
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04009002static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
NeilBrowna52458b2018-12-03 11:30:31 +11009003 const struct cred *cred,
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04009004 struct nfs4_slot *slot,
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04009005 bool is_privileged)
Andy Adamsonfc01cea2009-04-01 09:22:36 -04009006{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04009007 struct nfs4_sequence_data *calldata;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04009008 struct rpc_message msg = {
9009 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
9010 .rpc_cred = cred,
9011 };
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009012 struct rpc_task_setup task_setup_data = {
9013 .rpc_client = clp->cl_rpcclient,
9014 .rpc_message = &msg,
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04009015 .callback_ops = &nfs41_sequence_ops,
Trond Myklebustbc7a05c2013-04-08 17:50:28 -04009016 .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009017 };
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04009018 struct rpc_task *ret;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04009019
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04009020 ret = ERR_PTR(-EIO);
Elena Reshetova212bf412017-10-20 12:53:38 +03009021 if (!refcount_inc_not_zero(&clp->cl_count))
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04009022 goto out_err;
9023
9024 ret = ERR_PTR(-ENOMEM);
Benny Halevydfb4f3092010-09-24 09:17:01 -04009025 calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04009026 if (calldata == NULL)
9027 goto out_put_clp;
Anna Schumakerfba83f32018-05-04 16:22:50 -04009028 nfs4_init_sequence(&calldata->args, &calldata->res, 0, is_privileged);
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04009029 nfs4_sequence_attach_slot(&calldata->args, &calldata->res, slot);
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04009030 msg.rpc_argp = &calldata->args;
9031 msg.rpc_resp = &calldata->res;
9032 calldata->clp = clp;
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009033 task_setup_data.callback_data = calldata;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04009034
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04009035 ret = rpc_run_task(&task_setup_data);
9036 if (IS_ERR(ret))
9037 goto out_err;
9038 return ret;
9039out_put_clp:
9040 nfs_put_client(clp);
9041out_err:
9042 nfs41_release_slot(slot);
9043 return ret;
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009044}
9045
NeilBrowna52458b2018-12-03 11:30:31 +11009046static int nfs41_proc_async_sequence(struct nfs_client *clp, const struct cred *cred, unsigned renew_flags)
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009047{
9048 struct rpc_task *task;
9049 int ret = 0;
9050
Trond Myklebust2f60ea62011-08-24 15:07:37 -04009051 if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
Andy Adamsond1f456b2014-09-29 12:31:57 -04009052 return -EAGAIN;
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04009053 task = _nfs41_proc_sequence(clp, cred, NULL, false);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009054 if (IS_ERR(task))
9055 ret = PTR_ERR(task);
9056 else
Trond Myklebustbf294b42011-02-21 11:05:41 -08009057 rpc_put_task_async(task);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009058 dprintk("<-- %s status=%d\n", __func__, ret);
9059 return ret;
9060}
9061
NeilBrowna52458b2018-12-03 11:30:31 +11009062static int nfs4_proc_sequence(struct nfs_client *clp, const struct cred *cred)
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009063{
9064 struct rpc_task *task;
9065 int ret;
9066
Trond Myklebust3be0f80b2017-10-19 15:46:45 -04009067 task = _nfs41_proc_sequence(clp, cred, NULL, true);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009068 if (IS_ERR(task)) {
9069 ret = PTR_ERR(task);
9070 goto out;
9071 }
9072 ret = rpc_wait_for_completion_task(task);
Trond Myklebustbe824162015-07-05 14:50:46 -04009073 if (!ret)
Trond Myklebust71ac6da2010-06-16 09:52:26 -04009074 ret = task->tk_status;
9075 rpc_put_task(task);
9076out:
9077 dprintk("<-- %s status=%d\n", __func__, ret);
9078 return ret;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04009079}
9080
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009081struct nfs4_reclaim_complete_data {
9082 struct nfs_client *clp;
9083 struct nfs41_reclaim_complete_args arg;
9084 struct nfs41_reclaim_complete_res res;
9085};
9086
9087static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
9088{
9089 struct nfs4_reclaim_complete_data *calldata = data;
9090
Anna Schumaker7981c8a2017-01-10 11:39:53 -05009091 nfs4_setup_sequence(calldata->clp,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04009092 &calldata->arg.seq_args,
9093 &calldata->res.seq_res,
9094 task);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009095}
9096
Trond Myklebustaa5190d2010-06-16 09:52:25 -04009097static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp)
9098{
9099 switch(task->tk_status) {
9100 case 0:
Jeff Layton57174592018-03-18 08:37:03 -04009101 wake_up_all(&clp->cl_lock_waitq);
9102 /* Fallthrough */
Trond Myklebustaa5190d2010-06-16 09:52:25 -04009103 case -NFS4ERR_COMPLETE_ALREADY:
9104 case -NFS4ERR_WRONG_CRED: /* What to do here? */
9105 break;
9106 case -NFS4ERR_DELAY:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04009107 rpc_delay(task, NFS4_POLL_RETRY_MAX);
Andy Adamsona8a4ae32011-05-03 13:43:03 -04009108 /* fall through */
9109 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04009110 return -EAGAIN;
Trond Myklebust0048fdd2017-05-04 13:44:04 -04009111 case -NFS4ERR_BADSESSION:
9112 case -NFS4ERR_DEADSESSION:
9113 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
Trond Myklebust0048fdd2017-05-04 13:44:04 -04009114 break;
Trond Myklebustaa5190d2010-06-16 09:52:25 -04009115 default:
Trond Myklebust0400a6b2011-03-09 16:00:53 -05009116 nfs4_schedule_lease_recovery(clp);
Trond Myklebustaa5190d2010-06-16 09:52:25 -04009117 }
9118 return 0;
9119}
9120
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009121static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
9122{
9123 struct nfs4_reclaim_complete_data *calldata = data;
9124 struct nfs_client *clp = calldata->clp;
9125 struct nfs4_sequence_res *res = &calldata->res.seq_res;
9126
9127 dprintk("--> %s\n", __func__);
Trond Myklebust14516c32010-07-31 14:29:06 -04009128 if (!nfs41_sequence_done(task, res))
9129 return;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009130
Trond Myklebustc6d01c62013-08-09 11:51:26 -04009131 trace_nfs4_reclaim_complete(clp, task->tk_status);
Trond Myklebustaa5190d2010-06-16 09:52:25 -04009132 if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) {
9133 rpc_restart_call_prepare(task);
9134 return;
9135 }
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009136 dprintk("<-- %s\n", __func__);
9137}
9138
9139static void nfs4_free_reclaim_complete_data(void *data)
9140{
9141 struct nfs4_reclaim_complete_data *calldata = data;
9142
9143 kfree(calldata);
9144}
9145
9146static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = {
9147 .rpc_call_prepare = nfs4_reclaim_complete_prepare,
9148 .rpc_call_done = nfs4_reclaim_complete_done,
9149 .rpc_release = nfs4_free_reclaim_complete_data,
9150};
9151
9152/*
9153 * Issue a global reclaim complete.
9154 */
Trond Myklebust965e9c22013-05-20 11:05:17 -04009155static int nfs41_proc_reclaim_complete(struct nfs_client *clp,
NeilBrowna52458b2018-12-03 11:30:31 +11009156 const struct cred *cred)
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009157{
9158 struct nfs4_reclaim_complete_data *calldata;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009159 struct rpc_message msg = {
9160 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE],
Trond Myklebust965e9c22013-05-20 11:05:17 -04009161 .rpc_cred = cred,
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009162 };
9163 struct rpc_task_setup task_setup_data = {
9164 .rpc_client = clp->cl_rpcclient,
9165 .rpc_message = &msg,
9166 .callback_ops = &nfs4_reclaim_complete_call_ops,
Anna Schumaker4c952e32019-08-14 15:46:48 -04009167 .flags = RPC_TASK_NO_ROUND_ROBIN,
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009168 };
9169 int status = -ENOMEM;
9170
9171 dprintk("--> %s\n", __func__);
Trond Myklebust8535b2b2010-05-13 12:51:01 -04009172 calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009173 if (calldata == NULL)
9174 goto out;
9175 calldata->clp = clp;
9176 calldata->arg.one_fs = 0;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009177
Anna Schumakerfba83f32018-05-04 16:22:50 -04009178 nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0, 1);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009179 msg.rpc_argp = &calldata->arg;
9180 msg.rpc_resp = &calldata->res;
9181 task_setup_data.callback_data = calldata;
Anna Schumaker4c952e32019-08-14 15:46:48 -04009182 status = nfs4_call_sync_custom(&task_setup_data);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05009183out:
9184 dprintk("<-- %s status=%d\n", __func__, status);
9185 return status;
9186}
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009187
9188static void
9189nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
9190{
9191 struct nfs4_layoutget *lgp = calldata;
Fred Isamanc31663d2011-01-06 11:36:24 +00009192 struct nfs_server *server = NFS_SERVER(lgp->args.inode);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009193
9194 dprintk("--> %s\n", __func__);
Anna Schumaker7981c8a2017-01-10 11:39:53 -05009195 nfs4_setup_sequence(server->nfs_client, &lgp->args.seq_args,
Jeff Layton183d9e72016-05-17 12:28:47 -04009196 &lgp->res.seq_res, task);
9197 dprintk("<-- %s\n", __func__);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009198}
9199
9200static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
9201{
9202 struct nfs4_layoutget *lgp = calldata;
Jeff Layton183d9e72016-05-17 12:28:47 -04009203
9204 dprintk("--> %s\n", __func__);
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04009205 nfs41_sequence_process(task, &lgp->res.seq_res);
Jeff Layton183d9e72016-05-17 12:28:47 -04009206 dprintk("<-- %s\n", __func__);
9207}
9208
9209static int
9210nfs4_layoutget_handle_exception(struct rpc_task *task,
9211 struct nfs4_layoutget *lgp, struct nfs4_exception *exception)
9212{
Trond Myklebustee314c22012-10-01 17:25:48 -07009213 struct inode *inode = lgp->args.inode;
9214 struct nfs_server *server = NFS_SERVER(inode);
9215 struct pnfs_layout_hdr *lo;
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04009216 int nfs4err = task->tk_status;
9217 int err, status = 0;
Trond Myklebustf7db0b22016-07-14 15:14:02 -04009218 LIST_HEAD(head);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009219
Boaz Harroshed7e5422014-01-22 20:34:54 +02009220 dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009221
Trond Myklebust2dbf8df2018-06-15 15:58:45 -04009222 nfs4_sequence_free_slot(&lgp->res.seq_res);
9223
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04009224 switch (nfs4err) {
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009225 case 0:
Trond Myklebustee314c22012-10-01 17:25:48 -07009226 goto out;
Peng Tao7c1e6e52015-12-05 17:01:01 +08009227
9228 /*
9229 * NFS4ERR_LAYOUTUNAVAILABLE means we are not supposed to use pnfs
9230 * on the file. set tk_status to -ENODATA to tell upper layer to
9231 * retry go inband.
9232 */
9233 case -NFS4ERR_LAYOUTUNAVAILABLE:
Jeff Layton183d9e72016-05-17 12:28:47 -04009234 status = -ENODATA;
Peng Tao7c1e6e52015-12-05 17:01:01 +08009235 goto out;
Boaz Harroshed7e5422014-01-22 20:34:54 +02009236 /*
Trond Myklebust21b874c2015-08-31 01:19:22 -07009237 * NFS4ERR_BADLAYOUT means the MDS cannot return a layout of
9238 * length lgp->args.minlength != 0 (see RFC5661 section 18.43.3).
9239 */
9240 case -NFS4ERR_BADLAYOUT:
Jeff Layton183d9e72016-05-17 12:28:47 -04009241 status = -EOVERFLOW;
9242 goto out;
Trond Myklebust21b874c2015-08-31 01:19:22 -07009243 /*
Boaz Harroshed7e5422014-01-22 20:34:54 +02009244 * NFS4ERR_LAYOUTTRYLATER is a conflict with another client
Trond Myklebust21b874c2015-08-31 01:19:22 -07009245 * (or clients) writing to the same RAID stripe except when
9246 * the minlength argument is 0 (see RFC5661 section 18.43.3).
Jeff Layton183d9e72016-05-17 12:28:47 -04009247 *
9248 * Treat it like we would RECALLCONFLICT -- we retry for a little
9249 * while, and then eventually give up.
Boaz Harroshed7e5422014-01-22 20:34:54 +02009250 */
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009251 case -NFS4ERR_LAYOUTTRYLATER:
Jeff Layton183d9e72016-05-17 12:28:47 -04009252 if (lgp->args.minlength == 0) {
9253 status = -EOVERFLOW;
9254 goto out;
Boaz Harroshed7e5422014-01-22 20:34:54 +02009255 }
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04009256 status = -EBUSY;
9257 break;
Jeff Layton183d9e72016-05-17 12:28:47 -04009258 case -NFS4ERR_RECALLCONFLICT:
Jeff Layton183d9e72016-05-17 12:28:47 -04009259 status = -ERECALLCONFLICT;
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04009260 break;
Trond Myklebust26f47442016-09-22 13:39:10 -04009261 case -NFS4ERR_DELEG_REVOKED:
9262 case -NFS4ERR_ADMIN_REVOKED:
Trond Myklebustee314c22012-10-01 17:25:48 -07009263 case -NFS4ERR_EXPIRED:
9264 case -NFS4ERR_BAD_STATEID:
Jeff Layton183d9e72016-05-17 12:28:47 -04009265 exception->timeout = 0;
Trond Myklebustee314c22012-10-01 17:25:48 -07009266 spin_lock(&inode->i_lock);
Trond Myklebustf7db0b22016-07-14 15:14:02 -04009267 lo = NFS_I(inode)->layout;
9268 /* If the open stateid was bad, then recover it. */
9269 if (!lo || test_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags) ||
Trond Myklebuste8fa33a2017-10-04 13:49:12 -04009270 !nfs4_stateid_match_other(&lgp->args.stateid, &lo->plh_stateid)) {
Trond Myklebustee314c22012-10-01 17:25:48 -07009271 spin_unlock(&inode->i_lock);
Jeff Layton183d9e72016-05-17 12:28:47 -04009272 exception->state = lgp->args.ctx->state;
Trond Myklebust26f47442016-09-22 13:39:10 -04009273 exception->stateid = &lgp->args.stateid;
Trond Myklebust2259f962015-09-20 13:30:30 -04009274 break;
9275 }
Trond Myklebustee314c22012-10-01 17:25:48 -07009276
Trond Myklebustf7db0b22016-07-14 15:14:02 -04009277 /*
9278 * Mark the bad layout state as invalid, then retry
9279 */
Trond Myklebust668f4552016-07-24 17:08:59 -04009280 pnfs_mark_layout_stateid_invalid(lo, &head);
Trond Myklebustf7db0b22016-07-14 15:14:02 -04009281 spin_unlock(&inode->i_lock);
Trond Myklebust1f18b822017-04-29 10:10:17 -04009282 nfs_commit_inode(inode, 0);
Trond Myklebustf7db0b22016-07-14 15:14:02 -04009283 pnfs_free_lseg_list(&head);
9284 status = -EAGAIN;
9285 goto out;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009286 }
Jeff Layton183d9e72016-05-17 12:28:47 -04009287
Trond Myklebuste85d7ee2016-07-14 18:46:24 -04009288 err = nfs4_handle_exception(server, nfs4err, exception);
9289 if (!status) {
9290 if (exception->retry)
9291 status = -EAGAIN;
9292 else
9293 status = err;
9294 }
Trond Myklebustee314c22012-10-01 17:25:48 -07009295out:
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009296 dprintk("<-- %s\n", __func__);
Jeff Layton183d9e72016-05-17 12:28:47 -04009297 return status;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009298}
9299
Fred Isamandacb4522016-09-19 17:47:09 -04009300size_t max_response_pages(struct nfs_server *server)
Idan Kedar85541162012-08-02 11:47:10 +03009301{
9302 u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
9303 return nfs_page_array_len(0, max_resp_sz);
9304}
9305
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009306static void nfs4_layoutget_release(void *calldata)
9307{
9308 struct nfs4_layoutget *lgp = calldata;
9309
9310 dprintk("--> %s\n", __func__);
Trond Myklebustbd171932017-06-27 17:33:38 -04009311 nfs4_sequence_free_slot(&lgp->res.seq_res);
Trond Myklebust29a8bfe2018-05-30 17:16:20 -04009312 pnfs_layoutget_free(lgp);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009313 dprintk("<-- %s\n", __func__);
9314}
9315
9316static const struct rpc_call_ops nfs4_layoutget_call_ops = {
9317 .rpc_call_prepare = nfs4_layoutget_prepare,
9318 .rpc_call_done = nfs4_layoutget_done,
9319 .rpc_release = nfs4_layoutget_release,
9320};
9321
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04009322struct pnfs_layout_segment *
Fred Isamandacb4522016-09-19 17:47:09 -04009323nfs4_proc_layoutget(struct nfs4_layoutget *lgp, long *timeout)
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009324{
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05009325 struct inode *inode = lgp->args.inode;
9326 struct nfs_server *server = NFS_SERVER(inode);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009327 struct rpc_task *task;
9328 struct rpc_message msg = {
9329 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
9330 .rpc_argp = &lgp->args,
9331 .rpc_resp = &lgp->res,
Trond Myklebust6ab59342013-05-20 10:49:34 -04009332 .rpc_cred = lgp->cred,
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009333 };
9334 struct rpc_task_setup task_setup_data = {
9335 .rpc_client = server->client,
9336 .rpc_message = &msg,
9337 .callback_ops = &nfs4_layoutget_call_ops,
9338 .callback_data = lgp,
Trond Myklebust63ec2b62020-02-07 19:40:14 -05009339 .flags = RPC_TASK_ASYNC | RPC_TASK_CRED_NOREF,
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009340 };
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04009341 struct pnfs_layout_segment *lseg = NULL;
Trond Myklebustbc236762016-06-17 16:48:18 -04009342 struct nfs4_exception exception = {
9343 .inode = inode,
9344 .timeout = *timeout,
9345 };
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009346 int status = 0;
9347
9348 dprintk("--> %s\n", __func__);
9349
Peng Tao4bd5a982014-11-17 11:05:17 +08009350 /* nfs4_layoutget_release calls pnfs_put_layout_hdr */
9351 pnfs_get_layout_hdr(NFS_I(inode)->layout);
9352
Anna Schumakerfba83f32018-05-04 16:22:50 -04009353 nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0, 0);
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05009354
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009355 task = rpc_run_task(&task_setup_data);
Xiyu Yang6e476662020-04-25 21:04:40 +08009356
Anna Schumaker820bf852017-01-11 15:01:43 -05009357 status = rpc_wait_for_completion_task(task);
Trond Myklebust2dbf8df2018-06-15 15:58:45 -04009358 if (status != 0)
9359 goto out;
9360
Trond Myklebust18c07782019-02-13 07:55:31 -05009361 if (task->tk_status < 0) {
Jeff Layton183d9e72016-05-17 12:28:47 -04009362 status = nfs4_layoutget_handle_exception(task, lgp, &exception);
9363 *timeout = exception.timeout;
Trond Myklebust18c07782019-02-13 07:55:31 -05009364 } else if (lgp->res.layoutp->len == 0) {
9365 status = -EAGAIN;
9366 *timeout = nfs4_update_delay(&exception.timeout);
Trond Myklebust2dbf8df2018-06-15 15:58:45 -04009367 } else
9368 lseg = pnfs_layout_process(lgp);
9369out:
Trond Myklebust1037e6e2013-08-14 16:36:51 -04009370 trace_nfs4_layoutget(lgp->args.ctx,
9371 &lgp->args.range,
9372 &lgp->res.range,
Olga Kornievskaia48c95792015-11-24 13:29:41 -05009373 &lgp->res.stateid,
Trond Myklebust1037e6e2013-08-14 16:36:51 -04009374 status);
Jeff Layton183d9e72016-05-17 12:28:47 -04009375
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009376 rpc_put_task(task);
9377 dprintk("<-- %s status=%d\n", __func__, status);
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04009378 if (status)
9379 return ERR_PTR(status);
9380 return lseg;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009381}
9382
Benny Halevycbe82602011-05-22 19:52:37 +03009383static void
9384nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
9385{
9386 struct nfs4_layoutreturn *lrp = calldata;
9387
9388 dprintk("--> %s\n", __func__);
Anna Schumaker7981c8a2017-01-10 11:39:53 -05009389 nfs4_setup_sequence(lrp->clp,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04009390 &lrp->args.seq_args,
9391 &lrp->res.seq_res,
9392 task);
Trond Myklebustc8bf7072018-06-15 16:31:02 -04009393 if (!pnfs_layout_is_valid(lrp->args.layout))
9394 rpc_exit(task, 0);
Benny Halevycbe82602011-05-22 19:52:37 +03009395}
9396
9397static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
9398{
9399 struct nfs4_layoutreturn *lrp = calldata;
9400 struct nfs_server *server;
9401
9402 dprintk("--> %s\n", __func__);
9403
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04009404 if (!nfs41_sequence_process(task, &lrp->res.seq_res))
Benny Halevycbe82602011-05-22 19:52:37 +03009405 return;
9406
Trond Myklebust6109bcf2019-09-20 07:23:43 -04009407 /*
9408 * Was there an RPC level error? Assume the call succeeded,
9409 * and that we need to release the layout
9410 */
9411 if (task->tk_rpc_status != 0 && RPC_WAS_SENT(task)) {
9412 lrp->res.lrs_present = 0;
9413 return;
9414 }
9415
Benny Halevycbe82602011-05-22 19:52:37 +03009416 server = NFS_SERVER(lrp->args.inode);
Trond Myklebustf22e5ed2013-12-04 12:09:45 -05009417 switch (task->tk_status) {
Trond Myklebustff905142017-11-06 15:28:08 -05009418 case -NFS4ERR_OLD_STATEID:
Trond Myklebust30cb3ee2019-09-20 07:23:45 -04009419 if (nfs4_layout_refresh_old_stateid(&lrp->args.stateid,
Trond Myklebustecf84022018-08-15 21:35:46 -04009420 &lrp->args.range,
Trond Myklebustff905142017-11-06 15:28:08 -05009421 lrp->args.inode))
9422 goto out_restart;
9423 /* Fallthrough */
Trond Myklebustf22e5ed2013-12-04 12:09:45 -05009424 default:
9425 task->tk_status = 0;
Trond Myklebustff905142017-11-06 15:28:08 -05009426 /* Fallthrough */
Trond Myklebustf22e5ed2013-12-04 12:09:45 -05009427 case 0:
9428 break;
9429 case -NFS4ERR_DELAY:
NeilBrown8478eaa2014-09-18 16:09:27 +10009430 if (nfs4_async_handle_error(task, server, NULL, NULL) != -EAGAIN)
Trond Myklebustf22e5ed2013-12-04 12:09:45 -05009431 break;
Trond Myklebustff905142017-11-06 15:28:08 -05009432 goto out_restart;
Benny Halevycbe82602011-05-22 19:52:37 +03009433 }
Benny Halevycbe82602011-05-22 19:52:37 +03009434 dprintk("<-- %s\n", __func__);
Trond Myklebustff905142017-11-06 15:28:08 -05009435 return;
9436out_restart:
9437 task->tk_status = 0;
9438 nfs4_sequence_free_slot(&lrp->res.seq_res);
9439 rpc_restart_call_prepare(task);
Benny Halevycbe82602011-05-22 19:52:37 +03009440}
9441
9442static void nfs4_layoutreturn_release(void *calldata)
9443{
9444 struct nfs4_layoutreturn *lrp = calldata;
Trond Myklebust849b2862012-09-24 14:18:39 -04009445 struct pnfs_layout_hdr *lo = lrp->args.layout;
Benny Halevycbe82602011-05-22 19:52:37 +03009446
9447 dprintk("--> %s\n", __func__);
Trond Myklebust2a974422016-11-20 13:13:54 -05009448 pnfs_layoutreturn_free_lsegs(lo, &lrp->args.stateid, &lrp->args.range,
Trond Myklebust68f74472016-10-12 19:50:54 -04009449 lrp->res.lrs_present ? &lrp->res.stateid : NULL);
Trond Myklebust2e80dbe2016-08-28 11:50:26 -04009450 nfs4_sequence_free_slot(&lrp->res.seq_res);
Trond Myklebust4d796d72016-09-23 11:38:08 -04009451 if (lrp->ld_private.ops && lrp->ld_private.ops->free)
9452 lrp->ld_private.ops->free(&lrp->ld_private);
Trond Myklebust2f065dd2016-12-07 12:29:26 -05009453 pnfs_put_layout_hdr(lrp->args.layout);
9454 nfs_iput_and_deactive(lrp->inode);
Trond Myklebust44ea8df2020-04-02 15:37:02 -04009455 put_cred(lrp->cred);
Benny Halevycbe82602011-05-22 19:52:37 +03009456 kfree(calldata);
9457 dprintk("<-- %s\n", __func__);
9458}
9459
9460static const struct rpc_call_ops nfs4_layoutreturn_call_ops = {
9461 .rpc_call_prepare = nfs4_layoutreturn_prepare,
9462 .rpc_call_done = nfs4_layoutreturn_done,
9463 .rpc_release = nfs4_layoutreturn_release,
9464};
9465
Peng Tao6c166052014-11-17 09:30:40 +08009466int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp, bool sync)
Benny Halevycbe82602011-05-22 19:52:37 +03009467{
9468 struct rpc_task *task;
9469 struct rpc_message msg = {
9470 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN],
9471 .rpc_argp = &lrp->args,
9472 .rpc_resp = &lrp->res,
Trond Myklebust95560002013-05-20 10:43:47 -04009473 .rpc_cred = lrp->cred,
Benny Halevycbe82602011-05-22 19:52:37 +03009474 };
9475 struct rpc_task_setup task_setup_data = {
Andy Adamson1771c572013-07-22 12:42:05 -04009476 .rpc_client = NFS_SERVER(lrp->args.inode)->client,
Benny Halevycbe82602011-05-22 19:52:37 +03009477 .rpc_message = &msg,
9478 .callback_ops = &nfs4_layoutreturn_call_ops,
9479 .callback_data = lrp,
9480 };
Peng Tao6c166052014-11-17 09:30:40 +08009481 int status = 0;
Benny Halevycbe82602011-05-22 19:52:37 +03009482
Andrew Elble99ade3c2015-12-02 09:39:51 -05009483 nfs4_state_protect(NFS_SERVER(lrp->args.inode)->nfs_client,
9484 NFS_SP4_MACH_CRED_PNFS_CLEANUP,
9485 &task_setup_data.rpc_client, &msg);
9486
Benny Halevycbe82602011-05-22 19:52:37 +03009487 dprintk("--> %s\n", __func__);
Trond Myklebust5a0ec8ac2015-02-05 16:35:16 -05009488 if (!sync) {
9489 lrp->inode = nfs_igrab_and_active(lrp->args.inode);
9490 if (!lrp->inode) {
9491 nfs4_layoutreturn_release(lrp);
9492 return -EAGAIN;
9493 }
9494 task_setup_data.flags |= RPC_TASK_ASYNC;
9495 }
Anna Schumakerfba83f32018-05-04 16:22:50 -04009496 nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1, 0);
Benny Halevycbe82602011-05-22 19:52:37 +03009497 task = rpc_run_task(&task_setup_data);
9498 if (IS_ERR(task))
9499 return PTR_ERR(task);
Trond Myklebust5a0ec8ac2015-02-05 16:35:16 -05009500 if (sync)
9501 status = task->tk_status;
Olga Kornievskaia48c95792015-11-24 13:29:41 -05009502 trace_nfs4_layoutreturn(lrp->args.inode, &lrp->args.stateid, status);
Benny Halevycbe82602011-05-22 19:52:37 +03009503 dprintk("<-- %s status=%d\n", __func__, status);
9504 rpc_put_task(task);
9505 return status;
9506}
9507
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009508static int
Trond Myklebustcd5875f2013-05-20 11:42:54 -04009509_nfs4_proc_getdeviceinfo(struct nfs_server *server,
9510 struct pnfs_device *pdev,
NeilBrowna52458b2018-12-03 11:30:31 +11009511 const struct cred *cred)
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009512{
9513 struct nfs4_getdeviceinfo_args args = {
9514 .pdev = pdev,
Trond Myklebust4e590802015-03-09 14:01:25 -04009515 .notify_types = NOTIFY_DEVICEID4_CHANGE |
9516 NOTIFY_DEVICEID4_DELETE,
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009517 };
9518 struct nfs4_getdeviceinfo_res res = {
9519 .pdev = pdev,
9520 };
9521 struct rpc_message msg = {
9522 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO],
9523 .rpc_argp = &args,
9524 .rpc_resp = &res,
Trond Myklebustcd5875f2013-05-20 11:42:54 -04009525 .rpc_cred = cred,
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009526 };
9527 int status;
9528
9529 dprintk("--> %s\n", __func__);
Bryan Schumaker7c513052011-03-24 17:12:24 +00009530 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Trond Myklebust4e590802015-03-09 14:01:25 -04009531 if (res.notification & ~args.notify_types)
9532 dprintk("%s: unsupported notification\n", __func__);
Trond Myklebustdf526992015-03-09 14:48:32 -04009533 if (res.notification != args.notify_types)
9534 pdev->nocache = 1;
Trond Myklebust4e590802015-03-09 14:01:25 -04009535
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009536 dprintk("<-- %s status=%d\n", __func__, status);
9537
9538 return status;
9539}
9540
Trond Myklebustcd5875f2013-05-20 11:42:54 -04009541int nfs4_proc_getdeviceinfo(struct nfs_server *server,
9542 struct pnfs_device *pdev,
NeilBrowna52458b2018-12-03 11:30:31 +11009543 const struct cred *cred)
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009544{
9545 struct nfs4_exception exception = { };
9546 int err;
9547
9548 do {
9549 err = nfs4_handle_exception(server,
Trond Myklebustcd5875f2013-05-20 11:42:54 -04009550 _nfs4_proc_getdeviceinfo(server, pdev, cred),
Andy Adamsonb1f69b72010-10-20 00:18:03 -04009551 &exception);
9552 } while (exception.retry);
9553 return err;
9554}
9555EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo);
9556
Andy Adamson863a3c62011-03-23 13:27:54 +00009557static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
9558{
9559 struct nfs4_layoutcommit_data *data = calldata;
9560 struct nfs_server *server = NFS_SERVER(data->args.inode);
9561
Anna Schumaker7981c8a2017-01-10 11:39:53 -05009562 nfs4_setup_sequence(server->nfs_client,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04009563 &data->args.seq_args,
9564 &data->res.seq_res,
9565 task);
Andy Adamson863a3c62011-03-23 13:27:54 +00009566}
9567
9568static void
9569nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
9570{
9571 struct nfs4_layoutcommit_data *data = calldata;
9572 struct nfs_server *server = NFS_SERVER(data->args.inode);
9573
Trond Myklebust6ba7db32012-10-22 20:07:20 -04009574 if (!nfs41_sequence_done(task, &data->res.seq_res))
Andy Adamson863a3c62011-03-23 13:27:54 +00009575 return;
9576
9577 switch (task->tk_status) { /* Just ignore these failures */
Trond Myklebuste59d27e2012-03-27 18:22:19 -04009578 case -NFS4ERR_DELEG_REVOKED: /* layout was recalled */
9579 case -NFS4ERR_BADIOMODE: /* no IOMODE_RW layout for range */
9580 case -NFS4ERR_BADLAYOUT: /* no layout */
9581 case -NFS4ERR_GRACE: /* loca_recalim always false */
Andy Adamson863a3c62011-03-23 13:27:54 +00009582 task->tk_status = 0;
Trond Myklebuste59d27e2012-03-27 18:22:19 -04009583 case 0:
Trond Myklebuste59d27e2012-03-27 18:22:19 -04009584 break;
9585 default:
NeilBrown8478eaa2014-09-18 16:09:27 +10009586 if (nfs4_async_handle_error(task, server, NULL, NULL) == -EAGAIN) {
Trond Myklebuste59d27e2012-03-27 18:22:19 -04009587 rpc_restart_call_prepare(task);
9588 return;
9589 }
9590 }
Andy Adamson863a3c62011-03-23 13:27:54 +00009591}
9592
9593static void nfs4_layoutcommit_release(void *calldata)
9594{
9595 struct nfs4_layoutcommit_data *data = calldata;
9596
Andy Adamsondb29c082011-07-30 20:52:38 -04009597 pnfs_cleanup_layoutcommit(data);
Trond Myklebustd8c951c2014-01-13 12:08:11 -05009598 nfs_post_op_update_inode_force_wcc(data->args.inode,
9599 data->res.fattr);
NeilBrowna52458b2018-12-03 11:30:31 +11009600 put_cred(data->cred);
Trond Myklebust472e2592015-02-05 16:50:30 -05009601 nfs_iput_and_deactive(data->inode);
Andy Adamson863a3c62011-03-23 13:27:54 +00009602 kfree(data);
9603}
9604
9605static const struct rpc_call_ops nfs4_layoutcommit_ops = {
9606 .rpc_call_prepare = nfs4_layoutcommit_prepare,
9607 .rpc_call_done = nfs4_layoutcommit_done,
9608 .rpc_release = nfs4_layoutcommit_release,
9609};
9610
9611int
Andy Adamsonef311532011-03-12 02:58:10 -05009612nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
Andy Adamson863a3c62011-03-23 13:27:54 +00009613{
9614 struct rpc_message msg = {
9615 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTCOMMIT],
9616 .rpc_argp = &data->args,
9617 .rpc_resp = &data->res,
9618 .rpc_cred = data->cred,
9619 };
9620 struct rpc_task_setup task_setup_data = {
9621 .task = &data->task,
9622 .rpc_client = NFS_CLIENT(data->args.inode),
9623 .rpc_message = &msg,
9624 .callback_ops = &nfs4_layoutcommit_ops,
9625 .callback_data = data,
Andy Adamson863a3c62011-03-23 13:27:54 +00009626 };
9627 struct rpc_task *task;
9628 int status = 0;
9629
Kinglong Meeb4839eb2015-07-01 12:00:13 +08009630 dprintk("NFS: initiating layoutcommit call. sync %d "
9631 "lbw: %llu inode %lu\n", sync,
Andy Adamson863a3c62011-03-23 13:27:54 +00009632 data->args.lastbytewritten,
9633 data->args.inode->i_ino);
9634
Trond Myklebust472e2592015-02-05 16:50:30 -05009635 if (!sync) {
9636 data->inode = nfs_igrab_and_active(data->args.inode);
9637 if (data->inode == NULL) {
9638 nfs4_layoutcommit_release(data);
9639 return -EAGAIN;
9640 }
9641 task_setup_data.flags = RPC_TASK_ASYNC;
9642 }
Anna Schumakerfba83f32018-05-04 16:22:50 -04009643 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1, 0);
Andy Adamson863a3c62011-03-23 13:27:54 +00009644 task = rpc_run_task(&task_setup_data);
9645 if (IS_ERR(task))
9646 return PTR_ERR(task);
Trond Myklebust472e2592015-02-05 16:50:30 -05009647 if (sync)
9648 status = task->tk_status;
Olga Kornievskaia48c95792015-11-24 13:29:41 -05009649 trace_nfs4_layoutcommit(data->args.inode, &data->args.stateid, status);
Andy Adamson863a3c62011-03-23 13:27:54 +00009650 dprintk("%s: status %d\n", __func__, status);
9651 rpc_put_task(task);
9652 return status;
9653}
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009654
Trond Myklebust302fad72019-02-18 13:32:38 -05009655/*
Andy Adamson97431202013-08-08 10:57:56 -04009656 * Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
9657 * possible) as per RFC3530bis and RFC5661 Security Considerations sections
9658 */
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009659static int
9660_nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04009661 struct nfs_fsinfo *info,
9662 struct nfs4_secinfo_flavors *flavors, bool use_integrity)
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009663{
9664 struct nfs41_secinfo_no_name_args args = {
9665 .style = SECINFO_STYLE_CURRENT_FH,
9666 };
9667 struct nfs4_secinfo_res res = {
9668 .flavors = flavors,
9669 };
9670 struct rpc_message msg = {
9671 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO_NO_NAME],
9672 .rpc_argp = &args,
9673 .rpc_resp = &res,
9674 };
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04009675 struct rpc_clnt *clnt = server->client;
Anna Schumakercc15e242019-08-14 16:22:31 -04009676 struct nfs4_call_sync_data data = {
9677 .seq_server = server,
9678 .seq_args = &args.seq_args,
9679 .seq_res = &res.seq_res,
9680 };
9681 struct rpc_task_setup task_setup = {
9682 .rpc_client = server->client,
9683 .rpc_message = &msg,
9684 .callback_ops = server->nfs_client->cl_mvops->call_sync_ops,
9685 .callback_data = &data,
9686 .flags = RPC_TASK_NO_ROUND_ROBIN,
9687 };
NeilBrowna52458b2018-12-03 11:30:31 +11009688 const struct cred *cred = NULL;
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04009689 int status;
9690
9691 if (use_integrity) {
9692 clnt = server->nfs_client->cl_rpcclient;
Anna Schumakercc15e242019-08-14 16:22:31 -04009693 task_setup.rpc_client = clnt;
9694
Weston Andros Adamson7cb852d2013-09-10 18:44:31 -04009695 cred = nfs4_get_clid_cred(server->nfs_client);
9696 msg.rpc_cred = cred;
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04009697 }
9698
9699 dprintk("--> %s\n", __func__);
Anna Schumakercc15e242019-08-14 16:22:31 -04009700 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
9701 status = nfs4_call_sync_custom(&task_setup);
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04009702 dprintk("<-- %s status=%d\n", __func__, status);
9703
NeilBrowna52458b2018-12-03 11:30:31 +11009704 put_cred(cred);
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04009705
9706 return status;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009707}
9708
9709static int
9710nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
9711 struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
9712{
Trond Myklebust0688e642019-04-07 13:59:09 -04009713 struct nfs4_exception exception = {
9714 .interruptible = true,
9715 };
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009716 int err;
9717 do {
Weston Andros Adamsonb1b3e132013-09-04 12:13:19 -04009718 /* first try using integrity protection */
9719 err = -NFS4ERR_WRONGSEC;
9720
9721 /* try to use integrity protection with machine cred */
9722 if (_nfs4_is_integrity_protected(server->nfs_client))
9723 err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
9724 flavors, true);
9725
9726 /*
9727 * if unable to use integrity protection, or SECINFO with
9728 * integrity protection returns NFS4ERR_WRONGSEC (which is
9729 * disallowed by spec, but exists in deployed servers) use
9730 * the current filesystem's rpc_client and the user cred.
9731 */
9732 if (err == -NFS4ERR_WRONGSEC)
9733 err = _nfs41_proc_secinfo_no_name(server, fhandle, info,
9734 flavors, false);
9735
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009736 switch (err) {
9737 case 0:
9738 case -NFS4ERR_WRONGSEC:
Weston Andros Adamson78b19ba2014-01-13 16:54:45 -05009739 case -ENOTSUPP:
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04009740 goto out;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009741 default:
9742 err = nfs4_handle_exception(server, err, &exception);
9743 }
9744 } while (exception.retry);
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04009745out:
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009746 return err;
9747}
9748
9749static int
9750nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
9751 struct nfs_fsinfo *info)
9752{
9753 int err;
9754 struct page *page;
Anna Schumaker367156d2013-09-25 17:02:48 -04009755 rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009756 struct nfs4_secinfo_flavors *flavors;
Weston Andros Adamson58a8cf12013-09-24 13:58:02 -04009757 struct nfs4_secinfo4 *secinfo;
9758 int i;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009759
9760 page = alloc_page(GFP_KERNEL);
9761 if (!page) {
9762 err = -ENOMEM;
9763 goto out;
9764 }
9765
9766 flavors = page_address(page);
9767 err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
9768
9769 /*
9770 * Fall back on "guess and check" method if
9771 * the server doesn't support SECINFO_NO_NAME
9772 */
Weston Andros Adamson78b19ba2014-01-13 16:54:45 -05009773 if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009774 err = nfs4_find_root_sec(server, fhandle, info);
9775 goto out_freepage;
9776 }
9777 if (err)
9778 goto out_freepage;
9779
Weston Andros Adamson58a8cf12013-09-24 13:58:02 -04009780 for (i = 0; i < flavors->num_flavors; i++) {
9781 secinfo = &flavors->flavors[i];
9782
9783 switch (secinfo->flavor) {
9784 case RPC_AUTH_NULL:
9785 case RPC_AUTH_UNIX:
9786 case RPC_AUTH_GSS:
9787 flavor = rpcauth_get_pseudoflavor(secinfo->flavor,
9788 &secinfo->flavor_info);
9789 break;
9790 default:
9791 flavor = RPC_AUTH_MAXFLAVOR;
9792 break;
9793 }
9794
Weston Andros Adamson4d4b69d2013-10-18 15:15:19 -04009795 if (!nfs_auth_info_match(&server->auth_info, flavor))
9796 flavor = RPC_AUTH_MAXFLAVOR;
9797
Weston Andros Adamson58a8cf12013-09-24 13:58:02 -04009798 if (flavor != RPC_AUTH_MAXFLAVOR) {
9799 err = nfs4_lookup_root_sec(server, fhandle,
9800 info, flavor);
9801 if (!err)
9802 break;
9803 }
9804 }
9805
9806 if (flavor == RPC_AUTH_MAXFLAVOR)
9807 err = -EPERM;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04009808
9809out_freepage:
9810 put_page(page);
9811 if (err == -EACCES)
9812 return -EPERM;
9813out:
9814 return err;
9815}
Bryan Schumaker1cab0652012-01-31 10:39:29 -05009816
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009817static int _nfs41_test_stateid(struct nfs_server *server,
9818 nfs4_stateid *stateid,
NeilBrowna52458b2018-12-03 11:30:31 +11009819 const struct cred *cred)
Bryan Schumaker7d974792011-06-02 14:59:08 -04009820{
9821 int status;
9822 struct nfs41_test_stateid_args args = {
Bryan Schumaker1cab0652012-01-31 10:39:29 -05009823 .stateid = stateid,
Bryan Schumaker7d974792011-06-02 14:59:08 -04009824 };
9825 struct nfs41_test_stateid_res res;
9826 struct rpc_message msg = {
9827 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID],
9828 .rpc_argp = &args,
9829 .rpc_resp = &res,
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009830 .rpc_cred = cred,
Bryan Schumaker7d974792011-06-02 14:59:08 -04009831 };
Weston Andros Adamson3787d502013-08-13 16:37:36 -04009832 struct rpc_clnt *rpc_client = server->client;
9833
9834 nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
9835 &rpc_client, &msg);
Bryan Schumaker1cab0652012-01-31 10:39:29 -05009836
Chuck Lever38527b12012-07-11 16:30:23 -04009837 dprintk("NFS call test_stateid %p\n", stateid);
Anna Schumakerfba83f32018-05-04 16:22:50 -04009838 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 1);
Weston Andros Adamson3787d502013-08-13 16:37:36 -04009839 status = nfs4_call_sync_sequence(rpc_client, server, &msg,
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04009840 &args.seq_args, &res.seq_res);
Chuck Lever38527b12012-07-11 16:30:23 -04009841 if (status != NFS_OK) {
9842 dprintk("NFS reply test_stateid: failed, %d\n", status);
Chuck Lever377e5072012-07-11 16:29:45 -04009843 return status;
Chuck Lever38527b12012-07-11 16:30:23 -04009844 }
9845 dprintk("NFS reply test_stateid: succeeded, %d\n", -res.status);
Chuck Lever377e5072012-07-11 16:29:45 -04009846 return -res.status;
Bryan Schumaker7d974792011-06-02 14:59:08 -04009847}
9848
Trond Myklebust43912bb2016-09-22 13:38:56 -04009849static void nfs4_handle_delay_or_session_error(struct nfs_server *server,
9850 int err, struct nfs4_exception *exception)
9851{
9852 exception->retry = 0;
9853 switch(err) {
9854 case -NFS4ERR_DELAY:
Trond Myklebust76e8a1b2016-09-22 13:39:19 -04009855 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebust43912bb2016-09-22 13:38:56 -04009856 nfs4_handle_exception(server, err, exception);
9857 break;
9858 case -NFS4ERR_BADSESSION:
9859 case -NFS4ERR_BADSLOT:
9860 case -NFS4ERR_BAD_HIGH_SLOT:
9861 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
9862 case -NFS4ERR_DEADSESSION:
9863 nfs4_do_handle_exception(server, err, exception);
9864 }
9865}
9866
Chuck Lever38527b12012-07-11 16:30:23 -04009867/**
9868 * nfs41_test_stateid - perform a TEST_STATEID operation
9869 *
9870 * @server: server / transport on which to perform the operation
9871 * @stateid: state ID to test
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009872 * @cred: credential
Chuck Lever38527b12012-07-11 16:30:23 -04009873 *
9874 * Returns NFS_OK if the server recognizes that "stateid" is valid.
9875 * Otherwise a negative NFS4ERR value is returned if the operation
9876 * failed or the state ID is not currently valid.
9877 */
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009878static int nfs41_test_stateid(struct nfs_server *server,
9879 nfs4_stateid *stateid,
NeilBrowna52458b2018-12-03 11:30:31 +11009880 const struct cred *cred)
Bryan Schumaker7d974792011-06-02 14:59:08 -04009881{
Trond Myklebust0688e642019-04-07 13:59:09 -04009882 struct nfs4_exception exception = {
9883 .interruptible = true,
9884 };
Bryan Schumaker7d974792011-06-02 14:59:08 -04009885 int err;
9886 do {
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009887 err = _nfs41_test_stateid(server, stateid, cred);
Trond Myklebust43912bb2016-09-22 13:38:56 -04009888 nfs4_handle_delay_or_session_error(server, err, &exception);
Bryan Schumaker7d974792011-06-02 14:59:08 -04009889 } while (exception.retry);
9890 return err;
9891}
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009892
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009893struct nfs_free_stateid_data {
9894 struct nfs_server *server;
9895 struct nfs41_free_stateid_args args;
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009896 struct nfs41_free_stateid_res res;
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009897};
9898
9899static void nfs41_free_stateid_prepare(struct rpc_task *task, void *calldata)
9900{
9901 struct nfs_free_stateid_data *data = calldata;
Anna Schumaker7981c8a2017-01-10 11:39:53 -05009902 nfs4_setup_sequence(data->server->nfs_client,
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009903 &data->args.seq_args,
9904 &data->res.seq_res,
9905 task);
9906}
9907
9908static void nfs41_free_stateid_done(struct rpc_task *task, void *calldata)
9909{
9910 struct nfs_free_stateid_data *data = calldata;
9911
9912 nfs41_sequence_done(task, &data->res.seq_res);
9913
9914 switch (task->tk_status) {
9915 case -NFS4ERR_DELAY:
NeilBrown8478eaa2014-09-18 16:09:27 +10009916 if (nfs4_async_handle_error(task, data->server, NULL, NULL) == -EAGAIN)
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009917 rpc_restart_call_prepare(task);
9918 }
9919}
9920
9921static void nfs41_free_stateid_release(void *calldata)
9922{
9923 kfree(calldata);
9924}
9925
Trond Myklebust17f26b12013-08-21 15:48:42 -04009926static const struct rpc_call_ops nfs41_free_stateid_ops = {
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009927 .rpc_call_prepare = nfs41_free_stateid_prepare,
9928 .rpc_call_done = nfs41_free_stateid_done,
9929 .rpc_release = nfs41_free_stateid_release,
9930};
9931
Anna Schumaker2f261022018-05-15 13:03:39 -04009932/**
9933 * nfs41_free_stateid - perform a FREE_STATEID operation
9934 *
9935 * @server: server / transport on which to perform the operation
9936 * @stateid: state ID to release
9937 * @cred: credential
Trond Myklebust302fad72019-02-18 13:32:38 -05009938 * @privileged: set to true if this call needs to be privileged
Anna Schumaker2f261022018-05-15 13:03:39 -04009939 *
9940 * Note: this function is always asynchronous.
9941 */
9942static int nfs41_free_stateid(struct nfs_server *server,
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009943 const nfs4_stateid *stateid,
NeilBrowna52458b2018-12-03 11:30:31 +11009944 const struct cred *cred,
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009945 bool privileged)
9946{
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009947 struct rpc_message msg = {
9948 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID],
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04009949 .rpc_cred = cred,
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009950 };
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009951 struct rpc_task_setup task_setup = {
9952 .rpc_client = server->client,
9953 .rpc_message = &msg,
9954 .callback_ops = &nfs41_free_stateid_ops,
9955 .flags = RPC_TASK_ASYNC,
9956 };
9957 struct nfs_free_stateid_data *data;
Anna Schumaker2f261022018-05-15 13:03:39 -04009958 struct rpc_task *task;
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009959
Weston Andros Adamson3787d502013-08-13 16:37:36 -04009960 nfs4_state_protect(server->nfs_client, NFS_SP4_MACH_CRED_STATEID,
9961 &task_setup.rpc_client, &msg);
9962
Chuck Lever38527b12012-07-11 16:30:23 -04009963 dprintk("NFS call free_stateid %p\n", stateid);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009964 data = kmalloc(sizeof(*data), GFP_NOFS);
9965 if (!data)
Anna Schumaker2f261022018-05-15 13:03:39 -04009966 return -ENOMEM;
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009967 data->server = server;
9968 nfs4_stateid_copy(&data->args.stateid, stateid);
9969
9970 task_setup.callback_data = data;
9971
9972 msg.rpc_argp = &data->args;
9973 msg.rpc_resp = &data->res;
Anna Schumakerfba83f32018-05-04 16:22:50 -04009974 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1, privileged);
Anna Schumaker2f261022018-05-15 13:03:39 -04009975 task = rpc_run_task(&task_setup);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009976 if (IS_ERR(task))
9977 return PTR_ERR(task);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04009978 rpc_put_task(task);
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009979 return 0;
Bryan Schumaker9aeda352011-06-02 14:59:09 -04009980}
Trond Myklebust36281ca2012-03-04 18:13:56 -05009981
Jeff Laytonf1cdae82014-05-01 06:28:47 -04009982static void
9983nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009984{
NeilBrowna52458b2018-12-03 11:30:31 +11009985 const struct cred *cred = lsp->ls_state->owner->so_cred;
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009986
Trond Myklebustf0b0bf82016-09-22 13:39:04 -04009987 nfs41_free_stateid(server, &lsp->ls_stateid, cred, false);
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009988 nfs4_free_lock_state(server, lsp);
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04009989}
9990
Trond Myklebust36281ca2012-03-04 18:13:56 -05009991static bool nfs41_match_stateid(const nfs4_stateid *s1,
9992 const nfs4_stateid *s2)
9993{
Trond Myklebust93b717f2016-05-16 17:42:43 -04009994 if (s1->type != s2->type)
9995 return false;
9996
Trond Myklebust2d2f24a2012-03-04 18:13:57 -05009997 if (memcmp(s1->other, s2->other, sizeof(s1->other)) != 0)
Trond Myklebust36281ca2012-03-04 18:13:56 -05009998 return false;
9999
Trond Myklebust2d2f24a2012-03-04 18:13:57 -050010000 if (s1->seqid == s2->seqid)
Trond Myklebust36281ca2012-03-04 18:13:56 -050010001 return true;
Trond Myklebust36281ca2012-03-04 18:13:56 -050010002
Anna Schumaker045c5512017-01-11 16:59:48 -050010003 return s1->seqid == 0 || s2->seqid == 0;
Trond Myklebust36281ca2012-03-04 18:13:56 -050010004}
10005
Andy Adamson557134a2009-04-01 09:21:53 -040010006#endif /* CONFIG_NFS_V4_1 */
10007
Trond Myklebust36281ca2012-03-04 18:13:56 -050010008static bool nfs4_match_stateid(const nfs4_stateid *s1,
10009 const nfs4_stateid *s2)
10010{
Trond Myklebustf597c532012-03-04 18:13:56 -050010011 return nfs4_stateid_match(s1, s2);
Trond Myklebust36281ca2012-03-04 18:13:56 -050010012}
10013
10014
Trond Myklebust17280172012-03-11 13:11:00 -040010015static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
Trond Myklebust7eff03a2008-12-23 15:21:43 -050010016 .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
Trond Myklebustb79a4a12008-12-23 15:21:41 -050010017 .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010018 .recover_open = nfs4_open_reclaim,
10019 .recover_lock = nfs4_lock_reclaim,
Andy Adamson591d71c2009-04-01 09:22:47 -040010020 .establish_clid = nfs4_init_clientid,
Chuck Lever05f4c352012-09-14 17:24:32 -040010021 .detect_trunking = nfs40_discover_server_trunking,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010022};
10023
Andy Adamson591d71c2009-04-01 09:22:47 -040010024#if defined(CONFIG_NFS_V4_1)
Trond Myklebust17280172012-03-11 13:11:00 -040010025static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
Andy Adamson591d71c2009-04-01 09:22:47 -040010026 .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
10027 .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
10028 .recover_open = nfs4_open_reclaim,
10029 .recover_lock = nfs4_lock_reclaim,
Andy Adamson4d643d12009-12-04 15:52:24 -050010030 .establish_clid = nfs41_init_clientid,
Ricardo Labiagafce5c832009-12-05 16:08:41 -050010031 .reclaim_complete = nfs41_proc_reclaim_complete,
Chuck Lever05f4c352012-09-14 17:24:32 -040010032 .detect_trunking = nfs41_discover_server_trunking,
Andy Adamson591d71c2009-04-01 09:22:47 -040010033};
10034#endif /* CONFIG_NFS_V4_1 */
10035
Trond Myklebust17280172012-03-11 13:11:00 -040010036static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
Trond Myklebust7eff03a2008-12-23 15:21:43 -050010037 .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
Trond Myklebustb79a4a12008-12-23 15:21:41 -050010038 .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
Trond Myklebust4dfd4f72014-10-17 15:10:25 +030010039 .recover_open = nfs40_open_expired,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010040 .recover_lock = nfs4_lock_expired,
Andy Adamson591d71c2009-04-01 09:22:47 -040010041 .establish_clid = nfs4_init_clientid,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010042};
10043
Andy Adamson591d71c2009-04-01 09:22:47 -040010044#if defined(CONFIG_NFS_V4_1)
Trond Myklebust17280172012-03-11 13:11:00 -040010045static const struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
Andy Adamson591d71c2009-04-01 09:22:47 -040010046 .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
10047 .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
Bryan Schumakerf062eb62011-06-02 14:59:10 -040010048 .recover_open = nfs41_open_expired,
10049 .recover_lock = nfs41_lock_expired,
Andy Adamson4d643d12009-12-04 15:52:24 -050010050 .establish_clid = nfs41_init_clientid,
Andy Adamson591d71c2009-04-01 09:22:47 -040010051};
10052#endif /* CONFIG_NFS_V4_1 */
10053
Trond Myklebust17280172012-03-11 13:11:00 -040010054static const struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
Benny Halevy29fba382009-04-01 09:22:44 -040010055 .sched_state_renewal = nfs4_proc_async_renew,
NeilBrownf15e1e82018-12-03 11:30:30 +110010056 .get_state_renewal_cred = nfs4_get_renew_cred,
Benny Halevy8e69514f2009-04-01 09:22:45 -040010057 .renew_lease = nfs4_proc_renew,
Benny Halevy29fba382009-04-01 09:22:44 -040010058};
10059
10060#if defined(CONFIG_NFS_V4_1)
Trond Myklebust17280172012-03-11 13:11:00 -040010061static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
Benny Halevy29fba382009-04-01 09:22:44 -040010062 .sched_state_renewal = nfs41_proc_async_sequence,
NeilBrownf15e1e82018-12-03 11:30:30 +110010063 .get_state_renewal_cred = nfs4_get_machine_cred,
Benny Halevy8e69514f2009-04-01 09:22:45 -040010064 .renew_lease = nfs4_proc_sequence,
Benny Halevy29fba382009-04-01 09:22:44 -040010065};
10066#endif
10067
Chuck Leverec011fe2013-10-17 14:12:39 -040010068static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = {
Chuck Leverb03d7352013-10-17 14:12:50 -040010069 .get_locations = _nfs40_proc_get_locations,
Chuck Lever44c99932013-10-17 14:13:30 -040010070 .fsid_present = _nfs40_proc_fsid_present,
Chuck Leverec011fe2013-10-17 14:12:39 -040010071};
10072
10073#if defined(CONFIG_NFS_V4_1)
10074static const struct nfs4_mig_recovery_ops nfs41_mig_recovery_ops = {
Chuck Leverb03d7352013-10-17 14:12:50 -040010075 .get_locations = _nfs41_proc_get_locations,
Chuck Lever44c99932013-10-17 14:13:30 -040010076 .fsid_present = _nfs41_proc_fsid_present,
Chuck Leverec011fe2013-10-17 14:12:39 -040010077};
10078#endif /* CONFIG_NFS_V4_1 */
10079
Trond Myklebust97dc1352010-06-16 09:52:26 -040010080static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
10081 .minor_version = 0,
Trond Myklebust39c6daa2013-03-15 16:11:57 -040010082 .init_caps = NFS_CAP_READDIRPLUS
10083 | NFS_CAP_ATOMIC_OPEN
Trond Myklebust39c6daa2013-03-15 16:11:57 -040010084 | NFS_CAP_POSIX_LOCK,
Chuck Leverabf79bb2013-08-09 12:49:11 -040010085 .init_client = nfs40_init_client,
10086 .shutdown_client = nfs40_shutdown_client,
Trond Myklebust36281ca2012-03-04 18:13:56 -050010087 .match_stateid = nfs4_match_stateid,
Bryan Schumakerfca78d62011-06-02 14:59:07 -040010088 .find_root_sec = nfs4_find_root_sec,
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -040010089 .free_lock_state = nfs4_release_lockowner,
Trond Myklebust45870d62016-09-22 13:38:59 -040010090 .test_and_free_expired = nfs40_test_and_free_expired_stateid,
Trond Myklebust63f5f792015-01-23 19:19:25 -050010091 .alloc_seqid = nfs_alloc_seqid,
Chuck Lever9915ea72013-08-09 12:48:27 -040010092 .call_sync_ops = &nfs40_call_sync_ops,
Trond Myklebustc48f4f32010-06-16 09:52:27 -040010093 .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
10094 .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
10095 .state_renewal_ops = &nfs40_state_renewal_ops,
Chuck Leverec011fe2013-10-17 14:12:39 -040010096 .mig_recovery_ops = &nfs40_mig_recovery_ops,
Trond Myklebust97dc1352010-06-16 09:52:26 -040010097};
10098
10099#if defined(CONFIG_NFS_V4_1)
Trond Myklebust63f5f792015-01-23 19:19:25 -050010100static struct nfs_seqid *
10101nfs_alloc_no_seqid(struct nfs_seqid_counter *arg1, gfp_t arg2)
10102{
10103 return NULL;
10104}
10105
Trond Myklebust97dc1352010-06-16 09:52:26 -040010106static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
10107 .minor_version = 1,
Trond Myklebust39c6daa2013-03-15 16:11:57 -040010108 .init_caps = NFS_CAP_READDIRPLUS
10109 | NFS_CAP_ATOMIC_OPEN
Trond Myklebust3b664862013-03-17 15:31:15 -040010110 | NFS_CAP_POSIX_LOCK
Trond Myklebust49f9a0f2013-03-15 16:44:28 -040010111 | NFS_CAP_STATEID_NFSV41
Fred Isaman6e012602016-10-04 15:26:41 -040010112 | NFS_CAP_ATOMIC_OPEN_V1
10113 | NFS_CAP_LGOPEN,
Chuck Leverabf79bb2013-08-09 12:49:11 -040010114 .init_client = nfs41_init_client,
10115 .shutdown_client = nfs41_shutdown_client,
Trond Myklebust36281ca2012-03-04 18:13:56 -050010116 .match_stateid = nfs41_match_stateid,
Bryan Schumakerfca78d62011-06-02 14:59:07 -040010117 .find_root_sec = nfs41_find_root_sec,
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -040010118 .free_lock_state = nfs41_free_lock_state,
Trond Myklebust45870d62016-09-22 13:38:59 -040010119 .test_and_free_expired = nfs41_test_and_free_expired_stateid,
Trond Myklebust63f5f792015-01-23 19:19:25 -050010120 .alloc_seqid = nfs_alloc_no_seqid,
Andy Adamson04fa2c62016-09-09 09:22:29 -040010121 .session_trunk = nfs4_test_session_trunk,
Chuck Lever9915ea72013-08-09 12:48:27 -040010122 .call_sync_ops = &nfs41_call_sync_ops,
Trond Myklebustc48f4f32010-06-16 09:52:27 -040010123 .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
10124 .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
10125 .state_renewal_ops = &nfs41_state_renewal_ops,
Chuck Leverec011fe2013-10-17 14:12:39 -040010126 .mig_recovery_ops = &nfs41_mig_recovery_ops,
Trond Myklebust97dc1352010-06-16 09:52:26 -040010127};
10128#endif
10129
Steve Dickson42c2c422013-05-22 12:50:38 -040010130#if defined(CONFIG_NFS_V4_2)
10131static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
10132 .minor_version = 2,
Bryan Schumaker70173102013-06-19 13:41:43 -040010133 .init_caps = NFS_CAP_READDIRPLUS
10134 | NFS_CAP_ATOMIC_OPEN
Bryan Schumaker70173102013-06-19 13:41:43 -040010135 | NFS_CAP_POSIX_LOCK
10136 | NFS_CAP_STATEID_NFSV41
Anna Schumakere9831202014-10-22 15:53:10 -040010137 | NFS_CAP_ATOMIC_OPEN_V1
Fred Isaman6e012602016-10-04 15:26:41 -040010138 | NFS_CAP_LGOPEN
Anna Schumakerf4ac1672014-11-25 13:18:15 -050010139 | NFS_CAP_ALLOCATE
Anna Schumaker2e724482013-05-21 16:53:03 -040010140 | NFS_CAP_COPY
Olga Kornievskaiacb95dee2018-07-09 15:13:29 -040010141 | NFS_CAP_OFFLOAD_CANCEL
Olga Kornievskaia04915672019-06-04 16:14:30 -040010142 | NFS_CAP_COPY_NOTIFY
Anna Schumaker624bd5b2014-11-25 13:18:16 -050010143 | NFS_CAP_DEALLOCATE
Trond Myklebust6c5a0d82015-06-27 11:45:46 -040010144 | NFS_CAP_SEEK
Peng Taoe5341f32015-09-26 02:24:35 +080010145 | NFS_CAP_LAYOUTSTATS
Trond Myklebust3eb86092019-02-08 10:31:05 -050010146 | NFS_CAP_CLONE
10147 | NFS_CAP_LAYOUTERROR,
Chuck Leverabf79bb2013-08-09 12:49:11 -040010148 .init_client = nfs41_init_client,
10149 .shutdown_client = nfs41_shutdown_client,
Steve Dickson42c2c422013-05-22 12:50:38 -040010150 .match_stateid = nfs41_match_stateid,
10151 .find_root_sec = nfs41_find_root_sec,
Bryan Schumaker70173102013-06-19 13:41:43 -040010152 .free_lock_state = nfs41_free_lock_state,
Chuck Lever9915ea72013-08-09 12:48:27 -040010153 .call_sync_ops = &nfs41_call_sync_ops,
Trond Myklebust45870d62016-09-22 13:38:59 -040010154 .test_and_free_expired = nfs41_test_and_free_expired_stateid,
Trond Myklebust63f5f792015-01-23 19:19:25 -050010155 .alloc_seqid = nfs_alloc_no_seqid,
Andy Adamson04fa2c62016-09-09 09:22:29 -040010156 .session_trunk = nfs4_test_session_trunk,
Steve Dickson42c2c422013-05-22 12:50:38 -040010157 .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
10158 .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
10159 .state_renewal_ops = &nfs41_state_renewal_ops,
Kinglong Mee18e3b732015-08-15 21:52:10 +080010160 .mig_recovery_ops = &nfs41_mig_recovery_ops,
Steve Dickson42c2c422013-05-22 12:50:38 -040010161};
10162#endif
10163
Trond Myklebust97dc1352010-06-16 09:52:26 -040010164const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
10165 [0] = &nfs_v4_0_minor_ops,
10166#if defined(CONFIG_NFS_V4_1)
10167 [1] = &nfs_v4_1_minor_ops,
10168#endif
Steve Dickson42c2c422013-05-22 12:50:38 -040010169#if defined(CONFIG_NFS_V4_2)
10170 [2] = &nfs_v4_2_minor_ops,
10171#endif
Trond Myklebust97dc1352010-06-16 09:52:26 -040010172};
10173
Trond Myklebust13997822016-07-24 17:10:52 -040010174static ssize_t nfs4_listxattr(struct dentry *dentry, char *list, size_t size)
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +010010175{
Frank van der Linden012a2112020-06-23 22:39:03 +000010176 ssize_t error, error2, error3;
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +010010177
10178 error = generic_listxattr(dentry, list, size);
10179 if (error < 0)
10180 return error;
10181 if (list) {
10182 list += error;
10183 size -= error;
10184 }
10185
10186 error2 = nfs4_listxattr_nfs4_label(d_inode(dentry), list, size);
10187 if (error2 < 0)
10188 return error2;
Frank van der Linden012a2112020-06-23 22:39:03 +000010189
10190 if (list) {
10191 list += error2;
10192 size -= error2;
10193 }
10194
10195 error3 = nfs4_listxattr_nfs4_user(d_inode(dentry), list, size);
10196 if (error3 < 0)
10197 return error3;
10198
10199 return error + error2 + error3;
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +010010200}
10201
Trond Myklebust17f26b12013-08-21 15:48:42 -040010202static const struct inode_operations nfs4_dir_inode_operations = {
Bryan Schumaker73a79702012-07-16 16:39:12 -040010203 .create = nfs_create,
10204 .lookup = nfs_lookup,
10205 .atomic_open = nfs_atomic_open,
10206 .link = nfs_link,
10207 .unlink = nfs_unlink,
10208 .symlink = nfs_symlink,
10209 .mkdir = nfs_mkdir,
10210 .rmdir = nfs_rmdir,
10211 .mknod = nfs_mknod,
10212 .rename = nfs_rename,
10213 .permission = nfs_permission,
10214 .getattr = nfs_getattr,
10215 .setattr = nfs_setattr,
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +010010216 .listxattr = nfs4_listxattr,
Bryan Schumaker73a79702012-07-16 16:39:12 -040010217};
10218
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -080010219static const struct inode_operations nfs4_file_inode_operations = {
J. Bruce Fields6b3b5492005-06-22 17:16:22 +000010220 .permission = nfs_permission,
10221 .getattr = nfs_getattr,
10222 .setattr = nfs_setattr,
Andreas Gruenbacherc4803c42015-12-02 14:44:41 +010010223 .listxattr = nfs4_listxattr,
J. Bruce Fields6b3b5492005-06-22 17:16:22 +000010224};
10225
David Howells509de812006-08-22 20:06:11 -040010226const struct nfs_rpc_ops nfs_v4_clientops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -070010227 .version = 4, /* protocol version */
10228 .dentry_ops = &nfs4_dentry_operations,
10229 .dir_inode_ops = &nfs4_dir_inode_operations,
J. Bruce Fields6b3b5492005-06-22 17:16:22 +000010230 .file_inode_ops = &nfs4_file_inode_operations,
Jeff Layton1788ea62011-11-04 13:31:21 -040010231 .file_ops = &nfs4_file_operations,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010232 .getroot = nfs4_proc_get_root,
Bryan Schumaker281cad42012-04-27 13:27:45 -040010233 .submount = nfs4_submount,
David Howellsf2aedb72019-12-10 07:31:13 -050010234 .try_get_tree = nfs4_try_get_tree,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010235 .getattr = nfs4_proc_getattr,
10236 .setattr = nfs4_proc_setattr,
10237 .lookup = nfs4_proc_lookup,
Jeff Layton5b5faaf2017-06-29 06:34:52 -070010238 .lookupp = nfs4_proc_lookupp,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010239 .access = nfs4_proc_access,
10240 .readlink = nfs4_proc_readlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010241 .create = nfs4_proc_create,
10242 .remove = nfs4_proc_remove,
10243 .unlink_setup = nfs4_proc_unlink_setup,
Bryan Schumaker34e137c2012-03-19 14:54:41 -040010244 .unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010245 .unlink_done = nfs4_proc_unlink_done,
Jeff Laytond3d41522010-09-17 17:31:57 -040010246 .rename_setup = nfs4_proc_rename_setup,
Bryan Schumakerc6bfa1a2012-03-19 14:54:42 -040010247 .rename_rpc_prepare = nfs4_proc_rename_rpc_prepare,
Jeff Laytond3d41522010-09-17 17:31:57 -040010248 .rename_done = nfs4_proc_rename_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010249 .link = nfs4_proc_link,
10250 .symlink = nfs4_proc_symlink,
10251 .mkdir = nfs4_proc_mkdir,
Trond Myklebust912678d2018-03-20 16:43:15 -040010252 .rmdir = nfs4_proc_rmdir,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010253 .readdir = nfs4_proc_readdir,
10254 .mknod = nfs4_proc_mknod,
10255 .statfs = nfs4_proc_statfs,
10256 .fsinfo = nfs4_proc_fsinfo,
10257 .pathconf = nfs4_proc_pathconf,
David Howellse9326dc2006-08-22 20:06:10 -040010258 .set_capabilities = nfs4_server_capabilities,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010259 .decode_dirent = nfs4_decode_dirent,
Anna Schumakera4cdda52014-05-06 09:12:31 -040010260 .pgio_rpc_prepare = nfs4_proc_pgio_rpc_prepare,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010261 .read_setup = nfs4_proc_read_setup,
Trond Myklebustec06c092006-03-20 13:44:27 -050010262 .read_done = nfs4_read_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010263 .write_setup = nfs4_proc_write_setup,
Trond Myklebust788e7a82006-03-20 13:44:27 -050010264 .write_done = nfs4_write_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010265 .commit_setup = nfs4_proc_commit_setup,
Fred Isaman0b7c0152012-04-20 14:47:39 -040010266 .commit_rpc_prepare = nfs4_proc_commit_rpc_prepare,
Trond Myklebust788e7a82006-03-20 13:44:27 -050010267 .commit_done = nfs4_commit_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010268 .lock = nfs4_proc_lock,
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +000010269 .clear_acl_cache = nfs4_zap_acl_attr,
Trond Myklebust7fe5c392009-03-19 15:35:50 -040010270 .close_context = nfs4_close_context,
Trond Myklebust2b484292010-09-17 10:56:51 -040010271 .open_context = nfs4_atomic_open,
Bryan Schumaker011e2a72012-06-20 15:53:43 -040010272 .have_delegation = nfs4_have_delegation,
Bryan Schumaker6663ee72012-06-20 15:53:46 -040010273 .alloc_client = nfs4_alloc_client,
Andy Adamson45a52a02011-03-01 01:34:08 +000010274 .init_client = nfs4_init_client,
Bryan Schumakercdb7eced2012-06-20 15:53:45 -040010275 .free_client = nfs4_free_client,
Bryan Schumaker1179acc2012-07-30 16:05:19 -040010276 .create_server = nfs4_create_server,
10277 .clone_server = nfs_clone_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -070010278};
10279
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +000010280static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
Andreas Gruenbacher98e9cb52015-12-02 14:44:36 +010010281 .name = XATTR_NAME_NFSV4_ACL,
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +000010282 .list = nfs4_xattr_list_nfs4_acl,
10283 .get = nfs4_xattr_get_nfs4_acl,
10284 .set = nfs4_xattr_set_nfs4_acl,
10285};
10286
Frank van der Linden012a2112020-06-23 22:39:03 +000010287#ifdef CONFIG_NFS_V4_2
10288static const struct xattr_handler nfs4_xattr_nfs4_user_handler = {
10289 .prefix = XATTR_USER_PREFIX,
10290 .get = nfs4_xattr_get_nfs4_user,
10291 .set = nfs4_xattr_set_nfs4_user,
10292};
10293#endif
10294
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +000010295const struct xattr_handler *nfs4_xattr_handlers[] = {
10296 &nfs4_xattr_nfs4_acl_handler,
David Quigleyc9bccef2013-05-22 12:50:45 -040010297#ifdef CONFIG_NFS_V4_SECURITY_LABEL
10298 &nfs4_xattr_nfs4_label_handler,
10299#endif
Frank van der Linden012a2112020-06-23 22:39:03 +000010300#ifdef CONFIG_NFS_V4_2
10301 &nfs4_xattr_nfs4_user_handler,
10302#endif
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +000010303 NULL
10304};
10305
Linus Torvalds1da177e2005-04-16 15:20:36 -070010306/*
10307 * Local variables:
10308 * c-basic-offset: 8
10309 * End:
10310 */