blob: 2fbf4824187e657fd53db07884d11a085ded0336 [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>
Trond Myklebust6926afd2012-01-07 13:22:46 -050054#include <linux/nfs_idmap.h>
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +000055#include <linux/xattr.h>
Andy Adamsonc7a360b2011-01-25 19:15:32 -050056#include <linux/utsname.h>
Jeff Laytond3103102011-12-01 22:44:39 +010057#include <linux/freezer.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"
Trond Myklebust73e39aa2012-11-26 12:49:34 -050066#include "nfs4session.h"
David Howellsde242c02012-12-20 21:52:38 +000067#include "fscache.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Trond Myklebustc6d01c62013-08-09 11:51:26 -040069#include "nfs4trace.h"
70
Linus Torvalds1da177e2005-04-16 15:20:36 -070071#define NFSDBG_FACILITY NFSDBG_PROC
72
Trond Myklebust2066fe82006-09-15 08:30:46 -040073#define NFS4_POLL_RETRY_MIN (HZ/10)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074#define NFS4_POLL_RETRY_MAX (15*HZ)
75
Trond Myklebustcdd4e682006-01-03 09:55:12 +010076struct nfs4_opendata;
Trond Myklebust864472e2006-01-03 09:55:15 +010077static int _nfs4_proc_open(struct nfs4_opendata *data);
Alexandros Batsakisb2579572009-12-14 21:27:57 -080078static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
Linus Torvalds1da177e2005-04-16 15:20:36 -070079static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
Trond Myklebust9e33bed2008-12-23 15:21:46 -050080static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
Chuck Lever81934dd2012-03-01 17:01:57 -050081static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
David Quigley1775fd32013-05-22 12:50:42 -040082static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label);
83static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label);
Trond Myklebust0ab64e02010-04-16 16:22:51 -040084static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
85 struct nfs_fattr *fattr, struct iattr *sattr,
David Quigley1775fd32013-05-22 12:50:42 -040086 struct nfs4_state *state, struct nfs4_label *ilabel,
87 struct nfs4_label *olabel);
Bryan Schumakerf062eb62011-06-02 14:59:10 -040088#ifdef CONFIG_NFS_V4_1
Trond Myklebustab7cb0d2013-05-20 11:20:27 -040089static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *,
90 struct rpc_cred *);
91static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *,
92 struct rpc_cred *);
Bryan Schumakerf062eb62011-06-02 14:59:10 -040093#endif
David Quigleyaa9c2662013-05-22 12:50:44 -040094
95#ifdef CONFIG_NFS_V4_SECURITY_LABEL
96static inline struct nfs4_label *
97nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
98 struct iattr *sattr, struct nfs4_label *label)
99{
100 int err;
101
102 if (label == NULL)
103 return NULL;
104
105 if (nfs_server_capable(dir, NFS_CAP_SECURITY_LABEL) == 0)
106 return NULL;
107
108 if (NFS_SERVER(dir)->nfs_client->cl_minorversion < 2)
109 return NULL;
110
111 err = security_dentry_init_security(dentry, sattr->ia_mode,
112 &dentry->d_name, (void **)&label->label, &label->len);
113 if (err == 0)
114 return label;
115
116 return NULL;
117}
118static inline void
119nfs4_label_release_security(struct nfs4_label *label)
120{
121 if (label)
122 security_release_secctx(label->label, label->len);
123}
124static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
125{
126 if (label)
127 return server->attr_bitmask;
128
129 return server->attr_bitmask_nl;
130}
131#else
132static inline struct nfs4_label *
133nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
134 struct iattr *sattr, struct nfs4_label *l)
135{ return NULL; }
136static inline void
137nfs4_label_release_security(struct nfs4_label *label)
138{ return; }
139static inline u32 *
140nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
141{ return server->attr_bitmask; }
142#endif
143
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144/* Prevent leaks of NFSv4 errors into userland */
WANG Cong46f72f52008-12-30 16:35:55 -0500145static int nfs4_map_errors(int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146{
Trond Myklebust52567b02009-10-23 14:46:42 -0400147 if (err >= -1000)
148 return err;
149 switch (err) {
150 case -NFS4ERR_RESOURCE:
Weston Andros Adamson30005122013-02-28 20:30:10 -0500151 case -NFS4ERR_LAYOUTTRYLATER:
152 case -NFS4ERR_RECALLCONFLICT:
Trond Myklebust52567b02009-10-23 14:46:42 -0400153 return -EREMOTEIO;
Bryan Schumaker7ebb9312011-03-24 17:12:30 +0000154 case -NFS4ERR_WRONGSEC:
155 return -EPERM;
Trond Myklebust3ddeb7c2011-02-22 15:44:31 -0800156 case -NFS4ERR_BADOWNER:
157 case -NFS4ERR_BADNAME:
158 return -EINVAL;
Trond Myklebustfb13bfa2012-05-28 11:36:28 -0400159 case -NFS4ERR_SHARE_DENIED:
160 return -EACCES;
Steve Dicksonf25efd82012-06-06 14:12:07 -0400161 case -NFS4ERR_MINOR_VERS_MISMATCH:
162 return -EPROTONOSUPPORT;
Weston Andros Adamson6168f622012-09-10 14:00:46 -0400163 case -NFS4ERR_ACCESS:
164 return -EACCES;
Trond Myklebust6e3cf242013-03-23 15:22:45 -0400165 case -NFS4ERR_FILE_OPEN:
166 return -EBUSY;
Trond Myklebust52567b02009-10-23 14:46:42 -0400167 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 dprintk("%s could not handle NFSv4 error %d\n",
Harvey Harrison3110ff82008-05-02 13:42:44 -0700169 __func__, -err);
Trond Myklebust52567b02009-10-23 14:46:42 -0400170 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 }
Trond Myklebust52567b02009-10-23 14:46:42 -0400172 return -EIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173}
174
175/*
176 * This is our standard bitmap for GETATTR requests.
177 */
Trond Myklebust1549210f2012-06-05 09:16:47 -0400178const u32 nfs4_fattr_bitmap[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 FATTR4_WORD0_TYPE
180 | FATTR4_WORD0_CHANGE
181 | FATTR4_WORD0_SIZE
182 | FATTR4_WORD0_FSID
183 | FATTR4_WORD0_FILEID,
184 FATTR4_WORD1_MODE
185 | FATTR4_WORD1_NUMLINKS
186 | FATTR4_WORD1_OWNER
187 | FATTR4_WORD1_OWNER_GROUP
188 | FATTR4_WORD1_RAWDEV
189 | FATTR4_WORD1_SPACE_USED
190 | FATTR4_WORD1_TIME_ACCESS
191 | FATTR4_WORD1_TIME_METADATA
David Quigleyaa9c2662013-05-22 12:50:44 -0400192 | FATTR4_WORD1_TIME_MODIFY,
193#ifdef CONFIG_NFS_V4_SECURITY_LABEL
194 FATTR4_WORD2_SECURITY_LABEL
195#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196};
197
Trond Myklebust1549210f2012-06-05 09:16:47 -0400198static const u32 nfs4_pnfs_open_bitmap[3] = {
199 FATTR4_WORD0_TYPE
200 | FATTR4_WORD0_CHANGE
201 | FATTR4_WORD0_SIZE
202 | FATTR4_WORD0_FSID
203 | FATTR4_WORD0_FILEID,
204 FATTR4_WORD1_MODE
205 | FATTR4_WORD1_NUMLINKS
206 | FATTR4_WORD1_OWNER
207 | FATTR4_WORD1_OWNER_GROUP
208 | FATTR4_WORD1_RAWDEV
209 | FATTR4_WORD1_SPACE_USED
210 | FATTR4_WORD1_TIME_ACCESS
211 | FATTR4_WORD1_TIME_METADATA
212 | FATTR4_WORD1_TIME_MODIFY,
213 FATTR4_WORD2_MDSTHRESHOLD
214};
215
Andy Adamsone23008e2012-10-02 21:07:32 -0400216static const u32 nfs4_open_noattr_bitmap[3] = {
217 FATTR4_WORD0_TYPE
218 | FATTR4_WORD0_CHANGE
219 | FATTR4_WORD0_FILEID,
220};
221
David Quigleya09df2c2013-05-22 12:50:41 -0400222const u32 nfs4_statfs_bitmap[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 FATTR4_WORD0_FILES_AVAIL
224 | FATTR4_WORD0_FILES_FREE
225 | FATTR4_WORD0_FILES_TOTAL,
226 FATTR4_WORD1_SPACE_AVAIL
227 | FATTR4_WORD1_SPACE_FREE
228 | FATTR4_WORD1_SPACE_TOTAL
229};
230
David Quigleya09df2c2013-05-22 12:50:41 -0400231const u32 nfs4_pathconf_bitmap[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 FATTR4_WORD0_MAXLINK
233 | FATTR4_WORD0_MAXNAME,
234 0
235};
236
Fred Isamandae100c2011-07-30 20:52:37 -0400237const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 | FATTR4_WORD0_MAXREAD
239 | FATTR4_WORD0_MAXWRITE
240 | FATTR4_WORD0_LEASE_TIME,
Ricardo Labiaga55b6e772010-10-12 16:30:06 -0700241 FATTR4_WORD1_TIME_DELTA
Fred Isamandae100c2011-07-30 20:52:37 -0400242 | FATTR4_WORD1_FS_LAYOUT_TYPES,
243 FATTR4_WORD2_LAYOUT_BLKSIZE
Linus Torvalds1da177e2005-04-16 15:20:36 -0700244};
245
David Quigleya09df2c2013-05-22 12:50:41 -0400246const u32 nfs4_fs_locations_bitmap[3] = {
Manoj Naik830b8e32006-06-09 09:34:25 -0400247 FATTR4_WORD0_TYPE
248 | FATTR4_WORD0_CHANGE
249 | FATTR4_WORD0_SIZE
250 | FATTR4_WORD0_FSID
251 | FATTR4_WORD0_FILEID
252 | FATTR4_WORD0_FS_LOCATIONS,
253 FATTR4_WORD1_MODE
254 | FATTR4_WORD1_NUMLINKS
255 | FATTR4_WORD1_OWNER
256 | FATTR4_WORD1_OWNER_GROUP
257 | FATTR4_WORD1_RAWDEV
258 | FATTR4_WORD1_SPACE_USED
259 | FATTR4_WORD1_TIME_ACCESS
260 | FATTR4_WORD1_TIME_METADATA
261 | FATTR4_WORD1_TIME_MODIFY
David Quigleya09df2c2013-05-22 12:50:41 -0400262 | FATTR4_WORD1_MOUNTED_ON_FILEID,
Manoj Naik830b8e32006-06-09 09:34:25 -0400263};
264
Al Virobc4785c2006-10-19 23:28:51 -0700265static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 struct nfs4_readdir_arg *readdir)
267{
Al Viro0dbb4c62006-10-19 23:28:49 -0700268 __be32 *start, *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 if (cookie > 2) {
Adrian Bunkb7ef1952005-06-22 17:16:28 +0000271 readdir->cookie = cookie;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));
273 return;
274 }
275
276 readdir->cookie = 0;
277 memset(&readdir->verifier, 0, sizeof(readdir->verifier));
278 if (cookie == 2)
279 return;
280
281 /*
282 * NFSv4 servers do not return entries for '.' and '..'
283 * Therefore, we fake these entries here. We let '.'
284 * have cookie 0 and '..' have cookie 1. Note that
285 * when talking to the server, we always send cookie 0
286 * instead of 1 or 2.
287 */
Cong Wang2b86ce22011-11-25 23:14:33 +0800288 start = p = kmap_atomic(*readdir->pages);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 if (cookie == 0) {
291 *p++ = xdr_one; /* next */
292 *p++ = xdr_zero; /* cookie, first word */
293 *p++ = xdr_one; /* cookie, second word */
294 *p++ = xdr_one; /* entry len */
295 memcpy(p, ".\0\0\0", 4); /* entry */
296 p++;
297 *p++ = xdr_one; /* bitmap length */
298 *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
299 *p++ = htonl(8); /* attribute buffer length */
Peter Staubach4e769b92007-08-03 15:07:10 -0400300 p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302
303 *p++ = xdr_one; /* next */
304 *p++ = xdr_zero; /* cookie, first word */
305 *p++ = xdr_two; /* cookie, second word */
306 *p++ = xdr_two; /* entry len */
307 memcpy(p, "..\0\0", 4); /* entry */
308 p++;
309 *p++ = xdr_one; /* bitmap length */
310 *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */
311 *p++ = htonl(8); /* attribute buffer length */
Peter Staubach4e769b92007-08-03 15:07:10 -0400312 p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
314 readdir->pgbase = (char *)p - (char *)start;
315 readdir->count -= readdir->pgbase;
Cong Wang2b86ce22011-11-25 23:14:33 +0800316 kunmap_atomic(start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317}
318
Trond Myklebust65de8722008-12-23 15:21:44 -0500319static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
320{
321 int res = 0;
322
323 might_sleep();
324
325 if (*timeout <= 0)
326 *timeout = NFS4_POLL_RETRY_MIN;
327 if (*timeout > NFS4_POLL_RETRY_MAX)
328 *timeout = NFS4_POLL_RETRY_MAX;
Colin Cross416ad3c2013-05-06 23:50:06 +0000329 freezable_schedule_timeout_killable_unsafe(*timeout);
Trond Myklebust65de8722008-12-23 15:21:44 -0500330 if (fatal_signal_pending(current))
331 res = -ERESTARTSYS;
332 *timeout <<= 1;
333 return res;
334}
335
336/* This is the error handling routine for processes that are allowed
337 * to sleep.
338 */
Trond Myklebustb064eca22011-02-22 15:44:32 -0800339static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
Trond Myklebust65de8722008-12-23 15:21:44 -0500340{
341 struct nfs_client *clp = server->nfs_client;
Trond Myklebust9e33bed2008-12-23 15:21:46 -0500342 struct nfs4_state *state = exception->state;
Trond Myklebust3114ea72012-03-07 16:39:06 -0500343 struct inode *inode = exception->inode;
Trond Myklebust65de8722008-12-23 15:21:44 -0500344 int ret = errorcode;
345
346 exception->retry = 0;
347 switch(errorcode) {
348 case 0:
349 return 0;
Trond Myklebust3114ea72012-03-07 16:39:06 -0500350 case -NFS4ERR_OPENMODE:
Bryan Schumaker011e2a72012-06-20 15:53:43 -0400351 if (inode && nfs4_have_delegation(inode, FMODE_READ)) {
Bryan Schumaker57ec14c2012-06-20 15:53:44 -0400352 nfs4_inode_return_delegation(inode);
Trond Myklebust3114ea72012-03-07 16:39:06 -0500353 exception->retry = 1;
354 return 0;
355 }
356 if (state == NULL)
357 break;
Trond Myklebust5d422302013-03-14 16:57:48 -0400358 ret = nfs4_schedule_stateid_recovery(server, state);
359 if (ret < 0)
360 break;
Trond Myklebust3114ea72012-03-07 16:39:06 -0500361 goto wait_on_recovery;
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -0500362 case -NFS4ERR_DELEG_REVOKED:
Trond Myklebust9e33bed2008-12-23 15:21:46 -0500363 case -NFS4ERR_ADMIN_REVOKED:
364 case -NFS4ERR_BAD_STATEID:
Trond Myklebustb570a972013-04-12 15:04:51 -0400365 if (inode != NULL && nfs4_have_delegation(inode, FMODE_READ)) {
366 nfs_remove_bad_delegation(inode);
367 exception->retry = 1;
368 break;
369 }
Trond Myklebust9e33bed2008-12-23 15:21:46 -0500370 if (state == NULL)
371 break;
Trond Myklebust5d422302013-03-14 16:57:48 -0400372 ret = nfs4_schedule_stateid_recovery(server, state);
373 if (ret < 0)
374 break;
Trond Myklebust0400a6b2011-03-09 16:00:53 -0500375 goto wait_on_recovery;
Trond Myklebust0ced63d2011-05-26 14:26:35 -0400376 case -NFS4ERR_EXPIRED:
Trond Myklebust5d422302013-03-14 16:57:48 -0400377 if (state != NULL) {
378 ret = nfs4_schedule_stateid_recovery(server, state);
379 if (ret < 0)
380 break;
381 }
Trond Myklebust65de8722008-12-23 15:21:44 -0500382 case -NFS4ERR_STALE_STATEID:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -0500383 case -NFS4ERR_STALE_CLIENTID:
Trond Myklebust0400a6b2011-03-09 16:00:53 -0500384 nfs4_schedule_lease_recovery(clp);
385 goto wait_on_recovery;
Trond Myklebust03391692010-01-26 15:42:38 -0500386#if defined(CONFIG_NFS_V4_1)
Andy Adamson4745e312009-04-01 09:22:42 -0400387 case -NFS4ERR_BADSESSION:
388 case -NFS4ERR_BADSLOT:
389 case -NFS4ERR_BAD_HIGH_SLOT:
390 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
391 case -NFS4ERR_DEADSESSION:
392 case -NFS4ERR_SEQ_FALSE_RETRY:
393 case -NFS4ERR_SEQ_MISORDERED:
394 dprintk("%s ERROR: %d Reset session\n", __func__,
395 errorcode);
Trond Myklebust9f594792012-05-27 13:02:53 -0400396 nfs4_schedule_session_recovery(clp->cl_session, errorcode);
Bryan Schumaker399f11c2012-10-30 16:06:35 -0400397 goto wait_on_recovery;
Trond Myklebust03391692010-01-26 15:42:38 -0500398#endif /* defined(CONFIG_NFS_V4_1) */
Trond Myklebust65de8722008-12-23 15:21:44 -0500399 case -NFS4ERR_FILE_OPEN:
NeilBrown44ed3552009-12-03 15:58:56 -0500400 if (exception->timeout > HZ) {
401 /* We have retried a decent amount, time to
402 * fail
403 */
404 ret = -EBUSY;
405 break;
406 }
Trond Myklebust65de8722008-12-23 15:21:44 -0500407 case -NFS4ERR_GRACE:
408 case -NFS4ERR_DELAY:
409 ret = nfs4_delay(server->client, &exception->timeout);
410 if (ret != 0)
411 break;
Andy Adamsona8a4ae32011-05-03 13:43:03 -0400412 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebust65de8722008-12-23 15:21:44 -0500413 case -NFS4ERR_OLD_STATEID:
414 exception->retry = 1;
Trond Myklebustb064eca22011-02-22 15:44:32 -0800415 break;
416 case -NFS4ERR_BADOWNER:
417 /* The following works around a Linux server bug! */
418 case -NFS4ERR_BADNAME:
419 if (server->caps & NFS_CAP_UIDGID_NOMAP) {
420 server->caps &= ~NFS_CAP_UIDGID_NOMAP;
421 exception->retry = 1;
422 printk(KERN_WARNING "NFS: v4 server %s "
423 "does not accept raw "
424 "uid/gids. "
425 "Reenabling the idmapper.\n",
426 server->nfs_client->cl_hostname);
427 }
Trond Myklebust65de8722008-12-23 15:21:44 -0500428 }
429 /* We failed to handle the error */
430 return nfs4_map_errors(ret);
Trond Myklebust0400a6b2011-03-09 16:00:53 -0500431wait_on_recovery:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -0500432 ret = nfs4_wait_clnt_recover(clp);
433 if (ret == 0)
434 exception->retry = 1;
435 return ret;
Trond Myklebust65de8722008-12-23 15:21:44 -0500436}
437
Weston Andros Adamsona5250de2013-09-03 15:18:49 -0400438/*
439 * Return 'true' if 'clp' is using an rpc_client that is integrity protected
440 * or 'false' otherwise.
441 */
442static bool _nfs4_is_integrity_protected(struct nfs_client *clp)
443{
444 rpc_authflavor_t flavor = clp->cl_rpcclient->cl_auth->au_flavor;
445
446 if (flavor == RPC_AUTH_GSS_KRB5I ||
447 flavor == RPC_AUTH_GSS_KRB5P)
448 return true;
449
450 return false;
451}
Trond Myklebust65de8722008-12-23 15:21:44 -0500452
Trond Myklebust452e9352010-07-31 14:29:06 -0400453static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700454{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 spin_lock(&clp->cl_lock);
456 if (time_before(clp->cl_last_renewal,timestamp))
457 clp->cl_last_renewal = timestamp;
458 spin_unlock(&clp->cl_lock);
459}
460
Trond Myklebust452e9352010-07-31 14:29:06 -0400461static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
462{
463 do_renew_lease(server->nfs_client, timestamp);
464}
465
Chuck Lever2a3eb2b2013-08-09 12:48:00 -0400466struct nfs4_call_sync_data {
467 const struct nfs_server *seq_server;
468 struct nfs4_sequence_args *seq_args;
469 struct nfs4_sequence_res *seq_res;
470};
471
Chuck Levera9c92d62013-08-09 12:48:18 -0400472static void nfs4_init_sequence(struct nfs4_sequence_args *args,
473 struct nfs4_sequence_res *res, int cache_reply)
474{
475 args->sa_slot = NULL;
476 args->sa_cache_this = cache_reply;
477 args->sa_privileged = 0;
478
479 res->sr_slot = NULL;
480}
481
482static void nfs4_set_sequence_privileged(struct nfs4_sequence_args *args)
483{
484 args->sa_privileged = 1;
485}
486
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400487#if defined(CONFIG_NFS_V4_1)
488
Trond Myklebustd185a332010-06-16 09:52:25 -0400489static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
Andy Adamson13615872009-04-01 09:22:17 -0400490{
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500491 struct nfs4_session *session;
Andy Adamson13615872009-04-01 09:22:17 -0400492 struct nfs4_slot_table *tbl;
Trond Myklebustc10e4492012-11-26 16:16:54 -0500493 bool send_new_highest_used_slotid = false;
Andy Adamson13615872009-04-01 09:22:17 -0400494
Benny Halevydfb4f3092010-09-24 09:17:01 -0400495 if (!res->sr_slot) {
Andy Adamson13615872009-04-01 09:22:17 -0400496 /* just wake up the next guy waiting since
497 * we may have not consumed a slot after all */
Andy Adamson691daf32009-12-04 15:55:39 -0500498 dprintk("%s: No slot\n", __func__);
Trond Myklebust35dc1d72009-12-05 19:32:19 -0500499 return;
Andy Adamson13615872009-04-01 09:22:17 -0400500 }
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500501 tbl = res->sr_slot->table;
502 session = tbl->session;
Andy Adamsonea028ac2009-12-04 15:55:38 -0500503
Trond Myklebust35dc1d72009-12-05 19:32:19 -0500504 spin_lock(&tbl->slot_tbl_lock);
Trond Myklebustc10e4492012-11-26 16:16:54 -0500505 /* Be nice to the server: try to ensure that the last transmitted
506 * value for highest_user_slotid <= target_highest_slotid
507 */
508 if (tbl->highest_used_slotid > tbl->target_highest_slotid)
509 send_new_highest_used_slotid = true;
510
Trond Myklebustb75ad4c2012-11-29 17:27:47 -0500511 if (nfs41_wake_and_assign_slot(tbl, res->sr_slot)) {
512 send_new_highest_used_slotid = false;
513 goto out_unlock;
514 }
Trond Myklebustf4af6e2a2012-11-20 14:17:32 -0500515 nfs4_free_slot(tbl, res->sr_slot);
Trond Myklebustc10e4492012-11-26 16:16:54 -0500516
517 if (tbl->highest_used_slotid != NFS4_NO_SLOT)
518 send_new_highest_used_slotid = false;
Trond Myklebustb75ad4c2012-11-29 17:27:47 -0500519out_unlock:
Trond Myklebust35dc1d72009-12-05 19:32:19 -0500520 spin_unlock(&tbl->slot_tbl_lock);
Benny Halevydfb4f3092010-09-24 09:17:01 -0400521 res->sr_slot = NULL;
Trond Myklebustc10e4492012-11-26 16:16:54 -0500522 if (send_new_highest_used_slotid)
523 nfs41_server_notify_highest_slotid_update(session->clp);
Andy Adamson13615872009-04-01 09:22:17 -0400524}
525
Trond Myklebust14516c32010-07-31 14:29:06 -0400526static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
Andy Adamsonb0df8062009-04-01 09:22:18 -0400527{
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500528 struct nfs4_session *session;
Trond Myklebust933602e2012-11-16 12:12:38 -0500529 struct nfs4_slot *slot;
Trond Myklebust14516c32010-07-31 14:29:06 -0400530 struct nfs_client *clp;
Trond Myklebustac20d162012-12-15 15:36:07 -0500531 bool interrupted = false;
Trond Myklebust85563072012-12-11 10:31:12 -0500532 int ret = 1;
Andy Adamsonb0df8062009-04-01 09:22:18 -0400533
Bryan Schumaker468f8612011-04-18 15:57:32 -0400534 /* don't increment the sequence number if the task wasn't sent */
535 if (!RPC_WAS_SENT(task))
Andy Adamsonb0df8062009-04-01 09:22:18 -0400536 goto out;
537
Trond Myklebust933602e2012-11-16 12:12:38 -0500538 slot = res->sr_slot;
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500539 session = slot->table->session;
Trond Myklebust933602e2012-11-16 12:12:38 -0500540
Trond Myklebustac20d162012-12-15 15:36:07 -0500541 if (slot->interrupted) {
542 slot->interrupted = 0;
543 interrupted = true;
544 }
545
Trond Myklebust2f92ae32013-08-14 17:58:28 -0400546 trace_nfs4_sequence_done(session, res);
Andy Adamson691daf32009-12-04 15:55:39 -0500547 /* Check the SEQUENCE operation status */
Trond Myklebust14516c32010-07-31 14:29:06 -0400548 switch (res->sr_status) {
549 case 0:
Andy Adamsonb0df8062009-04-01 09:22:18 -0400550 /* Update the slot's sequence and clientid lease timer */
Trond Myklebust933602e2012-11-16 12:12:38 -0500551 ++slot->seq_nr;
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500552 clp = session->clp;
Trond Myklebust8e63b6a2012-12-15 15:21:52 -0500553 do_renew_lease(clp, res->sr_timestamp);
Alexandros Batsakis0629e372009-12-05 13:46:14 -0500554 /* Check sequence flags */
Trond Myklebustb4410c22011-03-09 16:00:55 -0500555 if (res->sr_status_flags != 0)
556 nfs4_schedule_lease_recovery(clp);
Trond Myklebust464ee9f2012-11-20 12:49:27 -0500557 nfs41_update_target_slotid(slot->table, slot, res);
Trond Myklebust14516c32010-07-31 14:29:06 -0400558 break;
Trond Myklebustac20d162012-12-15 15:36:07 -0500559 case 1:
560 /*
561 * sr_status remains 1 if an RPC level error occurred.
562 * The server may or may not have processed the sequence
563 * operation..
564 * Mark the slot as having hosted an interrupted RPC call.
565 */
566 slot->interrupted = 1;
567 goto out;
Trond Myklebust14516c32010-07-31 14:29:06 -0400568 case -NFS4ERR_DELAY:
569 /* The server detected a resend of the RPC call and
570 * returned NFS4ERR_DELAY as per Section 2.10.6.2
571 * of RFC5661.
572 */
Trond Myklebustdf2fabf2012-11-16 12:45:06 -0500573 dprintk("%s: slot=%u seq=%u: Operation in progress\n",
Benny Halevydfb4f3092010-09-24 09:17:01 -0400574 __func__,
Trond Myklebustdf2fabf2012-11-16 12:45:06 -0500575 slot->slot_nr,
Trond Myklebust933602e2012-11-16 12:12:38 -0500576 slot->seq_nr);
Trond Myklebust14516c32010-07-31 14:29:06 -0400577 goto out_retry;
Trond Myklebust85563072012-12-11 10:31:12 -0500578 case -NFS4ERR_BADSLOT:
579 /*
580 * The slot id we used was probably retired. Try again
581 * using a different slot id.
582 */
Trond Myklebuste8794442012-12-15 13:56:18 -0500583 goto retry_nowait;
584 case -NFS4ERR_SEQ_MISORDERED:
585 /*
Trond Myklebustac20d162012-12-15 15:36:07 -0500586 * Was the last operation on this sequence interrupted?
587 * If so, retry after bumping the sequence number.
588 */
589 if (interrupted) {
590 ++slot->seq_nr;
591 goto retry_nowait;
592 }
593 /*
Trond Myklebuste8794442012-12-15 13:56:18 -0500594 * Could this slot have been previously retired?
595 * If so, then the server may be expecting seq_nr = 1!
596 */
Trond Myklebust8e63b6a2012-12-15 15:21:52 -0500597 if (slot->seq_nr != 1) {
598 slot->seq_nr = 1;
599 goto retry_nowait;
600 }
601 break;
Trond Myklebuste8794442012-12-15 13:56:18 -0500602 case -NFS4ERR_SEQ_FALSE_RETRY:
603 ++slot->seq_nr;
604 goto retry_nowait;
Trond Myklebust14516c32010-07-31 14:29:06 -0400605 default:
606 /* Just update the slot sequence no. */
Trond Myklebust933602e2012-11-16 12:12:38 -0500607 ++slot->seq_nr;
Andy Adamsonb0df8062009-04-01 09:22:18 -0400608 }
609out:
610 /* The session may be reset by one of the error handlers. */
611 dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
Trond Myklebustd185a332010-06-16 09:52:25 -0400612 nfs41_sequence_free_slot(res);
Trond Myklebust85563072012-12-11 10:31:12 -0500613 return ret;
Trond Myklebuste8794442012-12-15 13:56:18 -0500614retry_nowait:
615 if (rpc_restart_call_prepare(task)) {
616 task->tk_status = 0;
617 ret = 0;
618 }
619 goto out;
Trond Myklebust14516c32010-07-31 14:29:06 -0400620out_retry:
Trond Myklebustd05dd4e2010-07-31 14:29:07 -0400621 if (!rpc_restart_call(task))
Trond Myklebust14516c32010-07-31 14:29:06 -0400622 goto out;
623 rpc_delay(task, NFS4_POLL_RETRY_MAX);
624 return 0;
Andy Adamsonb0df8062009-04-01 09:22:18 -0400625}
626
Trond Myklebust14516c32010-07-31 14:29:06 -0400627static int nfs4_sequence_done(struct rpc_task *task,
628 struct nfs4_sequence_res *res)
Trond Myklebustdf896452010-06-16 09:52:26 -0400629{
Trond Myklebuste3725ec2012-11-16 12:25:01 -0500630 if (res->sr_slot == NULL)
Trond Myklebust14516c32010-07-31 14:29:06 -0400631 return 1;
632 return nfs41_sequence_done(task, res);
Trond Myklebustdf896452010-06-16 09:52:26 -0400633}
634
Andy Adamsondc70d7b2011-03-01 01:34:19 +0000635int nfs41_setup_sequence(struct nfs4_session *session,
Andy Adamsonce5039c2009-04-01 09:22:13 -0400636 struct nfs4_sequence_args *args,
637 struct nfs4_sequence_res *res,
Andy Adamsonce5039c2009-04-01 09:22:13 -0400638 struct rpc_task *task)
639{
Andy Adamsonfbcd4ab2009-04-01 09:22:15 -0400640 struct nfs4_slot *slot;
641 struct nfs4_slot_table *tbl;
Andy Adamsonfbcd4ab2009-04-01 09:22:15 -0400642
643 dprintk("--> %s\n", __func__);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400644 /* slot already allocated? */
Benny Halevydfb4f3092010-09-24 09:17:01 -0400645 if (res->sr_slot != NULL)
Trond Myklebustd9afbd12012-10-22 20:28:44 -0400646 goto out_success;
Andy Adamsonce5039c2009-04-01 09:22:13 -0400647
Andy Adamsonfbcd4ab2009-04-01 09:22:15 -0400648 tbl = &session->fc_slot_table;
649
Trond Myklebust69d206b2012-11-22 13:21:02 -0500650 task->tk_timeout = 0;
651
Andy Adamsonfbcd4ab2009-04-01 09:22:15 -0400652 spin_lock(&tbl->slot_tbl_lock);
Andy Adamson774d5f12013-05-20 14:13:50 -0400653 if (test_bit(NFS4_SLOT_TBL_DRAINING, &tbl->slot_tbl_state) &&
Trond Myklebust8fe72ba2012-10-29 19:02:20 -0400654 !args->sa_privileged) {
Andy Adamson0b1c8fc2011-11-09 13:58:26 -0500655 /* The state manager will wait until the slot table is empty */
Andy Adamson0b1c8fc2011-11-09 13:58:26 -0500656 dprintk("%s session is draining\n", __func__);
Trond Myklebust7b939a32012-11-01 15:19:46 -0400657 goto out_sleep;
Andy Adamsonb069d942009-04-01 09:22:43 -0400658 }
659
Trond Myklebust2dc03b72012-11-16 16:10:11 -0500660 slot = nfs4_alloc_slot(tbl);
Trond Myklebust69d206b2012-11-22 13:21:02 -0500661 if (IS_ERR(slot)) {
662 /* If out of memory, try again in 1/4 second */
663 if (slot == ERR_PTR(-ENOMEM))
664 task->tk_timeout = HZ >> 2;
Andy Adamsonfbcd4ab2009-04-01 09:22:15 -0400665 dprintk("<-- %s: no free slots\n", __func__);
Trond Myklebust7b939a32012-11-01 15:19:46 -0400666 goto out_sleep;
Andy Adamsonfbcd4ab2009-04-01 09:22:15 -0400667 }
668 spin_unlock(&tbl->slot_tbl_lock);
669
Trond Myklebust2b2fa712012-11-16 12:58:36 -0500670 args->sa_slot = slot;
Andy Adamsonfbcd4ab2009-04-01 09:22:15 -0400671
Chuck Levere8d92382013-08-09 12:47:51 -0400672 dprintk("<-- %s slotid=%u seqid=%u\n", __func__,
Trond Myklebust2dc03b72012-11-16 16:10:11 -0500673 slot->slot_nr, slot->seq_nr);
Andy Adamsonfbcd4ab2009-04-01 09:22:15 -0400674
Benny Halevydfb4f3092010-09-24 09:17:01 -0400675 res->sr_slot = slot;
Trond Myklebust8e63b6a2012-12-15 15:21:52 -0500676 res->sr_timestamp = jiffies;
Trond Myklebust2a6e26c2010-06-16 09:52:25 -0400677 res->sr_status_flags = 0;
Andy Adamsonfbcd4ab2009-04-01 09:22:15 -0400678 /*
679 * sr_status is only set in decode_sequence, and so will remain
680 * set to 1 if an rpc level failure occurs.
681 */
682 res->sr_status = 1;
Trond Myklebust2f92ae32013-08-14 17:58:28 -0400683 trace_nfs4_setup_sequence(session, args);
Trond Myklebustd9afbd12012-10-22 20:28:44 -0400684out_success:
685 rpc_call_start(task);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400686 return 0;
Trond Myklebust7b939a32012-11-01 15:19:46 -0400687out_sleep:
Trond Myklebust8fe72ba2012-10-29 19:02:20 -0400688 /* Privileged tasks are queued with top priority */
689 if (args->sa_privileged)
Trond Myklebust1e1093c2012-11-01 16:44:05 -0400690 rpc_sleep_on_priority(&tbl->slot_tbl_waitq, task,
691 NULL, RPC_PRIORITY_PRIVILEGED);
692 else
693 rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
Trond Myklebust7b939a32012-11-01 15:19:46 -0400694 spin_unlock(&tbl->slot_tbl_lock);
695 return -EAGAIN;
Andy Adamsonce5039c2009-04-01 09:22:13 -0400696}
Andy Adamsondc70d7b2011-03-01 01:34:19 +0000697EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400698
Chuck Lever5a580e02013-08-09 12:48:09 -0400699static int nfs4_setup_sequence(const struct nfs_server *server,
700 struct nfs4_sequence_args *args,
701 struct nfs4_sequence_res *res,
702 struct rpc_task *task)
Andy Adamsonce5039c2009-04-01 09:22:13 -0400703{
Trond Myklebust035168a2010-06-16 09:52:26 -0400704 struct nfs4_session *session = nfs4_get_session(server);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400705 int ret = 0;
706
Trond Myklebustd9afbd12012-10-22 20:28:44 -0400707 if (session == NULL) {
708 rpc_call_start(task);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400709 goto out;
Trond Myklebustd9afbd12012-10-22 20:28:44 -0400710 }
Trond Myklebust035168a2010-06-16 09:52:26 -0400711
Chuck Levere8d92382013-08-09 12:47:51 -0400712 dprintk("--> %s clp %p session %p sr_slot %u\n",
Benny Halevydfb4f3092010-09-24 09:17:01 -0400713 __func__, session->clp, session, res->sr_slot ?
Chuck Levere8d92382013-08-09 12:47:51 -0400714 res->sr_slot->slot_nr : NFS4_NO_SLOT);
Trond Myklebust035168a2010-06-16 09:52:26 -0400715
Trond Myklebust9d12b212012-01-17 22:04:25 -0500716 ret = nfs41_setup_sequence(session, args, res, task);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400717out:
718 dprintk("<-- %s status=%d\n", __func__, ret);
719 return ret;
720}
721
Andy Adamsonce5039c2009-04-01 09:22:13 -0400722static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
723{
Chuck Lever2a3eb2b2013-08-09 12:48:00 -0400724 struct nfs4_call_sync_data *data = calldata;
Trond Myklebust6ba7db32012-10-22 20:07:20 -0400725 struct nfs4_session *session = nfs4_get_session(data->seq_server);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400726
Trond Myklebust035168a2010-06-16 09:52:26 -0400727 dprintk("--> %s data->seq_server %p\n", __func__, data->seq_server);
728
Trond Myklebustd9afbd12012-10-22 20:28:44 -0400729 nfs41_setup_sequence(session, data->seq_args, data->seq_res, task);
Andy Adamsonce5039c2009-04-01 09:22:13 -0400730}
731
Andy Adamson69ab40c2009-04-01 09:22:19 -0400732static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
733{
Chuck Lever2a3eb2b2013-08-09 12:48:00 -0400734 struct nfs4_call_sync_data *data = calldata;
Andy Adamson69ab40c2009-04-01 09:22:19 -0400735
Trond Myklebust14516c32010-07-31 14:29:06 -0400736 nfs41_sequence_done(task, data->seq_res);
Andy Adamson69ab40c2009-04-01 09:22:19 -0400737}
738
Trond Myklebust17280172012-03-11 13:11:00 -0400739static const struct rpc_call_ops nfs41_call_sync_ops = {
Andy Adamsonce5039c2009-04-01 09:22:13 -0400740 .rpc_call_prepare = nfs41_call_sync_prepare,
Andy Adamson69ab40c2009-04-01 09:22:19 -0400741 .rpc_call_done = nfs41_call_sync_done,
Andy Adamsonce5039c2009-04-01 09:22:13 -0400742};
743
Trond Myklebustdf896452010-06-16 09:52:26 -0400744#else
Chuck Lever5a580e02013-08-09 12:48:09 -0400745static int nfs4_setup_sequence(const struct nfs_server *server,
746 struct nfs4_sequence_args *args,
747 struct nfs4_sequence_res *res,
748 struct rpc_task *task)
749{
750 rpc_call_start(task);
751 return 0;
752}
Trond Myklebust8fe72ba2012-10-29 19:02:20 -0400753
Trond Myklebust14516c32010-07-31 14:29:06 -0400754static int nfs4_sequence_done(struct rpc_task *task,
755 struct nfs4_sequence_res *res)
Trond Myklebustdf896452010-06-16 09:52:26 -0400756{
Trond Myklebust14516c32010-07-31 14:29:06 -0400757 return 1;
Trond Myklebustdf896452010-06-16 09:52:26 -0400758}
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400759#endif /* CONFIG_NFS_V4_1 */
760
Chuck Lever9915ea72013-08-09 12:48:27 -0400761static void nfs40_call_sync_prepare(struct rpc_task *task, void *calldata)
762{
763 struct nfs4_call_sync_data *data = calldata;
764 nfs4_setup_sequence(data->seq_server,
765 data->seq_args, data->seq_res, task);
766}
767
768static void nfs40_call_sync_done(struct rpc_task *task, void *calldata)
769{
770 struct nfs4_call_sync_data *data = calldata;
771 nfs4_sequence_done(task, data->seq_res);
772}
773
774static const struct rpc_call_ops nfs40_call_sync_ops = {
775 .rpc_call_prepare = nfs40_call_sync_prepare,
776 .rpc_call_done = nfs40_call_sync_done,
777};
778
779static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
780 struct nfs_server *server,
781 struct rpc_message *msg,
782 struct nfs4_sequence_args *args,
783 struct nfs4_sequence_res *res)
784{
785 int ret;
786 struct rpc_task *task;
787 struct nfs_client *clp = server->nfs_client;
788 struct nfs4_call_sync_data data = {
789 .seq_server = server,
790 .seq_args = args,
791 .seq_res = res,
792 };
793 struct rpc_task_setup task_setup = {
794 .rpc_client = clnt,
795 .rpc_message = msg,
796 .callback_ops = clp->cl_mvops->call_sync_ops,
797 .callback_data = &data
798 };
799
800 task = rpc_run_task(&task_setup);
801 if (IS_ERR(task))
802 ret = PTR_ERR(task);
803 else {
804 ret = task->tk_status;
805 rpc_put_task(task);
806 }
807 return ret;
808}
809
Trond Myklebustfd0c0952012-11-01 14:43:38 -0400810static
Bryan Schumaker7c513052011-03-24 17:12:24 +0000811int _nfs4_call_sync(struct rpc_clnt *clnt,
812 struct nfs_server *server,
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400813 struct rpc_message *msg,
814 struct nfs4_sequence_args *args,
Trond Myklebustfd0c0952012-11-01 14:43:38 -0400815 struct nfs4_sequence_res *res)
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400816{
Bryan Schumaker7c513052011-03-24 17:12:24 +0000817 return rpc_call_sync(clnt, msg, 0);
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400818}
819
Trond Myklebustfd0c0952012-11-01 14:43:38 -0400820static
Bryan Schumaker7c513052011-03-24 17:12:24 +0000821int nfs4_call_sync(struct rpc_clnt *clnt,
822 struct nfs_server *server,
Bryan Schumakere73b83f2011-03-24 17:12:23 +0000823 struct rpc_message *msg,
824 struct nfs4_sequence_args *args,
825 struct nfs4_sequence_res *res,
826 int cache_reply)
827{
Chuck Levera9c92d62013-08-09 12:48:18 -0400828 nfs4_init_sequence(args, res, cache_reply);
Chuck Lever9915ea72013-08-09 12:48:27 -0400829 return nfs4_call_sync_sequence(clnt, server, msg, args, res);
Bryan Schumakere73b83f2011-03-24 17:12:23 +0000830}
Andy Adamsoncccef3b2009-04-01 09:22:03 -0400831
Trond Myklebust38478b22006-05-25 01:40:57 -0400832static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833{
Trond Myklebust38478b22006-05-25 01:40:57 -0400834 struct nfs_inode *nfsi = NFS_I(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700835
Trond Myklebust38478b22006-05-25 01:40:57 -0400836 spin_lock(&dir->i_lock);
Trond Myklebust359d7d12012-05-28 10:01:34 -0400837 nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
Trond Myklebusta9a4a872011-10-17 16:08:46 -0700838 if (!cinfo->atomic || cinfo->before != dir->i_version)
Trond Myklebustbfc69a42007-10-15 18:18:29 -0400839 nfs_force_lookup_revalidate(dir);
Trond Myklebusta9a4a872011-10-17 16:08:46 -0700840 dir->i_version = cinfo->after;
David Howellsde242c02012-12-20 21:52:38 +0000841 nfs_fscache_invalidate(dir);
Trond Myklebust38478b22006-05-25 01:40:57 -0400842 spin_unlock(&dir->i_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843}
844
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100845struct nfs4_opendata {
Trond Myklebustc6d00e62007-06-17 16:02:44 -0400846 struct kref kref;
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100847 struct nfs_openargs o_arg;
848 struct nfs_openres o_res;
Trond Myklebustcdd4e682006-01-03 09:55:12 +0100849 struct nfs_open_confirmargs c_arg;
850 struct nfs_open_confirmres c_res;
Trond Myklebust6926afd2012-01-07 13:22:46 -0500851 struct nfs4_string owner_name;
852 struct nfs4_string group_name;
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100853 struct nfs_fattr f_attr;
David Quigley1775fd32013-05-22 12:50:42 -0400854 struct nfs4_label *f_label;
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100855 struct dentry *dir;
Al Viro82a2c1b2011-06-22 18:30:55 -0400856 struct dentry *dentry;
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100857 struct nfs4_state_owner *owner;
Trond Myklebustaac00a82007-07-05 19:02:21 -0400858 struct nfs4_state *state;
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100859 struct iattr attrs;
Trond Myklebust26e976a2006-01-03 09:55:21 +0100860 unsigned long timestamp;
Trond Myklebust3e309912007-07-07 13:19:59 -0400861 unsigned int rpc_done : 1;
Trond Myklebustbdeca1b2013-04-23 14:52:44 -0400862 unsigned int is_recover : 1;
Trond Myklebust24ac23a2006-01-03 09:55:11 +0100863 int rpc_status;
864 int cancelled;
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100865};
866
Trond Myklebust49f9a0f2013-03-15 16:44:28 -0400867static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
868 int err, struct nfs4_exception *exception)
869{
870 if (err != -EINVAL)
871 return false;
872 if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
873 return false;
874 server->caps &= ~NFS_CAP_ATOMIC_OPEN_V1;
875 exception->retry = 1;
876 return true;
877}
878
879static enum open_claim_type4
880nfs4_map_atomic_open_claim(struct nfs_server *server,
881 enum open_claim_type4 claim)
882{
883 if (server->caps & NFS_CAP_ATOMIC_OPEN_V1)
884 return claim;
885 switch (claim) {
886 default:
887 return claim;
888 case NFS4_OPEN_CLAIM_FH:
889 return NFS4_OPEN_CLAIM_NULL;
890 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
891 return NFS4_OPEN_CLAIM_DELEGATE_CUR;
892 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
893 return NFS4_OPEN_CLAIM_DELEGATE_PREV;
894 }
895}
Trond Myklebust2ced46c2007-07-03 23:48:13 -0400896
897static void nfs4_init_opendata_res(struct nfs4_opendata *p)
898{
899 p->o_res.f_attr = &p->f_attr;
David Quigley1775fd32013-05-22 12:50:42 -0400900 p->o_res.f_label = p->f_label;
Trond Myklebustc1d51932008-04-07 13:20:54 -0400901 p->o_res.seqid = p->o_arg.seqid;
902 p->c_res.seqid = p->c_arg.seqid;
Trond Myklebust2ced46c2007-07-03 23:48:13 -0400903 p->o_res.server = p->o_arg.server;
Andy Adamson5f657532012-10-03 02:39:34 -0400904 p->o_res.access_request = p->o_arg.access;
Trond Myklebust2ced46c2007-07-03 23:48:13 -0400905 nfs_fattr_init(&p->f_attr);
Trond Myklebust6926afd2012-01-07 13:22:46 -0500906 nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name);
Trond Myklebust2ced46c2007-07-03 23:48:13 -0400907}
908
Al Viro82a2c1b2011-06-22 18:30:55 -0400909static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
Trond Myklebustdc0b0272008-12-23 15:21:56 -0500910 struct nfs4_state_owner *sp, fmode_t fmode, int flags,
Trond Myklebust8535b2b2010-05-13 12:51:01 -0400911 const struct iattr *attrs,
David Quigley1775fd32013-05-22 12:50:42 -0400912 struct nfs4_label *label,
Trond Myklebust4a1c0892013-03-15 14:57:33 -0400913 enum open_claim_type4 claim,
Trond Myklebust8535b2b2010-05-13 12:51:01 -0400914 gfp_t gfp_mask)
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100915{
Al Viro82a2c1b2011-06-22 18:30:55 -0400916 struct dentry *parent = dget_parent(dentry);
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100917 struct inode *dir = parent->d_inode;
918 struct nfs_server *server = NFS_SERVER(dir);
919 struct nfs4_opendata *p;
920
Trond Myklebust8535b2b2010-05-13 12:51:01 -0400921 p = kzalloc(sizeof(*p), gfp_mask);
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100922 if (p == NULL)
923 goto err;
David Quigley14c43f72013-05-22 12:50:43 -0400924
925 p->f_label = nfs4_label_alloc(server, gfp_mask);
926 if (IS_ERR(p->f_label))
927 goto err_free_p;
928
Trond Myklebust8535b2b2010-05-13 12:51:01 -0400929 p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100930 if (p->o_arg.seqid == NULL)
David Quigley14c43f72013-05-22 12:50:43 -0400931 goto err_free_label;
Al Viro82a2c1b2011-06-22 18:30:55 -0400932 nfs_sb_active(dentry->d_sb);
933 p->dentry = dget(dentry);
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100934 p->dir = parent;
935 p->owner = sp;
936 atomic_inc(&sp->so_count);
Trond Myklebustdc0b0272008-12-23 15:21:56 -0500937 p->o_arg.open_flags = flags;
938 p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
Weston Andros Adamsonae2bb032012-10-02 14:49:52 -0700939 /* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS
940 * will return permission denied for all bits until close */
941 if (!(flags & O_EXCL)) {
942 /* ask server to check for all possible rights as results
943 * are cached */
944 p->o_arg.access = NFS4_ACCESS_READ | NFS4_ACCESS_MODIFY |
945 NFS4_ACCESS_EXTEND | NFS4_ACCESS_EXECUTE;
Weston Andros Adamsonae2bb032012-10-02 14:49:52 -0700946 }
David Howells7539bba2006-08-22 20:06:09 -0400947 p->o_arg.clientid = server->nfs_client->cl_clientid;
Trond Myklebust95b72eb2012-04-20 19:24:51 -0400948 p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);
949 p->o_arg.id.uniquifier = sp->so_seqid.owner_id;
Al Viro82a2c1b2011-06-22 18:30:55 -0400950 p->o_arg.name = &dentry->d_name;
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100951 p->o_arg.server = server;
David Quigleyaa9c2662013-05-22 12:50:44 -0400952 p->o_arg.bitmask = nfs4_bitmask(server, label);
Trond Myklebust1549210f2012-06-05 09:16:47 -0400953 p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
David Quigley1775fd32013-05-22 12:50:42 -0400954 p->o_arg.label = label;
Trond Myklebust49f9a0f2013-03-15 16:44:28 -0400955 p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
956 switch (p->o_arg.claim) {
Trond Myklebust4a1c0892013-03-15 14:57:33 -0400957 case NFS4_OPEN_CLAIM_NULL:
958 case NFS4_OPEN_CLAIM_DELEGATE_CUR:
959 case NFS4_OPEN_CLAIM_DELEGATE_PREV:
960 p->o_arg.fh = NFS_FH(dir);
961 break;
962 case NFS4_OPEN_CLAIM_PREVIOUS:
963 case NFS4_OPEN_CLAIM_FH:
964 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
965 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
966 p->o_arg.fh = NFS_FH(dentry->d_inode);
967 }
Trond Myklebust536e43d2012-01-17 22:04:26 -0500968 if (attrs != NULL && attrs->ia_valid != 0) {
Trond Myklebustc281fa9c2013-08-20 21:06:49 -0400969 __u32 verf[2];
Trond Myklebustd77d76f2010-06-16 09:52:27 -0400970
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100971 p->o_arg.u.attrs = &p->attrs;
972 memcpy(&p->attrs, attrs, sizeof(p->attrs));
Chuck Levercd937102012-03-02 17:14:31 -0500973
974 verf[0] = jiffies;
975 verf[1] = current->pid;
976 memcpy(p->o_arg.u.verifier.data, verf,
977 sizeof(p->o_arg.u.verifier.data));
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100978 }
Trond Myklebustcdd4e682006-01-03 09:55:12 +0100979 p->c_arg.fh = &p->o_res.fh;
980 p->c_arg.stateid = &p->o_res.stateid;
981 p->c_arg.seqid = p->o_arg.seqid;
Trond Myklebust2ced46c2007-07-03 23:48:13 -0400982 nfs4_init_opendata_res(p);
Trond Myklebustc6d00e62007-06-17 16:02:44 -0400983 kref_init(&p->kref);
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100984 return p;
David Quigley14c43f72013-05-22 12:50:43 -0400985
986err_free_label:
987 nfs4_label_free(p->f_label);
988err_free_p:
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100989 kfree(p);
990err:
991 dput(parent);
992 return NULL;
993}
994
Trond Myklebustc6d00e62007-06-17 16:02:44 -0400995static void nfs4_opendata_free(struct kref *kref)
Trond Myklebuste56e0b782006-01-03 09:55:08 +0100996{
Trond Myklebustc6d00e62007-06-17 16:02:44 -0400997 struct nfs4_opendata *p = container_of(kref,
998 struct nfs4_opendata, kref);
Al Viro82a2c1b2011-06-22 18:30:55 -0400999 struct super_block *sb = p->dentry->d_sb;
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001000
1001 nfs_free_seqid(p->o_arg.seqid);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001002 if (p->state != NULL)
1003 nfs4_put_open_state(p->state);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001004 nfs4_put_state_owner(p->owner);
David Quigley14c43f72013-05-22 12:50:43 -04001005
1006 nfs4_label_free(p->f_label);
1007
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001008 dput(p->dir);
Al Viro82a2c1b2011-06-22 18:30:55 -04001009 dput(p->dentry);
1010 nfs_sb_deactive(sb);
Trond Myklebust6926afd2012-01-07 13:22:46 -05001011 nfs_fattr_free_names(&p->f_attr);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001012 kfree(p);
1013}
1014
1015static void nfs4_opendata_put(struct nfs4_opendata *p)
1016{
1017 if (p != NULL)
1018 kref_put(&p->kref, nfs4_opendata_free);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001019}
1020
Trond Myklebust06f814a2006-01-03 09:55:07 +01001021static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
1022{
Trond Myklebust06f814a2006-01-03 09:55:07 +01001023 int ret;
1024
Trond Myklebust06f814a2006-01-03 09:55:07 +01001025 ret = rpc_wait_for_completion_task(task);
Trond Myklebust06f814a2006-01-03 09:55:07 +01001026 return ret;
1027}
1028
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001029static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode)
Trond Myklebust6ee41262007-07-08 14:11:36 -04001030{
1031 int ret = 0;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001032
Trond Myklebust536e43d2012-01-17 22:04:26 -05001033 if (open_mode & (O_EXCL|O_TRUNC))
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001034 goto out;
1035 switch (mode & (FMODE_READ|FMODE_WRITE)) {
Trond Myklebust6ee41262007-07-08 14:11:36 -04001036 case FMODE_READ:
Trond Myklebust88069f72009-12-08 08:33:16 -05001037 ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0
1038 && state->n_rdonly != 0;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001039 break;
1040 case FMODE_WRITE:
Trond Myklebust88069f72009-12-08 08:33:16 -05001041 ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0
1042 && state->n_wronly != 0;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001043 break;
1044 case FMODE_READ|FMODE_WRITE:
Trond Myklebust88069f72009-12-08 08:33:16 -05001045 ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0
1046 && state->n_rdwr != 0;
Trond Myklebust6ee41262007-07-08 14:11:36 -04001047 }
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001048out:
Trond Myklebust6ee41262007-07-08 14:11:36 -04001049 return ret;
1050}
1051
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001052static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001053{
Trond Myklebust652f89f2011-12-09 19:05:58 -05001054 if (delegation == NULL)
1055 return 0;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001056 if ((delegation->type & fmode) != fmode)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001057 return 0;
Trond Myklebust15c831b2008-12-23 15:21:39 -05001058 if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
Trond Myklebustaac00a82007-07-05 19:02:21 -04001059 return 0;
Trond Myklebustd25be542013-02-05 11:43:28 -05001060 if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
1061 return 0;
Trond Myklebustb7391f42008-12-23 15:21:52 -05001062 nfs_mark_delegation_referenced(delegation);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001063 return 1;
1064}
1065
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001066static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
Trond Myklebuste7616922006-01-03 09:55:13 +01001067{
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001068 switch (fmode) {
Trond Myklebuste7616922006-01-03 09:55:13 +01001069 case FMODE_WRITE:
1070 state->n_wronly++;
1071 break;
1072 case FMODE_READ:
1073 state->n_rdonly++;
1074 break;
1075 case FMODE_READ|FMODE_WRITE:
1076 state->n_rdwr++;
1077 }
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001078 nfs4_state_set_mode_locked(state, state->state | fmode);
Trond Myklebuste7616922006-01-03 09:55:13 +01001079}
1080
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001081static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
Trond Myklebust003707c2007-07-05 18:07:55 -04001082{
1083 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
Trond Myklebustf597c532012-03-04 18:13:56 -05001084 nfs4_stateid_copy(&state->stateid, stateid);
1085 nfs4_stateid_copy(&state->open_stateid, stateid);
Trond Myklebust92b40e92013-04-20 01:25:45 -04001086 set_bit(NFS_OPEN_STATE, &state->flags);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001087 switch (fmode) {
Trond Myklebust003707c2007-07-05 18:07:55 -04001088 case FMODE_READ:
1089 set_bit(NFS_O_RDONLY_STATE, &state->flags);
1090 break;
1091 case FMODE_WRITE:
1092 set_bit(NFS_O_WRONLY_STATE, &state->flags);
1093 break;
1094 case FMODE_READ|FMODE_WRITE:
1095 set_bit(NFS_O_RDWR_STATE, &state->flags);
1096 }
1097}
1098
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001099static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
Trond Myklebust003707c2007-07-05 18:07:55 -04001100{
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001101 write_seqlock(&state->seqlock);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001102 nfs_set_open_stateid_locked(state, stateid, fmode);
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001103 write_sequnlock(&state->seqlock);
Trond Myklebust003707c2007-07-05 18:07:55 -04001104}
1105
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001106static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107{
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001108 /*
1109 * Protect the call to nfs4_state_set_mode_locked and
1110 * serialise the stateid update
1111 */
1112 write_seqlock(&state->seqlock);
Trond Myklebust003707c2007-07-05 18:07:55 -04001113 if (deleg_stateid != NULL) {
Trond Myklebustf597c532012-03-04 18:13:56 -05001114 nfs4_stateid_copy(&state->stateid, deleg_stateid);
Trond Myklebust003707c2007-07-05 18:07:55 -04001115 set_bit(NFS_DELEGATED_STATE, &state->flags);
1116 }
1117 if (open_stateid != NULL)
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001118 nfs_set_open_stateid_locked(state, open_stateid, fmode);
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001119 write_sequnlock(&state->seqlock);
1120 spin_lock(&state->owner->so_lock);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001121 update_open_stateflags(state, fmode);
Trond Myklebustec073422005-10-20 14:22:47 -07001122 spin_unlock(&state->owner->so_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123}
1124
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001125static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *delegation, fmode_t fmode)
Trond Myklebust34310432008-12-23 15:21:38 -05001126{
1127 struct nfs_inode *nfsi = NFS_I(state->inode);
1128 struct nfs_delegation *deleg_cur;
1129 int ret = 0;
1130
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001131 fmode &= (FMODE_READ|FMODE_WRITE);
Trond Myklebust34310432008-12-23 15:21:38 -05001132
1133 rcu_read_lock();
1134 deleg_cur = rcu_dereference(nfsi->delegation);
1135 if (deleg_cur == NULL)
1136 goto no_delegation;
1137
1138 spin_lock(&deleg_cur->lock);
Trond Myklebust17f26b12013-08-21 15:48:42 -04001139 if (rcu_dereference(nfsi->delegation) != deleg_cur ||
Trond Myklebustd25be542013-02-05 11:43:28 -05001140 test_bit(NFS_DELEGATION_RETURNING, &deleg_cur->flags) ||
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001141 (deleg_cur->type & fmode) != fmode)
Trond Myklebust34310432008-12-23 15:21:38 -05001142 goto no_delegation_unlock;
1143
1144 if (delegation == NULL)
1145 delegation = &deleg_cur->stateid;
Trond Myklebustf597c532012-03-04 18:13:56 -05001146 else if (!nfs4_stateid_match(&deleg_cur->stateid, delegation))
Trond Myklebust34310432008-12-23 15:21:38 -05001147 goto no_delegation_unlock;
1148
Trond Myklebustb7391f42008-12-23 15:21:52 -05001149 nfs_mark_delegation_referenced(deleg_cur);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001150 __update_open_stateid(state, open_stateid, &deleg_cur->stateid, fmode);
Trond Myklebust34310432008-12-23 15:21:38 -05001151 ret = 1;
1152no_delegation_unlock:
1153 spin_unlock(&deleg_cur->lock);
1154no_delegation:
1155 rcu_read_unlock();
1156
1157 if (!ret && open_stateid != NULL) {
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001158 __update_open_stateid(state, open_stateid, NULL, fmode);
Trond Myklebust34310432008-12-23 15:21:38 -05001159 ret = 1;
1160 }
1161
1162 return ret;
1163}
1164
1165
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001166static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001167{
1168 struct nfs_delegation *delegation;
1169
1170 rcu_read_lock();
1171 delegation = rcu_dereference(NFS_I(inode)->delegation);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001172 if (delegation == NULL || (delegation->type & fmode) == fmode) {
Trond Myklebustaac00a82007-07-05 19:02:21 -04001173 rcu_read_unlock();
1174 return;
1175 }
1176 rcu_read_unlock();
Bryan Schumaker57ec14c2012-06-20 15:53:44 -04001177 nfs4_inode_return_delegation(inode);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001178}
1179
Trond Myklebust6ee41262007-07-08 14:11:36 -04001180static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
Trond Myklebustaac00a82007-07-05 19:02:21 -04001181{
1182 struct nfs4_state *state = opendata->state;
1183 struct nfs_inode *nfsi = NFS_I(state->inode);
1184 struct nfs_delegation *delegation;
Trond Myklebustf448bad2013-05-29 15:36:40 -04001185 int open_mode = opendata->o_arg.open_flags;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001186 fmode_t fmode = opendata->o_arg.fmode;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001187 nfs4_stateid stateid;
1188 int ret = -EAGAIN;
1189
Trond Myklebustaac00a82007-07-05 19:02:21 -04001190 for (;;) {
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001191 if (can_open_cached(state, fmode, open_mode)) {
Trond Myklebust6ee41262007-07-08 14:11:36 -04001192 spin_lock(&state->owner->so_lock);
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001193 if (can_open_cached(state, fmode, open_mode)) {
1194 update_open_stateflags(state, fmode);
Trond Myklebust6ee41262007-07-08 14:11:36 -04001195 spin_unlock(&state->owner->so_lock);
Trond Myklebust6ee41262007-07-08 14:11:36 -04001196 goto out_return_state;
1197 }
1198 spin_unlock(&state->owner->so_lock);
1199 }
Trond Myklebust34310432008-12-23 15:21:38 -05001200 rcu_read_lock();
1201 delegation = rcu_dereference(nfsi->delegation);
Trond Myklebust652f89f2011-12-09 19:05:58 -05001202 if (!can_open_delegated(delegation, fmode)) {
Trond Myklebust34310432008-12-23 15:21:38 -05001203 rcu_read_unlock();
Trond Myklebust6ee41262007-07-08 14:11:36 -04001204 break;
Trond Myklebust34310432008-12-23 15:21:38 -05001205 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04001206 /* Save the delegation */
Trond Myklebustf597c532012-03-04 18:13:56 -05001207 nfs4_stateid_copy(&stateid, &delegation->stateid);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001208 rcu_read_unlock();
Trond Myklebustfa332942013-04-09 12:56:52 -04001209 nfs_release_seqid(opendata->o_arg.seqid);
Trond Myklebustbdeca1b2013-04-23 14:52:44 -04001210 if (!opendata->is_recover) {
1211 ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
1212 if (ret != 0)
1213 goto out;
1214 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04001215 ret = -EAGAIN;
Trond Myklebust34310432008-12-23 15:21:38 -05001216
1217 /* Try to update the stateid using the delegation */
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001218 if (update_open_stateid(state, NULL, &stateid, fmode))
Trond Myklebust34310432008-12-23 15:21:38 -05001219 goto out_return_state;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001220 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04001221out:
1222 return ERR_PTR(ret);
1223out_return_state:
1224 atomic_inc(&state->count);
1225 return state;
1226}
1227
Andy Adamsone23008e2012-10-02 21:07:32 -04001228static void
1229nfs4_opendata_check_deleg(struct nfs4_opendata *data, struct nfs4_state *state)
1230{
1231 struct nfs_client *clp = NFS_SERVER(state->inode)->nfs_client;
1232 struct nfs_delegation *delegation;
1233 int delegation_flags = 0;
1234
1235 rcu_read_lock();
1236 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
1237 if (delegation)
1238 delegation_flags = delegation->flags;
1239 rcu_read_unlock();
1240 if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
1241 pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
1242 "returning a delegation for "
1243 "OPEN(CLAIM_DELEGATE_CUR)\n",
1244 clp->cl_hostname);
1245 } else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
1246 nfs_inode_set_delegation(state->inode,
1247 data->owner->so_cred,
1248 &data->o_res);
1249 else
1250 nfs_inode_reclaim_delegation(state->inode,
1251 data->owner->so_cred,
1252 &data->o_res);
1253}
1254
1255/*
1256 * Check the inode attributes against the CLAIM_PREVIOUS returned attributes
1257 * and update the nfs4_state.
1258 */
1259static struct nfs4_state *
1260_nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
1261{
1262 struct inode *inode = data->state->inode;
1263 struct nfs4_state *state = data->state;
1264 int ret;
1265
1266 if (!data->rpc_done) {
1267 ret = data->rpc_status;
1268 goto err;
1269 }
1270
1271 ret = -ESTALE;
1272 if (!(data->f_attr.valid & NFS_ATTR_FATTR_TYPE) ||
1273 !(data->f_attr.valid & NFS_ATTR_FATTR_FILEID) ||
1274 !(data->f_attr.valid & NFS_ATTR_FATTR_CHANGE))
1275 goto err;
1276
1277 ret = -ENOMEM;
1278 state = nfs4_get_open_state(inode, data->owner);
1279 if (state == NULL)
1280 goto err;
1281
1282 ret = nfs_refresh_inode(inode, &data->f_attr);
1283 if (ret)
1284 goto err;
1285
David Quigleyaa9c2662013-05-22 12:50:44 -04001286 nfs_setsecurity(inode, &data->f_attr, data->f_label);
1287
Andy Adamsone23008e2012-10-02 21:07:32 -04001288 if (data->o_res.delegation_type != 0)
1289 nfs4_opendata_check_deleg(data, state);
1290 update_open_stateid(state, &data->o_res.stateid, NULL,
1291 data->o_arg.fmode);
1292
1293 return state;
1294err:
1295 return ERR_PTR(ret);
1296
1297}
1298
1299static struct nfs4_state *
1300_nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001301{
1302 struct inode *inode;
1303 struct nfs4_state *state = NULL;
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001304 int ret;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001305
Trond Myklebustaac00a82007-07-05 19:02:21 -04001306 if (!data->rpc_done) {
Trond Myklebust6ee41262007-07-08 14:11:36 -04001307 state = nfs4_try_open_cached(data);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001308 goto out;
1309 }
1310
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001311 ret = -EAGAIN;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001312 if (!(data->f_attr.valid & NFS_ATTR_FATTR))
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001313 goto err;
David Quigley1775fd32013-05-22 12:50:42 -04001314 inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr, data->f_label);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001315 ret = PTR_ERR(inode);
Trond Myklebust03f28e32006-03-20 13:44:48 -05001316 if (IS_ERR(inode))
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001317 goto err;
1318 ret = -ENOMEM;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001319 state = nfs4_get_open_state(inode, data->owner);
1320 if (state == NULL)
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001321 goto err_put_inode;
Andy Adamsone23008e2012-10-02 21:07:32 -04001322 if (data->o_res.delegation_type != 0)
1323 nfs4_opendata_check_deleg(data, state);
Trond Myklebust34310432008-12-23 15:21:38 -05001324 update_open_stateid(state, &data->o_res.stateid, NULL,
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001325 data->o_arg.fmode);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001326 iput(inode);
Trond Myklebustaac00a82007-07-05 19:02:21 -04001327out:
Trond Myklebust7aa262b52013-02-28 16:19:59 -08001328 nfs_release_seqid(data->o_arg.seqid);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001329 return state;
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001330err_put_inode:
1331 iput(inode);
1332err:
1333 return ERR_PTR(ret);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001334}
1335
Andy Adamsone23008e2012-10-02 21:07:32 -04001336static struct nfs4_state *
1337nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
1338{
1339 if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS)
1340 return _nfs4_opendata_reclaim_to_nfs4_state(data);
1341 return _nfs4_opendata_to_nfs4_state(data);
1342}
1343
Trond Myklebust864472e2006-01-03 09:55:15 +01001344static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
1345{
1346 struct nfs_inode *nfsi = NFS_I(state->inode);
1347 struct nfs_open_context *ctx;
1348
1349 spin_lock(&state->inode->i_lock);
1350 list_for_each_entry(ctx, &nfsi->open_files, list) {
1351 if (ctx->state != state)
1352 continue;
1353 get_nfs_open_context(ctx);
1354 spin_unlock(&state->inode->i_lock);
1355 return ctx;
1356 }
1357 spin_unlock(&state->inode->i_lock);
1358 return ERR_PTR(-ENOENT);
1359}
1360
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001361static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx,
1362 struct nfs4_state *state, enum open_claim_type4 claim)
Trond Myklebust6f220ed2007-07-17 21:50:45 -04001363{
1364 struct nfs4_opendata *opendata;
1365
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001366 opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0,
David Quigley1775fd32013-05-22 12:50:42 -04001367 NULL, NULL, claim, GFP_NOFS);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04001368 if (opendata == NULL)
1369 return ERR_PTR(-ENOMEM);
1370 opendata->state = state;
1371 atomic_inc(&state->count);
1372 return opendata;
1373}
1374
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001375static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res)
Trond Myklebust864472e2006-01-03 09:55:15 +01001376{
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001377 struct nfs4_state *newstate;
Trond Myklebust864472e2006-01-03 09:55:15 +01001378 int ret;
1379
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001380 opendata->o_arg.open_flags = 0;
1381 opendata->o_arg.fmode = fmode;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001382 memset(&opendata->o_res, 0, sizeof(opendata->o_res));
1383 memset(&opendata->c_res, 0, sizeof(opendata->c_res));
1384 nfs4_init_opendata_res(opendata);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08001385 ret = _nfs4_recover_proc_open(opendata);
Trond Myklebust864472e2006-01-03 09:55:15 +01001386 if (ret != 0)
1387 return ret;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001388 newstate = nfs4_opendata_to_nfs4_state(opendata);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001389 if (IS_ERR(newstate))
1390 return PTR_ERR(newstate);
Al Viro643168c2011-06-22 18:20:23 -04001391 nfs4_close_state(newstate, fmode);
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001392 *res = newstate;
Trond Myklebust864472e2006-01-03 09:55:15 +01001393 return 0;
1394}
1395
1396static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state)
1397{
Trond Myklebust864472e2006-01-03 09:55:15 +01001398 struct nfs4_state *newstate;
Trond Myklebust864472e2006-01-03 09:55:15 +01001399 int ret;
1400
1401 /* memory barrier prior to reading state->n_* */
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001402 clear_bit(NFS_DELEGATED_STATE, &state->flags);
Trond Myklebustfd068b22013-04-22 11:29:51 -04001403 clear_bit(NFS_OPEN_STATE, &state->flags);
Trond Myklebust864472e2006-01-03 09:55:15 +01001404 smp_rmb();
1405 if (state->n_rdwr != 0) {
Trond Myklebustb0ed9db2010-10-04 17:59:08 -04001406 clear_bit(NFS_O_RDWR_STATE, &state->flags);
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001407 ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
Trond Myklebust864472e2006-01-03 09:55:15 +01001408 if (ret != 0)
1409 return ret;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001410 if (newstate != state)
1411 return -ESTALE;
Trond Myklebust864472e2006-01-03 09:55:15 +01001412 }
1413 if (state->n_wronly != 0) {
Trond Myklebustb0ed9db2010-10-04 17:59:08 -04001414 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001415 ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
Trond Myklebust864472e2006-01-03 09:55:15 +01001416 if (ret != 0)
1417 return ret;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001418 if (newstate != state)
1419 return -ESTALE;
Trond Myklebust864472e2006-01-03 09:55:15 +01001420 }
1421 if (state->n_rdonly != 0) {
Trond Myklebustb0ed9db2010-10-04 17:59:08 -04001422 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001423 ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
Trond Myklebust864472e2006-01-03 09:55:15 +01001424 if (ret != 0)
1425 return ret;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001426 if (newstate != state)
1427 return -ESTALE;
Trond Myklebust864472e2006-01-03 09:55:15 +01001428 }
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001429 /*
1430 * We may have performed cached opens for all three recoveries.
1431 * Check if we need to update the current stateid.
1432 */
1433 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
Trond Myklebustf597c532012-03-04 18:13:56 -05001434 !nfs4_stateid_match(&state->stateid, &state->open_stateid)) {
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001435 write_seqlock(&state->seqlock);
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001436 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
Trond Myklebustf597c532012-03-04 18:13:56 -05001437 nfs4_stateid_copy(&state->stateid, &state->open_stateid);
Trond Myklebust8bda4e42007-07-09 10:45:42 -04001438 write_sequnlock(&state->seqlock);
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001439 }
Trond Myklebust864472e2006-01-03 09:55:15 +01001440 return 0;
1441}
1442
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443/*
1444 * OPEN_RECLAIM:
1445 * reclaim state on the server after a reboot.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 */
Trond Myklebust539cd032007-06-05 11:46:42 -04001447static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448{
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001449 struct nfs_delegation *delegation;
Trond Myklebust864472e2006-01-03 09:55:15 +01001450 struct nfs4_opendata *opendata;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001451 fmode_t delegation_type = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 int status;
1453
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001454 opendata = nfs4_open_recoverdata_alloc(ctx, state,
1455 NFS4_OPEN_CLAIM_PREVIOUS);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04001456 if (IS_ERR(opendata))
1457 return PTR_ERR(opendata);
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001458 rcu_read_lock();
1459 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
Trond Myklebust15c831b2008-12-23 15:21:39 -05001460 if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0)
Trond Myklebust65bbf6b2007-08-27 09:57:46 -04001461 delegation_type = delegation->type;
Trond Myklebust1ac7e2f2007-07-08 21:04:15 -04001462 rcu_read_unlock();
Trond Myklebust864472e2006-01-03 09:55:15 +01001463 opendata->o_arg.u.delegation_type = delegation_type;
1464 status = nfs4_open_recover(opendata, state);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001465 nfs4_opendata_put(opendata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001466 return status;
1467}
1468
Trond Myklebust539cd032007-06-05 11:46:42 -04001469static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470{
1471 struct nfs_server *server = NFS_SERVER(state->inode);
1472 struct nfs4_exception exception = { };
1473 int err;
1474 do {
Trond Myklebust539cd032007-06-05 11:46:42 -04001475 err = _nfs4_do_open_reclaim(ctx, state);
Trond Myklebust42113a72013-08-12 16:19:27 -04001476 trace_nfs4_open_reclaim(ctx, 0, err);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001477 if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
1478 continue;
Trond Myklebust168667c2010-10-19 19:47:49 -04001479 if (err != -NFS4ERR_DELAY)
Trond Myklebust202b50d2005-06-22 17:16:29 +00001480 break;
1481 nfs4_handle_exception(server, err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001482 } while (exception.retry);
1483 return err;
1484}
1485
Trond Myklebust864472e2006-01-03 09:55:15 +01001486static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
1487{
1488 struct nfs_open_context *ctx;
1489 int ret;
1490
1491 ctx = nfs4_state_find_open_context(state);
1492 if (IS_ERR(ctx))
Trond Myklebust91876b12013-03-28 14:01:33 -04001493 return -EAGAIN;
Trond Myklebust539cd032007-06-05 11:46:42 -04001494 ret = nfs4_do_open_reclaim(ctx, state);
Trond Myklebust864472e2006-01-03 09:55:15 +01001495 put_nfs_open_context(ctx);
1496 return ret;
1497}
1498
Trond Myklebustdb4f2e632013-04-01 15:56:46 -04001499static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct nfs4_state *state, const nfs4_stateid *stateid, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500{
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001501 switch (err) {
1502 default:
1503 printk(KERN_ERR "NFS: %s: unhandled error "
1504 "%d.\n", __func__, err);
1505 case 0:
1506 case -ENOENT:
1507 case -ESTALE:
1508 break;
1509 case -NFS4ERR_BADSESSION:
1510 case -NFS4ERR_BADSLOT:
1511 case -NFS4ERR_BAD_HIGH_SLOT:
1512 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1513 case -NFS4ERR_DEADSESSION:
1514 set_bit(NFS_DELEGATED_STATE, &state->flags);
1515 nfs4_schedule_session_recovery(server->nfs_client->cl_session, err);
1516 return -EAGAIN;
1517 case -NFS4ERR_STALE_CLIENTID:
1518 case -NFS4ERR_STALE_STATEID:
1519 set_bit(NFS_DELEGATED_STATE, &state->flags);
1520 case -NFS4ERR_EXPIRED:
1521 /* Don't recall a delegation if it was lost */
1522 nfs4_schedule_lease_recovery(server->nfs_client);
1523 return -EAGAIN;
1524 case -NFS4ERR_DELEG_REVOKED:
1525 case -NFS4ERR_ADMIN_REVOKED:
1526 case -NFS4ERR_BAD_STATEID:
Trond Myklebustdb4f2e632013-04-01 15:56:46 -04001527 case -NFS4ERR_OPENMODE:
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001528 nfs_inode_find_state_and_recover(state->inode,
1529 stateid);
1530 nfs4_schedule_stateid_recovery(server, state);
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001531 return 0;
1532 case -NFS4ERR_DELAY:
1533 case -NFS4ERR_GRACE:
1534 set_bit(NFS_DELEGATED_STATE, &state->flags);
1535 ssleep(1);
1536 return -EAGAIN;
Trond Myklebustdb4f2e632013-04-01 15:56:46 -04001537 case -ENOMEM:
1538 case -NFS4ERR_DENIED:
1539 /* kill_proc(fl->fl_pid, SIGLOST, 1); */
1540 return 0;
Trond Myklebustbe76b5b2013-04-01 15:40:44 -04001541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001542 return err;
1543}
1544
Trond Myklebustdb4f2e632013-04-01 15:56:46 -04001545int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
1546{
1547 struct nfs_server *server = NFS_SERVER(state->inode);
1548 struct nfs4_opendata *opendata;
1549 int err;
1550
1551 opendata = nfs4_open_recoverdata_alloc(ctx, state,
1552 NFS4_OPEN_CLAIM_DELEG_CUR_FH);
1553 if (IS_ERR(opendata))
1554 return PTR_ERR(opendata);
1555 nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
1556 err = nfs4_open_recover(opendata, state);
1557 nfs4_opendata_put(opendata);
1558 return nfs4_handle_delegation_recall_error(server, state, stateid, err);
1559}
1560
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001561static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
1562{
1563 struct nfs4_opendata *data = calldata;
1564
1565 data->rpc_status = task->tk_status;
Trond Myklebust26e976a2006-01-03 09:55:21 +01001566 if (data->rpc_status == 0) {
Trond Myklebustf597c532012-03-04 18:13:56 -05001567 nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid);
Trond Myklebustbb226292008-01-02 15:19:18 -05001568 nfs_confirm_seqid(&data->owner->so_seqid, 0);
Trond Myklebust26e976a2006-01-03 09:55:21 +01001569 renew_lease(data->o_res.server, data->timestamp);
Trond Myklebust3e309912007-07-07 13:19:59 -04001570 data->rpc_done = 1;
Trond Myklebust26e976a2006-01-03 09:55:21 +01001571 }
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001572}
1573
1574static void nfs4_open_confirm_release(void *calldata)
1575{
1576 struct nfs4_opendata *data = calldata;
1577 struct nfs4_state *state = NULL;
1578
1579 /* If this request hasn't been cancelled, do nothing */
1580 if (data->cancelled == 0)
1581 goto out_free;
1582 /* In case of error, no cleanup! */
Trond Myklebust3e309912007-07-07 13:19:59 -04001583 if (!data->rpc_done)
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001584 goto out_free;
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001585 state = nfs4_opendata_to_nfs4_state(data);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001586 if (!IS_ERR(state))
Al Viro643168c2011-06-22 18:20:23 -04001587 nfs4_close_state(state, data->o_arg.fmode);
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001588out_free:
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001589 nfs4_opendata_put(data);
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001590}
1591
1592static const struct rpc_call_ops nfs4_open_confirm_ops = {
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001593 .rpc_call_done = nfs4_open_confirm_done,
1594 .rpc_release = nfs4_open_confirm_release,
1595};
1596
1597/*
1598 * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata
1599 */
1600static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
1601{
1602 struct nfs_server *server = NFS_SERVER(data->dir->d_inode);
1603 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04001604 struct rpc_message msg = {
1605 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM],
1606 .rpc_argp = &data->c_arg,
1607 .rpc_resp = &data->c_res,
1608 .rpc_cred = data->owner->so_cred,
1609 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04001610 struct rpc_task_setup task_setup_data = {
1611 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04001612 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04001613 .callback_ops = &nfs4_open_confirm_ops,
1614 .callback_data = data,
Trond Myklebust101070c2008-02-19 20:04:23 -05001615 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04001616 .flags = RPC_TASK_ASYNC,
1617 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 int status;
1619
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001620 kref_get(&data->kref);
Trond Myklebust3e309912007-07-07 13:19:59 -04001621 data->rpc_done = 0;
1622 data->rpc_status = 0;
Trond Myklebust5138fde2007-07-14 15:40:01 -04001623 data->timestamp = jiffies;
Trond Myklebustc970aa82007-07-14 15:39:59 -04001624 task = rpc_run_task(&task_setup_data);
Trond Myklebust7a1218a2006-03-20 18:11:10 -05001625 if (IS_ERR(task))
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001626 return PTR_ERR(task);
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001627 status = nfs4_wait_for_completion_rpc_task(task);
1628 if (status != 0) {
1629 data->cancelled = 1;
1630 smp_wmb();
1631 } else
1632 status = data->rpc_status;
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05001633 rpc_put_task(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 return status;
1635}
1636
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001637static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001638{
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001639 struct nfs4_opendata *data = calldata;
1640 struct nfs4_state_owner *sp = data->owner;
Trond Myklebust549b19c2013-04-16 18:42:34 -04001641 struct nfs_client *clp = sp->so_server->nfs_client;
Trond Myklebust5138fde2007-07-14 15:40:01 -04001642
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001643 if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05001644 goto out_wait;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001645 /*
1646 * Check if we still need to send an OPEN call, or if we can use
1647 * a delegation instead.
1648 */
1649 if (data->state != NULL) {
1650 struct nfs_delegation *delegation;
1651
Trond Myklebustdc0b0272008-12-23 15:21:56 -05001652 if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags))
Trond Myklebust6ee41262007-07-08 14:11:36 -04001653 goto out_no_action;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001654 rcu_read_lock();
1655 delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
Trond Myklebust652f89f2011-12-09 19:05:58 -05001656 if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR &&
Trond Myklebustcd4c9be2013-04-23 14:46:25 -04001657 data->o_arg.claim != NFS4_OPEN_CLAIM_DELEG_CUR_FH &&
Trond Myklebust652f89f2011-12-09 19:05:58 -05001658 can_open_delegated(delegation, data->o_arg.fmode))
1659 goto unlock_no_action;
Trond Myklebustaac00a82007-07-05 19:02:21 -04001660 rcu_read_unlock();
1661 }
Trond Myklebust95b72eb2012-04-20 19:24:51 -04001662 /* Update client id. */
Trond Myklebust549b19c2013-04-16 18:42:34 -04001663 data->o_arg.clientid = clp->cl_clientid;
Trond Myklebust8188df12013-04-23 14:31:19 -04001664 switch (data->o_arg.claim) {
1665 case NFS4_OPEN_CLAIM_PREVIOUS:
1666 case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
1667 case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
Andy Adamsone23008e2012-10-02 21:07:32 -04001668 data->o_arg.open_bitmap = &nfs4_open_noattr_bitmap[0];
Trond Myklebust8188df12013-04-23 14:31:19 -04001669 case NFS4_OPEN_CLAIM_FH:
1670 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
Trond Myklebust6f220ed2007-07-17 21:50:45 -04001671 nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
1672 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01001673 data->timestamp = jiffies;
Trond Myklebust035168a2010-06-16 09:52:26 -04001674 if (nfs4_setup_sequence(data->o_arg.server,
Andy Adamsond8985282009-04-01 09:22:21 -04001675 &data->o_arg.seq_args,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04001676 &data->o_res.seq_res,
1677 task) != 0)
1678 nfs_release_seqid(data->o_arg.seqid);
Trond Myklebust549b19c2013-04-16 18:42:34 -04001679
1680 /* Set the create mode (note dependency on the session type) */
1681 data->o_arg.createmode = NFS4_CREATE_UNCHECKED;
1682 if (data->o_arg.open_flags & O_EXCL) {
1683 data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE;
1684 if (nfs4_has_persistent_session(clp))
1685 data->o_arg.createmode = NFS4_CREATE_GUARDED;
1686 else if (clp->cl_mvops->minor_version > 0)
1687 data->o_arg.createmode = NFS4_CREATE_EXCLUSIVE4_1;
1688 }
Trond Myklebust6ee41262007-07-08 14:11:36 -04001689 return;
Trond Myklebust652f89f2011-12-09 19:05:58 -05001690unlock_no_action:
1691 rcu_read_unlock();
Trond Myklebust6ee41262007-07-08 14:11:36 -04001692out_no_action:
1693 task->tk_action = NULL;
Trond Myklebustc8da19b2013-02-11 19:01:21 -05001694out_wait:
Trond Myklebustb75ad4c2012-11-29 17:27:47 -05001695 nfs4_sequence_done(task, &data->o_res.seq_res);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08001696}
1697
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001698static void nfs4_open_done(struct rpc_task *task, void *calldata)
1699{
1700 struct nfs4_opendata *data = calldata;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001701
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001702 data->rpc_status = task->tk_status;
Andy Adamsond8985282009-04-01 09:22:21 -04001703
Trond Myklebust14516c32010-07-31 14:29:06 -04001704 if (!nfs4_sequence_done(task, &data->o_res.seq_res))
1705 return;
Andy Adamsond8985282009-04-01 09:22:21 -04001706
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001707 if (task->tk_status == 0) {
Trond Myklebust807d66d82012-10-02 17:09:00 -07001708 if (data->o_res.f_attr->valid & NFS_ATTR_FATTR_TYPE) {
1709 switch (data->o_res.f_attr->mode & S_IFMT) {
Trond Myklebust6f926b52005-10-18 14:20:18 -07001710 case S_IFREG:
1711 break;
1712 case S_IFLNK:
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001713 data->rpc_status = -ELOOP;
Trond Myklebust6f926b52005-10-18 14:20:18 -07001714 break;
1715 case S_IFDIR:
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001716 data->rpc_status = -EISDIR;
Trond Myklebust6f926b52005-10-18 14:20:18 -07001717 break;
1718 default:
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001719 data->rpc_status = -ENOTDIR;
Trond Myklebust807d66d82012-10-02 17:09:00 -07001720 }
Trond Myklebust6f926b52005-10-18 14:20:18 -07001721 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01001722 renew_lease(data->o_res.server, data->timestamp);
Trond Myklebust0f9f95e2007-07-08 16:19:56 -04001723 if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
1724 nfs_confirm_seqid(&data->owner->so_seqid, 0);
Trond Myklebust6f926b52005-10-18 14:20:18 -07001725 }
Trond Myklebust3e309912007-07-07 13:19:59 -04001726 data->rpc_done = 1;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001727}
Trond Myklebust6f926b52005-10-18 14:20:18 -07001728
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001729static void nfs4_open_release(void *calldata)
1730{
1731 struct nfs4_opendata *data = calldata;
1732 struct nfs4_state *state = NULL;
1733
1734 /* If this request hasn't been cancelled, do nothing */
1735 if (data->cancelled == 0)
1736 goto out_free;
1737 /* In case of error, no cleanup! */
Trond Myklebust3e309912007-07-07 13:19:59 -04001738 if (data->rpc_status != 0 || !data->rpc_done)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001739 goto out_free;
1740 /* In case we need an open_confirm, no cleanup! */
1741 if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)
1742 goto out_free;
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001743 state = nfs4_opendata_to_nfs4_state(data);
Trond Myklebust1b370bc2007-07-07 08:04:47 -04001744 if (!IS_ERR(state))
Al Viro643168c2011-06-22 18:20:23 -04001745 nfs4_close_state(state, data->o_arg.fmode);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001746out_free:
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001747 nfs4_opendata_put(data);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001748}
1749
1750static const struct rpc_call_ops nfs4_open_ops = {
1751 .rpc_call_prepare = nfs4_open_prepare,
1752 .rpc_call_done = nfs4_open_done,
1753 .rpc_release = nfs4_open_release,
1754};
1755
Alexandros Batsakisb2579572009-12-14 21:27:57 -08001756static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001757{
1758 struct inode *dir = data->dir->d_inode;
1759 struct nfs_server *server = NFS_SERVER(dir);
1760 struct nfs_openargs *o_arg = &data->o_arg;
1761 struct nfs_openres *o_res = &data->o_res;
1762 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04001763 struct rpc_message msg = {
1764 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN],
1765 .rpc_argp = o_arg,
1766 .rpc_resp = o_res,
1767 .rpc_cred = data->owner->so_cred,
1768 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04001769 struct rpc_task_setup task_setup_data = {
1770 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04001771 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04001772 .callback_ops = &nfs4_open_ops,
1773 .callback_data = data,
Trond Myklebust101070c2008-02-19 20:04:23 -05001774 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04001775 .flags = RPC_TASK_ASYNC,
1776 };
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001777 int status;
1778
Chuck Levera9c92d62013-08-09 12:48:18 -04001779 nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001780 kref_get(&data->kref);
Trond Myklebust3e309912007-07-07 13:19:59 -04001781 data->rpc_done = 0;
1782 data->rpc_status = 0;
Trond Myklebust2ced46c2007-07-03 23:48:13 -04001783 data->cancelled = 0;
Trond Myklebustbdeca1b2013-04-23 14:52:44 -04001784 data->is_recover = 0;
1785 if (isrecover) {
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04001786 nfs4_set_sequence_privileged(&o_arg->seq_args);
Trond Myklebustbdeca1b2013-04-23 14:52:44 -04001787 data->is_recover = 1;
1788 }
Trond Myklebustc970aa82007-07-14 15:39:59 -04001789 task = rpc_run_task(&task_setup_data);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08001790 if (IS_ERR(task))
1791 return PTR_ERR(task);
1792 status = nfs4_wait_for_completion_rpc_task(task);
1793 if (status != 0) {
1794 data->cancelled = 1;
1795 smp_wmb();
1796 } else
1797 status = data->rpc_status;
1798 rpc_put_task(task);
1799
1800 return status;
1801}
1802
1803static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
1804{
1805 struct inode *dir = data->dir->d_inode;
1806 struct nfs_openres *o_res = &data->o_res;
1807 int status;
1808
1809 status = nfs4_run_open_task(data, 1);
1810 if (status != 0 || !data->rpc_done)
1811 return status;
1812
Trond Myklebust6926afd2012-01-07 13:22:46 -05001813 nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr);
1814
Alexandros Batsakisb2579572009-12-14 21:27:57 -08001815 if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
1816 status = _nfs4_proc_open_confirm(data);
1817 if (status != 0)
1818 return status;
1819 }
1820
1821 return status;
1822}
1823
Weston Andros Adamson6168f622012-09-10 14:00:46 -04001824static int nfs4_opendata_access(struct rpc_cred *cred,
1825 struct nfs4_opendata *opendata,
Weston Andros Adamsonf8d9a892013-01-03 16:42:29 -05001826 struct nfs4_state *state, fmode_t fmode,
1827 int openflags)
Weston Andros Adamson6168f622012-09-10 14:00:46 -04001828{
1829 struct nfs_access_entry cache;
1830 u32 mask;
1831
1832 /* access call failed or for some reason the server doesn't
1833 * support any access modes -- defer access call until later */
1834 if (opendata->o_res.access_supported == 0)
1835 return 0;
1836
1837 mask = 0;
Weston Andros Adamsonbbd3a8e2012-10-02 14:49:51 -07001838 /* don't check MAY_WRITE - a newly created file may not have
Weston Andros Adamsonf8d9a892013-01-03 16:42:29 -05001839 * write mode bits, but POSIX allows the creating process to write.
1840 * use openflags to check for exec, because fmode won't
1841 * always have FMODE_EXEC set when file open for exec. */
1842 if (openflags & __FMODE_EXEC) {
1843 /* ONLY check for exec rights */
1844 mask = MAY_EXEC;
1845 } else if (fmode & FMODE_READ)
1846 mask = MAY_READ;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04001847
1848 cache.cred = cred;
1849 cache.jiffies = jiffies;
1850 nfs_access_set_mask(&cache, opendata->o_res.access_result);
1851 nfs_access_add_cache(state->inode, &cache);
1852
Weston Andros Adamsonbbd3a8e2012-10-02 14:49:51 -07001853 if ((mask & ~cache.mask & (MAY_READ | MAY_EXEC)) == 0)
Weston Andros Adamson6168f622012-09-10 14:00:46 -04001854 return 0;
1855
1856 /* even though OPEN succeeded, access is denied. Close the file */
1857 nfs4_close_state(state, fmode);
Weston Andros Adamson998f40b2012-11-02 18:00:56 -04001858 return -EACCES;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04001859}
1860
Alexandros Batsakisb2579572009-12-14 21:27:57 -08001861/*
1862 * Note: On error, nfs4_proc_open will free the struct nfs4_opendata
1863 */
1864static int _nfs4_proc_open(struct nfs4_opendata *data)
1865{
1866 struct inode *dir = data->dir->d_inode;
1867 struct nfs_server *server = NFS_SERVER(dir);
1868 struct nfs_openargs *o_arg = &data->o_arg;
1869 struct nfs_openres *o_res = &data->o_res;
1870 int status;
1871
1872 status = nfs4_run_open_task(data, 0);
Trond Myklebust08ef7bd2011-10-18 16:11:49 -07001873 if (!data->rpc_done)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001874 return status;
Trond Myklebust08ef7bd2011-10-18 16:11:49 -07001875 if (status != 0) {
1876 if (status == -NFS4ERR_BADNAME &&
1877 !(o_arg->open_flags & O_CREAT))
1878 return -ENOENT;
1879 return status;
1880 }
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001881
Trond Myklebust6926afd2012-01-07 13:22:46 -05001882 nfs_fattr_map_and_free_names(server, &data->f_attr);
1883
Trond Myklebust90ff0c52012-04-27 13:48:18 -04001884 if (o_arg->open_flags & O_CREAT)
Trond Myklebust56ae19f2005-10-27 22:12:40 -04001885 update_changeattr(dir, &o_res->cinfo);
Trond Myklebust0df5dd42010-04-11 16:48:44 -04001886 if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
1887 server->caps &= ~NFS_CAP_POSIX_LOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
Trond Myklebustcdd4e682006-01-03 09:55:12 +01001889 status = _nfs4_proc_open_confirm(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 if (status != 0)
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001891 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 }
1893 if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
David Quigley1775fd32013-05-22 12:50:42 -04001894 _nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr, o_res->f_label);
Trond Myklebust24ac23a2006-01-03 09:55:11 +01001895 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896}
1897
Andy Adamsond83217c2011-03-01 01:34:17 +00001898static int nfs4_recover_expired_lease(struct nfs_server *server)
1899{
1900 return nfs4_client_recover_expired_lease(server->nfs_client);
1901}
1902
Linus Torvalds1da177e2005-04-16 15:20:36 -07001903/*
1904 * OPEN_EXPIRED:
1905 * reclaim state on the server after a network partition.
1906 * Assumes caller holds the appropriate lock
1907 */
Trond Myklebust539cd032007-06-05 11:46:42 -04001908static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001909{
Trond Myklebuste56e0b782006-01-03 09:55:08 +01001910 struct nfs4_opendata *opendata;
Trond Myklebust864472e2006-01-03 09:55:15 +01001911 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912
Trond Myklebust4a1c0892013-03-15 14:57:33 -04001913 opendata = nfs4_open_recoverdata_alloc(ctx, state,
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001914 NFS4_OPEN_CLAIM_FH);
Trond Myklebust6f220ed2007-07-17 21:50:45 -04001915 if (IS_ERR(opendata))
1916 return PTR_ERR(opendata);
Trond Myklebust864472e2006-01-03 09:55:15 +01001917 ret = nfs4_open_recover(opendata, state);
Trond Myklebust35d05772008-04-05 15:54:17 -04001918 if (ret == -ESTALE)
Al Viro3d4ff432011-06-22 18:40:12 -04001919 d_drop(ctx->dentry);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04001920 nfs4_opendata_put(opendata);
Trond Myklebust864472e2006-01-03 09:55:15 +01001921 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001922}
1923
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05001924static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
Trond Myklebust202b50d2005-06-22 17:16:29 +00001925{
Trond Myklebust539cd032007-06-05 11:46:42 -04001926 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust202b50d2005-06-22 17:16:29 +00001927 struct nfs4_exception exception = { };
1928 int err;
1929
1930 do {
Trond Myklebust539cd032007-06-05 11:46:42 -04001931 err = _nfs4_open_expired(ctx, state);
Trond Myklebust42113a72013-08-12 16:19:27 -04001932 trace_nfs4_open_expired(ctx, 0, err);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04001933 if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
1934 continue;
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05001935 switch (err) {
1936 default:
1937 goto out;
1938 case -NFS4ERR_GRACE:
1939 case -NFS4ERR_DELAY:
1940 nfs4_handle_exception(server, err, &exception);
1941 err = 0;
1942 }
Trond Myklebust202b50d2005-06-22 17:16:29 +00001943 } while (exception.retry);
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05001944out:
Trond Myklebust202b50d2005-06-22 17:16:29 +00001945 return err;
1946}
1947
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
1949{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 struct nfs_open_context *ctx;
Trond Myklebust864472e2006-01-03 09:55:15 +01001951 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952
Trond Myklebust864472e2006-01-03 09:55:15 +01001953 ctx = nfs4_state_find_open_context(state);
1954 if (IS_ERR(ctx))
Trond Myklebust91876b12013-03-28 14:01:33 -04001955 return -EAGAIN;
Trond Myklebust539cd032007-06-05 11:46:42 -04001956 ret = nfs4_do_open_expired(ctx, state);
Trond Myklebust864472e2006-01-03 09:55:15 +01001957 put_nfs_open_context(ctx);
1958 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001959}
1960
Bryan Schumakerf062eb62011-06-02 14:59:10 -04001961#if defined(CONFIG_NFS_V4_1)
Chuck Lever3e60ffd2012-07-11 16:30:14 -04001962static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
Bryan Schumakerf062eb62011-06-02 14:59:10 -04001963{
Bryan Schumakerf062eb62011-06-02 14:59:10 -04001964 struct nfs_server *server = NFS_SERVER(state->inode);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04001965 nfs4_stateid *stateid = &state->stateid;
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04001966 struct nfs_delegation *delegation;
1967 struct rpc_cred *cred = NULL;
1968 int status = -NFS4ERR_BAD_STATEID;
Bryan Schumakerf062eb62011-06-02 14:59:10 -04001969
Chuck Lever3e60ffd2012-07-11 16:30:14 -04001970 /* If a state reset has been done, test_stateid is unneeded */
1971 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
1972 return;
1973
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04001974 /* Get the delegation credential for use by test/free_stateid */
1975 rcu_read_lock();
1976 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
1977 if (delegation != NULL &&
1978 nfs4_stateid_match(&delegation->stateid, stateid)) {
1979 cred = get_rpccred(delegation->cred);
1980 rcu_read_unlock();
1981 status = nfs41_test_stateid(server, stateid, cred);
Trond Myklebust08cb47f2013-08-20 21:59:40 -04001982 trace_nfs4_test_delegation_stateid(state, NULL, status);
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04001983 } else
1984 rcu_read_unlock();
1985
Chuck Lever3e60ffd2012-07-11 16:30:14 -04001986 if (status != NFS_OK) {
1987 /* Free the stateid unless the server explicitly
1988 * informs us the stateid is unrecognized. */
1989 if (status != -NFS4ERR_BAD_STATEID)
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04001990 nfs41_free_stateid(server, stateid, cred);
Bryan Schumaker69388672012-09-26 15:25:52 -04001991 nfs_remove_bad_delegation(state->inode);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04001992
Bryan Schumaker69388672012-09-26 15:25:52 -04001993 write_seqlock(&state->seqlock);
1994 nfs4_stateid_copy(&state->stateid, &state->open_stateid);
1995 write_sequnlock(&state->seqlock);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04001996 clear_bit(NFS_DELEGATED_STATE, &state->flags);
1997 }
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04001998
1999 if (cred != NULL)
2000 put_rpccred(cred);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002001}
2002
2003/**
2004 * nfs41_check_open_stateid - possibly free an open stateid
2005 *
2006 * @state: NFSv4 state for an inode
2007 *
2008 * Returns NFS_OK if recovery for this stateid is now finished.
2009 * Otherwise a negative NFS4ERR value is returned.
2010 */
2011static int nfs41_check_open_stateid(struct nfs4_state *state)
2012{
2013 struct nfs_server *server = NFS_SERVER(state->inode);
Bryan Schumakerfcb6d9c2012-09-26 15:25:53 -04002014 nfs4_stateid *stateid = &state->open_stateid;
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002015 struct rpc_cred *cred = state->owner->so_cred;
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002016 int status;
2017
2018 /* If a state reset has been done, test_stateid is unneeded */
2019 if ((test_bit(NFS_O_RDONLY_STATE, &state->flags) == 0) &&
2020 (test_bit(NFS_O_WRONLY_STATE, &state->flags) == 0) &&
2021 (test_bit(NFS_O_RDWR_STATE, &state->flags) == 0))
2022 return -NFS4ERR_BAD_STATEID;
2023
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002024 status = nfs41_test_stateid(server, stateid, cred);
Trond Myklebust08cb47f2013-08-20 21:59:40 -04002025 trace_nfs4_test_open_stateid(state, NULL, status);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002026 if (status != NFS_OK) {
2027 /* Free the stateid unless the server explicitly
2028 * informs us the stateid is unrecognized. */
2029 if (status != -NFS4ERR_BAD_STATEID)
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04002030 nfs41_free_stateid(server, stateid, cred);
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002031
2032 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
2033 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
2034 clear_bit(NFS_O_RDWR_STATE, &state->flags);
Trond Myklebustfd068b22013-04-22 11:29:51 -04002035 clear_bit(NFS_OPEN_STATE, &state->flags);
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05002036 }
2037 return status;
2038}
2039
2040static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
2041{
Chuck Levereb64cf92012-07-11 16:30:05 -04002042 int status;
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05002043
Chuck Lever3e60ffd2012-07-11 16:30:14 -04002044 nfs41_clear_delegation_stateid(state);
2045 status = nfs41_check_open_stateid(state);
Chuck Levereb64cf92012-07-11 16:30:05 -04002046 if (status != NFS_OK)
2047 status = nfs4_open_expired(sp, state);
2048 return status;
Bryan Schumakerf062eb62011-06-02 14:59:10 -04002049}
2050#endif
2051
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052/*
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002053 * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-*
2054 * fields corresponding to attributes that were used to store the verifier.
2055 * Make sure we clobber those fields in the later setattr call
2056 */
2057static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr)
2058{
2059 if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) &&
2060 !(sattr->ia_valid & ATTR_ATIME_SET))
2061 sattr->ia_valid |= ATTR_ATIME;
2062
2063 if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) &&
2064 !(sattr->ia_valid & ATTR_MTIME_SET))
2065 sattr->ia_valid |= ATTR_MTIME;
2066}
2067
Trond Myklebustc21443c2013-02-07 14:26:21 -05002068static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
2069 fmode_t fmode,
2070 int flags,
Trond Myklebust3efb9722013-05-29 13:17:04 -04002071 struct nfs_open_context *ctx)
Trond Myklebustc21443c2013-02-07 14:26:21 -05002072{
2073 struct nfs4_state_owner *sp = opendata->owner;
2074 struct nfs_server *server = sp->so_server;
Trond Myklebust275bb302013-05-29 13:11:28 -04002075 struct dentry *dentry;
Trond Myklebustc21443c2013-02-07 14:26:21 -05002076 struct nfs4_state *state;
2077 unsigned int seq;
2078 int ret;
2079
2080 seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
2081
2082 ret = _nfs4_proc_open(opendata);
2083 if (ret != 0)
2084 goto out;
2085
2086 state = nfs4_opendata_to_nfs4_state(opendata);
2087 ret = PTR_ERR(state);
2088 if (IS_ERR(state))
2089 goto out;
2090 if (server->caps & NFS_CAP_POSIX_LOCK)
2091 set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
2092
Trond Myklebust275bb302013-05-29 13:11:28 -04002093 dentry = opendata->dentry;
2094 if (dentry->d_inode == NULL) {
2095 /* FIXME: Is this d_drop() ever needed? */
2096 d_drop(dentry);
2097 dentry = d_add_unique(dentry, igrab(state->inode));
2098 if (dentry == NULL) {
2099 dentry = opendata->dentry;
2100 } else if (dentry != ctx->dentry) {
2101 dput(ctx->dentry);
2102 ctx->dentry = dget(dentry);
2103 }
2104 nfs_set_verifier(dentry,
2105 nfs_save_change_attribute(opendata->dir->d_inode));
2106 }
2107
Trond Myklebustc21443c2013-02-07 14:26:21 -05002108 ret = nfs4_opendata_access(sp->so_cred, opendata, state, fmode, flags);
2109 if (ret != 0)
2110 goto out;
2111
Trond Myklebust3efb9722013-05-29 13:17:04 -04002112 ctx->state = state;
Trond Myklebustc45ffdd2013-05-29 13:34:46 -04002113 if (dentry->d_inode == state->inode) {
2114 nfs_inode_attach_open_context(ctx);
2115 if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
2116 nfs4_schedule_stateid_recovery(server, state);
2117 }
Trond Myklebustc21443c2013-02-07 14:26:21 -05002118out:
2119 return ret;
2120}
2121
Jeff Laytonaa53ed52007-06-05 14:49:03 -04002122/*
Trond Myklebust24ac23a2006-01-03 09:55:11 +01002123 * Returns a referenced nfs4_state
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 */
Andy Adamson82be4172012-05-23 05:02:35 -04002125static int _nfs4_do_open(struct inode *dir,
Trond Myklebust4197a052013-05-29 12:37:49 -04002126 struct nfs_open_context *ctx,
Andy Adamson82be4172012-05-23 05:02:35 -04002127 int flags,
2128 struct iattr *sattr,
Trond Myklebust959d9212013-06-28 16:29:51 -04002129 struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002130{
2131 struct nfs4_state_owner *sp;
2132 struct nfs4_state *state = NULL;
2133 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01002134 struct nfs4_opendata *opendata;
Trond Myklebust4197a052013-05-29 12:37:49 -04002135 struct dentry *dentry = ctx->dentry;
2136 struct rpc_cred *cred = ctx->cred;
2137 struct nfs4_threshold **ctx_th = &ctx->mdsthreshold;
2138 fmode_t fmode = ctx->mode & (FMODE_READ|FMODE_WRITE|FMODE_EXEC);
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002139 enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL;
David Quigley1775fd32013-05-22 12:50:42 -04002140 struct nfs4_label *olabel = NULL;
Trond Myklebustaac00a82007-07-05 19:02:21 -04002141 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002142
2143 /* Protect against reboot recovery conflicts */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144 status = -ENOMEM;
Trond Myklebustd1e284d2012-01-17 22:04:24 -05002145 sp = nfs4_get_state_owner(server, cred, GFP_KERNEL);
2146 if (sp == NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002147 dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
2148 goto out_err;
2149 }
Trond Myklebust58d97142006-01-03 09:55:24 +01002150 status = nfs4_recover_expired_lease(server);
2151 if (status != 0)
Trond Myklebustb4454fe2006-01-03 09:55:25 +01002152 goto err_put_state_owner;
Al Viro82a2c1b2011-06-22 18:30:55 -04002153 if (dentry->d_inode != NULL)
2154 nfs4_return_incompatible_delegation(dentry->d_inode, fmode);
Trond Myklebust58d97142006-01-03 09:55:24 +01002155 status = -ENOMEM;
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002156 if (dentry->d_inode)
2157 claim = NFS4_OPEN_CLAIM_FH;
Trond Myklebust4a1c0892013-03-15 14:57:33 -04002158 opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr,
David Quigley1775fd32013-05-22 12:50:42 -04002159 label, claim, GFP_KERNEL);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01002160 if (opendata == NULL)
Trond Myklebust95d35cb2008-12-23 15:21:45 -05002161 goto err_put_state_owner;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002162
David Quigley14c43f72013-05-22 12:50:43 -04002163 if (label) {
2164 olabel = nfs4_label_alloc(server, GFP_KERNEL);
2165 if (IS_ERR(olabel)) {
2166 status = PTR_ERR(olabel);
2167 goto err_opendata_put;
2168 }
2169 }
2170
Andy Adamson82be4172012-05-23 05:02:35 -04002171 if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
2172 opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
2173 if (!opendata->f_attr.mdsthreshold)
David Quigley14c43f72013-05-22 12:50:43 -04002174 goto err_free_label;
Trond Myklebust1549210f2012-06-05 09:16:47 -04002175 opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0];
Andy Adamson82be4172012-05-23 05:02:35 -04002176 }
Al Viro82a2c1b2011-06-22 18:30:55 -04002177 if (dentry->d_inode != NULL)
2178 opendata->state = nfs4_get_open_state(dentry->d_inode, sp);
Trond Myklebustaac00a82007-07-05 19:02:21 -04002179
Trond Myklebust3efb9722013-05-29 13:17:04 -04002180 status = _nfs4_open_and_get_state(opendata, fmode, flags, ctx);
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002181 if (status != 0)
David Quigley14c43f72013-05-22 12:50:43 -04002182 goto err_free_label;
Trond Myklebust3efb9722013-05-29 13:17:04 -04002183 state = ctx->state;
Weston Andros Adamson6168f622012-09-10 14:00:46 -04002184
Trond Myklebust549b19c2013-04-16 18:42:34 -04002185 if ((opendata->o_arg.open_flags & O_EXCL) &&
2186 (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) {
Trond Myklebust0ab64e02010-04-16 16:22:51 -04002187 nfs4_exclusive_attrset(opendata, sattr);
2188
2189 nfs_fattr_init(opendata->o_res.f_attr);
2190 status = nfs4_do_setattr(state->inode, cred,
2191 opendata->o_res.f_attr, sattr,
David Quigley1775fd32013-05-22 12:50:42 -04002192 state, label, olabel);
2193 if (status == 0) {
Trond Myklebust0ab64e02010-04-16 16:22:51 -04002194 nfs_setattr_update_inode(state->inode, sattr);
David Quigley1775fd32013-05-22 12:50:42 -04002195 nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
David Quigleyaa9c2662013-05-22 12:50:44 -04002196 nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel);
David Quigley1775fd32013-05-22 12:50:42 -04002197 }
Trond Myklebust0ab64e02010-04-16 16:22:51 -04002198 }
Andy Adamson82be4172012-05-23 05:02:35 -04002199
2200 if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
2201 *ctx_th = opendata->f_attr.mdsthreshold;
2202 else
2203 kfree(opendata->f_attr.mdsthreshold);
2204 opendata->f_attr.mdsthreshold = NULL;
2205
David Quigley14c43f72013-05-22 12:50:43 -04002206 nfs4_label_free(olabel);
2207
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002208 nfs4_opendata_put(opendata);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 nfs4_put_state_owner(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210 return 0;
David Quigley14c43f72013-05-22 12:50:43 -04002211err_free_label:
2212 nfs4_label_free(olabel);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002213err_opendata_put:
Andy Adamson82be4172012-05-23 05:02:35 -04002214 kfree(opendata->f_attr.mdsthreshold);
Trond Myklebustc6d00e62007-06-17 16:02:44 -04002215 nfs4_opendata_put(opendata);
Trond Myklebuste56e0b782006-01-03 09:55:08 +01002216err_put_state_owner:
2217 nfs4_put_state_owner(sp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002218out_err:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 return status;
2220}
2221
2222
Andy Adamson82be4172012-05-23 05:02:35 -04002223static struct nfs4_state *nfs4_do_open(struct inode *dir,
Trond Myklebust4197a052013-05-29 12:37:49 -04002224 struct nfs_open_context *ctx,
Andy Adamson82be4172012-05-23 05:02:35 -04002225 int flags,
2226 struct iattr *sattr,
Trond Myklebust959d9212013-06-28 16:29:51 -04002227 struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228{
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002229 struct nfs_server *server = NFS_SERVER(dir);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002230 struct nfs4_exception exception = { };
2231 struct nfs4_state *res;
2232 int status;
2233
2234 do {
Trond Myklebust959d9212013-06-28 16:29:51 -04002235 status = _nfs4_do_open(dir, ctx, flags, sattr, label);
Trond Myklebust3efb9722013-05-29 13:17:04 -04002236 res = ctx->state;
Trond Myklebust42113a72013-08-12 16:19:27 -04002237 trace_nfs4_open_file(ctx, flags, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 if (status == 0)
2239 break;
2240 /* NOTE: BAD_SEQID means the server and client disagree about the
2241 * book-keeping w.r.t. state-changing operations
2242 * (OPEN/CLOSE/LOCK/LOCKU...)
2243 * It is actually a sign of a bug on the client or on the server.
2244 *
2245 * If we receive a BAD_SEQID error in the particular case of
Trond Myklebustcee54fc2005-10-18 14:20:12 -07002246 * doing an OPEN, we assume that nfs_increment_open_seqid() will
Linus Torvalds1da177e2005-04-16 15:20:36 -07002247 * have unhashed the old state_owner for us, and that we can
2248 * therefore safely retry using a new one. We should still warn
2249 * the user though...
2250 */
2251 if (status == -NFS4ERR_BAD_SEQID) {
Trond Myklebust9a3ba432012-03-12 18:01:48 -04002252 pr_warn_ratelimited("NFS: v4 server %s "
Trond Myklebust6f43ddc2007-07-08 16:49:11 -04002253 " returned a bad sequence-id error!\n",
2254 NFS_SERVER(dir)->nfs_client->cl_hostname);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 exception.retry = 1;
2256 continue;
2257 }
Trond Myklebust550f5742005-10-18 14:20:21 -07002258 /*
2259 * BAD_STATEID on OPEN means that the server cancelled our
2260 * state before it received the OPEN_CONFIRM.
2261 * Recover by retrying the request as per the discussion
2262 * on Page 181 of RFC3530.
2263 */
2264 if (status == -NFS4ERR_BAD_STATEID) {
2265 exception.retry = 1;
2266 continue;
2267 }
Trond Myklebustaac00a82007-07-05 19:02:21 -04002268 if (status == -EAGAIN) {
2269 /* We must have found a delegation */
2270 exception.retry = 1;
2271 continue;
2272 }
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04002273 if (nfs4_clear_cap_atomic_open_v1(server, status, &exception))
2274 continue;
2275 res = ERR_PTR(nfs4_handle_exception(server,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 status, &exception));
2277 } while (exception.retry);
2278 return res;
2279}
2280
Trond Myklebust659bfcd2008-06-10 19:39:41 -04002281static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
2282 struct nfs_fattr *fattr, struct iattr *sattr,
David Quigley1775fd32013-05-22 12:50:42 -04002283 struct nfs4_state *state, struct nfs4_label *ilabel,
2284 struct nfs4_label *olabel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285{
Trond Myklebust3e4f6292006-03-20 13:44:46 -05002286 struct nfs_server *server = NFS_SERVER(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 struct nfs_setattrargs arg = {
Trond Myklebust3e4f6292006-03-20 13:44:46 -05002288 .fh = NFS_FH(inode),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 .iap = sattr,
2290 .server = server,
2291 .bitmask = server->attr_bitmask,
David Quigley1775fd32013-05-22 12:50:42 -04002292 .label = ilabel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 };
2294 struct nfs_setattrres res = {
2295 .fattr = fattr,
David Quigley1775fd32013-05-22 12:50:42 -04002296 .label = olabel,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 .server = server,
2298 };
2299 struct rpc_message msg = {
Trond Myklebust659bfcd2008-06-10 19:39:41 -04002300 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
2301 .rpc_argp = &arg,
2302 .rpc_resp = &res,
2303 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002304 };
Trond Myklebust26e976a2006-01-03 09:55:21 +01002305 unsigned long timestamp = jiffies;
Trond Myklebustee3ae842013-04-29 10:35:36 -04002306 fmode_t fmode;
2307 bool truncate;
Trond Myklebust65e43082005-08-16 11:49:44 -04002308 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002309
David Quigleyaa9c2662013-05-22 12:50:44 -04002310 arg.bitmask = nfs4_bitmask(server, ilabel);
2311 if (ilabel)
2312 arg.bitmask = nfs4_bitmask(server, olabel);
2313
Trond Myklebust0e574af2005-10-27 22:12:38 -04002314 nfs_fattr_init(fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002315
Trond Myklebustee3ae842013-04-29 10:35:36 -04002316 /* Servers should only apply open mode checks for file size changes */
2317 truncate = (sattr->ia_valid & ATTR_SIZE) ? true : false;
2318 fmode = truncate ? FMODE_WRITE : FMODE_READ;
2319
2320 if (nfs4_copy_delegation_stateid(&arg.stateid, inode, fmode)) {
2321 /* Use that stateid */
2322 } else if (truncate && state != NULL && nfs4_valid_open_stateid(state)) {
Trond Myklebust2a369152012-08-13 18:54:45 -04002323 struct nfs_lockowner lockowner = {
2324 .l_owner = current->files,
2325 .l_pid = current->tgid,
2326 };
Trond Myklebust4fc87962012-03-08 17:42:01 -05002327 nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
Trond Myklebust2a369152012-08-13 18:54:45 -04002328 &lockowner);
Trond Myklebust08e9eac2005-06-22 17:16:29 +00002329 } else
Trond Myklebustf597c532012-03-04 18:13:56 -05002330 nfs4_stateid_copy(&arg.stateid, &zero_stateid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002331
Bryan Schumaker7c513052011-03-24 17:12:24 +00002332 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Trond Myklebust26e976a2006-01-03 09:55:21 +01002333 if (status == 0 && state != NULL)
2334 renew_lease(server, timestamp);
Trond Myklebust65e43082005-08-16 11:49:44 -04002335 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336}
2337
Trond Myklebust659bfcd2008-06-10 19:39:41 -04002338static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
2339 struct nfs_fattr *fattr, struct iattr *sattr,
David Quigley1775fd32013-05-22 12:50:42 -04002340 struct nfs4_state *state, struct nfs4_label *ilabel,
2341 struct nfs4_label *olabel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342{
Trond Myklebust3e4f6292006-03-20 13:44:46 -05002343 struct nfs_server *server = NFS_SERVER(inode);
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -05002344 struct nfs4_exception exception = {
2345 .state = state,
Trond Myklebust3114ea72012-03-07 16:39:06 -05002346 .inode = inode,
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -05002347 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348 int err;
2349 do {
David Quigley1775fd32013-05-22 12:50:42 -04002350 err = _nfs4_do_setattr(inode, cred, fattr, sattr, state, ilabel, olabel);
Trond Myklebustc1578b72013-08-12 16:58:42 -04002351 trace_nfs4_setattr(inode, err);
Trond Myklebust451146b2012-04-18 16:29:11 -04002352 switch (err) {
2353 case -NFS4ERR_OPENMODE:
Trond Myklebust721ccfb2013-04-29 11:11:58 -04002354 if (!(sattr->ia_valid & ATTR_SIZE)) {
2355 pr_warn_once("NFSv4: server %s is incorrectly "
2356 "applying open mode checks to "
2357 "a SETATTR that is not "
2358 "changing file size.\n",
2359 server->nfs_client->cl_hostname);
2360 }
Trond Myklebust451146b2012-04-18 16:29:11 -04002361 if (state && !(state->state & FMODE_WRITE)) {
2362 err = -EBADF;
2363 if (sattr->ia_valid & ATTR_OPEN)
2364 err = -EACCES;
2365 goto out;
2366 }
2367 }
2368 err = nfs4_handle_exception(server, err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002369 } while (exception.retry);
Trond Myklebust451146b2012-04-18 16:29:11 -04002370out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371 return err;
2372}
2373
2374struct nfs4_closedata {
2375 struct inode *inode;
2376 struct nfs4_state *state;
2377 struct nfs_closeargs arg;
2378 struct nfs_closeres res;
Trond Myklebust516a6af2005-10-27 22:12:41 -04002379 struct nfs_fattr fattr;
Trond Myklebust26e976a2006-01-03 09:55:21 +01002380 unsigned long timestamp;
Fred Isamanf7e89172011-01-06 11:36:32 +00002381 bool roc;
2382 u32 roc_barrier;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383};
2384
Trond Myklebust963d8fe2006-01-03 09:55:04 +01002385static void nfs4_free_closedata(void *data)
Trond Myklebust95121352005-10-18 14:20:12 -07002386{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01002387 struct nfs4_closedata *calldata = data;
2388 struct nfs4_state_owner *sp = calldata->state->owner;
Al Viro643168c2011-06-22 18:20:23 -04002389 struct super_block *sb = calldata->state->inode->i_sb;
Trond Myklebust95121352005-10-18 14:20:12 -07002390
Fred Isamanf7e89172011-01-06 11:36:32 +00002391 if (calldata->roc)
2392 pnfs_roc_release(calldata->state->inode);
Trond Myklebust95121352005-10-18 14:20:12 -07002393 nfs4_put_open_state(calldata->state);
2394 nfs_free_seqid(calldata->arg.seqid);
Trond Myklebust95121352005-10-18 14:20:12 -07002395 nfs4_put_state_owner(sp);
Trond Myklebust322b2b92013-01-11 16:39:51 -05002396 nfs_sb_deactive(sb);
Trond Myklebust95121352005-10-18 14:20:12 -07002397 kfree(calldata);
2398}
2399
Trond Myklebust88069f72009-12-08 08:33:16 -05002400static void nfs4_close_clear_stateid_flags(struct nfs4_state *state,
2401 fmode_t fmode)
2402{
2403 spin_lock(&state->owner->so_lock);
Trond Myklebust88069f72009-12-08 08:33:16 -05002404 clear_bit(NFS_O_RDWR_STATE, &state->flags);
Trond Myklebustfd068b22013-04-22 11:29:51 -04002405 switch (fmode & (FMODE_READ|FMODE_WRITE)) {
2406 case FMODE_WRITE:
2407 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
2408 break;
2409 case FMODE_READ:
2410 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
2411 break;
2412 case 0:
2413 clear_bit(NFS_O_RDONLY_STATE, &state->flags);
2414 clear_bit(NFS_O_WRONLY_STATE, &state->flags);
2415 clear_bit(NFS_OPEN_STATE, &state->flags);
2416 }
Trond Myklebust88069f72009-12-08 08:33:16 -05002417 spin_unlock(&state->owner->so_lock);
2418}
2419
Trond Myklebust963d8fe2006-01-03 09:55:04 +01002420static void nfs4_close_done(struct rpc_task *task, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002421{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01002422 struct nfs4_closedata *calldata = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002423 struct nfs4_state *state = calldata->state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 struct nfs_server *server = NFS_SERVER(calldata->inode);
2425
Chuck Levera3ca5652012-03-01 17:00:40 -05002426 dprintk("%s: begin!\n", __func__);
Trond Myklebust14516c32010-07-31 14:29:06 -04002427 if (!nfs4_sequence_done(task, &calldata->res.seq_res))
2428 return;
Trond Myklebust42113a72013-08-12 16:19:27 -04002429 trace_nfs4_close(state, &calldata->arg, &calldata->res, task->tk_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 /* hmm. we are done with the inode, and in the process of freeing
2431 * the state_owner. we keep this around to process errors
2432 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002433 switch (task->tk_status) {
2434 case 0:
Fred Isamanf7e89172011-01-06 11:36:32 +00002435 if (calldata->roc)
2436 pnfs_roc_set_barrier(state->inode,
2437 calldata->roc_barrier);
Trond Myklebust45328c32007-07-26 17:47:34 -04002438 nfs_set_open_stateid(state, &calldata->res.stateid, 0);
Trond Myklebust26e976a2006-01-03 09:55:21 +01002439 renew_lease(server, calldata->timestamp);
Trond Myklebust88069f72009-12-08 08:33:16 -05002440 nfs4_close_clear_stateid_flags(state,
2441 calldata->arg.fmode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 break;
2443 case -NFS4ERR_STALE_STATEID:
Trond Myklebust9e33bed2008-12-23 15:21:46 -05002444 case -NFS4ERR_OLD_STATEID:
2445 case -NFS4ERR_BAD_STATEID:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446 case -NFS4ERR_EXPIRED:
Trond Myklebustdc0b0272008-12-23 15:21:56 -05002447 if (calldata->arg.fmode == 0)
Trond Myklebust9e33bed2008-12-23 15:21:46 -05002448 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002449 default:
Trond Myklebust72211db2009-12-15 14:47:36 -05002450 if (nfs4_async_handle_error(task, server, state) == -EAGAIN)
2451 rpc_restart_call_prepare(task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 }
Trond Myklebust72211db2009-12-15 14:47:36 -05002453 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebust516a6af2005-10-27 22:12:41 -04002454 nfs_refresh_inode(calldata->inode, calldata->res.fattr);
Chuck Levera3ca5652012-03-01 17:00:40 -05002455 dprintk("%s: done, ret = %d!\n", __func__, task->tk_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456}
2457
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01002458static void nfs4_close_prepare(struct rpc_task *task, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002459{
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01002460 struct nfs4_closedata *calldata = data;
Trond Myklebust95121352005-10-18 14:20:12 -07002461 struct nfs4_state *state = calldata->state;
Trond Myklebust7fdab062012-09-20 20:15:57 -04002462 struct inode *inode = calldata->inode;
Trond Myklebust88069f72009-12-08 08:33:16 -05002463 int call_close = 0;
Trond Myklebust95121352005-10-18 14:20:12 -07002464
Chuck Levera3ca5652012-03-01 17:00:40 -05002465 dprintk("%s: begin!\n", __func__);
Trond Myklebust963d8fe2006-01-03 09:55:04 +01002466 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05002467 goto out_wait;
Trond Myklebust003707c2007-07-05 18:07:55 -04002468
Trond Myklebust88069f72009-12-08 08:33:16 -05002469 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
2470 calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
Trond Myklebust4cecb762005-11-04 15:32:58 -05002471 spin_lock(&state->owner->so_lock);
Trond Myklebust003707c2007-07-05 18:07:55 -04002472 /* Calculate the change in open mode */
Trond Myklebuste7616922006-01-03 09:55:13 +01002473 if (state->n_rdwr == 0) {
Trond Myklebust003707c2007-07-05 18:07:55 -04002474 if (state->n_rdonly == 0) {
Trond Myklebust88069f72009-12-08 08:33:16 -05002475 call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
2476 call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
2477 calldata->arg.fmode &= ~FMODE_READ;
Trond Myklebust003707c2007-07-05 18:07:55 -04002478 }
2479 if (state->n_wronly == 0) {
Trond Myklebust88069f72009-12-08 08:33:16 -05002480 call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
2481 call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
2482 calldata->arg.fmode &= ~FMODE_WRITE;
Trond Myklebust003707c2007-07-05 18:07:55 -04002483 }
Trond Myklebuste7616922006-01-03 09:55:13 +01002484 }
Trond Myklebust5d422302013-03-14 16:57:48 -04002485 if (!nfs4_valid_open_stateid(state))
2486 call_close = 0;
Trond Myklebust4cecb762005-11-04 15:32:58 -05002487 spin_unlock(&state->owner->so_lock);
Trond Myklebust88069f72009-12-08 08:33:16 -05002488
2489 if (!call_close) {
Trond Myklebust963d8fe2006-01-03 09:55:04 +01002490 /* Note: exit _without_ calling nfs4_close_done */
Trond Myklebustc8da19b2013-02-11 19:01:21 -05002491 goto out_no_action;
Trond Myklebust95121352005-10-18 14:20:12 -07002492 }
Trond Myklebust88069f72009-12-08 08:33:16 -05002493
Fred Isamanf7e89172011-01-06 11:36:32 +00002494 if (calldata->arg.fmode == 0) {
Trond Myklebust88069f72009-12-08 08:33:16 -05002495 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
Fred Isamanf7e89172011-01-06 11:36:32 +00002496 if (calldata->roc &&
Andy Adamsonb9536ad2013-04-11 09:28:45 -04002497 pnfs_roc_drain(inode, &calldata->roc_barrier, task)) {
2498 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05002499 goto out_wait;
Andy Adamsonb9536ad2013-04-11 09:28:45 -04002500 }
Fred Isamanf7e89172011-01-06 11:36:32 +00002501 }
Trond Myklebust88069f72009-12-08 08:33:16 -05002502
Trond Myklebust516a6af2005-10-27 22:12:41 -04002503 nfs_fattr_init(calldata->res.fattr);
Trond Myklebust26e976a2006-01-03 09:55:21 +01002504 calldata->timestamp = jiffies;
Trond Myklebust7fdab062012-09-20 20:15:57 -04002505 if (nfs4_setup_sequence(NFS_SERVER(inode),
Trond Myklebust9d12b212012-01-17 22:04:25 -05002506 &calldata->arg.seq_args,
2507 &calldata->res.seq_res,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04002508 task) != 0)
2509 nfs_release_seqid(calldata->arg.seqid);
Chuck Levera3ca5652012-03-01 17:00:40 -05002510 dprintk("%s: done!\n", __func__);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05002511 return;
2512out_no_action:
2513 task->tk_action = NULL;
2514out_wait:
2515 nfs4_sequence_done(task, &calldata->res.seq_res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516}
2517
Trond Myklebust963d8fe2006-01-03 09:55:04 +01002518static const struct rpc_call_ops nfs4_close_ops = {
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01002519 .rpc_call_prepare = nfs4_close_prepare,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01002520 .rpc_call_done = nfs4_close_done,
2521 .rpc_release = nfs4_free_closedata,
2522};
2523
Linus Torvalds1da177e2005-04-16 15:20:36 -07002524/*
2525 * It is possible for data to be read/written from a mem-mapped file
2526 * after the sys_close call (which hits the vfs layer as a flush).
2527 * This means that we can't safely call nfsv4 close on a file until
2528 * the inode is cleared. This in turn means that we are not good
2529 * NFSv4 citizens - we do not indicate to the server to update the file's
2530 * share state even when we are done with one of the three share
2531 * stateid's in the inode.
2532 *
2533 * NOTE: Caller must be holding the sp->so_owner semaphore!
2534 */
Trond Myklebust1f7977c2012-09-20 20:31:51 -04002535int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536{
Trond Myklebust4a35bd42007-06-05 10:31:33 -04002537 struct nfs_server *server = NFS_SERVER(state->inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002538 struct nfs4_closedata *calldata;
Trond Myklebustb39e6252007-06-11 23:05:07 -04002539 struct nfs4_state_owner *sp = state->owner;
2540 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04002541 struct rpc_message msg = {
2542 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE],
2543 .rpc_cred = state->owner->so_cred,
2544 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04002545 struct rpc_task_setup task_setup_data = {
2546 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04002547 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002548 .callback_ops = &nfs4_close_ops,
Trond Myklebust101070c2008-02-19 20:04:23 -05002549 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04002550 .flags = RPC_TASK_ASYNC,
2551 };
Trond Myklebust95121352005-10-18 14:20:12 -07002552 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002553
Trond Myklebust8535b2b2010-05-13 12:51:01 -04002554 calldata = kzalloc(sizeof(*calldata), gfp_mask);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 if (calldata == NULL)
Trond Myklebust95121352005-10-18 14:20:12 -07002556 goto out;
Chuck Levera9c92d62013-08-09 12:48:18 -04002557 nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 1);
Trond Myklebust4a35bd42007-06-05 10:31:33 -04002558 calldata->inode = state->inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559 calldata->state = state;
Trond Myklebust4a35bd42007-06-05 10:31:33 -04002560 calldata->arg.fh = NFS_FH(state->inode);
Trond Myklebust003707c2007-07-05 18:07:55 -04002561 calldata->arg.stateid = &state->open_stateid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 /* Serialization for the sequence id */
Trond Myklebust8535b2b2010-05-13 12:51:01 -04002563 calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid, gfp_mask);
Trond Myklebust95121352005-10-18 14:20:12 -07002564 if (calldata->arg.seqid == NULL)
2565 goto out_free_calldata;
Trond Myklebustdc0b0272008-12-23 15:21:56 -05002566 calldata->arg.fmode = 0;
Trond Myklebusta65318b2009-03-11 14:10:28 -04002567 calldata->arg.bitmask = server->cache_consistency_bitmask;
Trond Myklebust516a6af2005-10-27 22:12:41 -04002568 calldata->res.fattr = &calldata->fattr;
Trond Myklebustc1d51932008-04-07 13:20:54 -04002569 calldata->res.seqid = calldata->arg.seqid;
Trond Myklebust516a6af2005-10-27 22:12:41 -04002570 calldata->res.server = server;
Trond Myklebust1f7977c2012-09-20 20:31:51 -04002571 calldata->roc = pnfs_roc(state->inode);
Al Viro643168c2011-06-22 18:20:23 -04002572 nfs_sb_active(calldata->inode->i_sb);
Trond Myklebust95121352005-10-18 14:20:12 -07002573
Trond Myklebust1174dd12010-12-21 10:52:24 -05002574 msg.rpc_argp = &calldata->arg;
2575 msg.rpc_resp = &calldata->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04002576 task_setup_data.callback_data = calldata;
2577 task = rpc_run_task(&task_setup_data);
Trond Myklebustb39e6252007-06-11 23:05:07 -04002578 if (IS_ERR(task))
2579 return PTR_ERR(task);
Trond Myklebusta49c3c72007-10-18 18:03:27 -04002580 status = 0;
2581 if (wait)
2582 status = rpc_wait_for_completion_task(task);
Trond Myklebustb39e6252007-06-11 23:05:07 -04002583 rpc_put_task(task);
Trond Myklebusta49c3c72007-10-18 18:03:27 -04002584 return status;
Trond Myklebust95121352005-10-18 14:20:12 -07002585out_free_calldata:
2586 kfree(calldata);
2587out:
Trond Myklebustb39e6252007-06-11 23:05:07 -04002588 nfs4_put_open_state(state);
2589 nfs4_put_state_owner(sp);
Trond Myklebust95121352005-10-18 14:20:12 -07002590 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591}
2592
Trond Myklebust2b484292010-09-17 10:56:51 -04002593static struct inode *
Trond Myklebustcd9a1c02010-09-17 10:56:50 -04002594nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 struct nfs4_state *state;
David Quigleyaa9c2662013-05-22 12:50:44 -04002597 struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
2598
2599 label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
Trond Myklebust565277f2007-10-15 18:17:53 -04002601 /* Protect against concurrent sillydeletes */
Trond Myklebust959d9212013-06-28 16:29:51 -04002602 state = nfs4_do_open(dir, ctx, open_flags, attr, label);
David Quigleyaa9c2662013-05-22 12:50:44 -04002603
2604 nfs4_label_release_security(label);
2605
Trond Myklebustf46e0bd2010-09-17 10:56:50 -04002606 if (IS_ERR(state))
2607 return ERR_CAST(state);
Trond Myklebust275bb302013-05-29 13:11:28 -04002608 return state->inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002609}
2610
Trond Myklebust1185a552009-12-03 15:54:02 -05002611static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
Trond Myklebust7fe5c392009-03-19 15:35:50 -04002612{
2613 if (ctx->state == NULL)
2614 return;
2615 if (is_sync)
Al Viro643168c2011-06-22 18:20:23 -04002616 nfs4_close_sync(ctx->state, ctx->mode);
Trond Myklebust7fe5c392009-03-19 15:35:50 -04002617 else
Al Viro643168c2011-06-22 18:20:23 -04002618 nfs4_close_state(ctx->state, ctx->mode);
Trond Myklebust7fe5c392009-03-19 15:35:50 -04002619}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
2621static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
2622{
Benny Halevy43652ad2009-04-01 09:21:54 -04002623 struct nfs4_server_caps_arg args = {
2624 .fhandle = fhandle,
2625 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 struct nfs4_server_caps_res res = {};
2627 struct rpc_message msg = {
2628 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS],
Benny Halevy43652ad2009-04-01 09:21:54 -04002629 .rpc_argp = &args,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 .rpc_resp = &res,
2631 };
2632 int status;
2633
Bryan Schumaker7c513052011-03-24 17:12:24 +00002634 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 if (status == 0) {
2636 memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
Trond Myklebust62ab460c2009-08-09 15:06:19 -04002637 server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS|
2638 NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
2639 NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|
2640 NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME|
2641 NFS_CAP_CTIME|NFS_CAP_MTIME);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
2643 server->caps |= NFS_CAP_ACLS;
2644 if (res.has_links != 0)
2645 server->caps |= NFS_CAP_HARDLINKS;
2646 if (res.has_symlinks != 0)
2647 server->caps |= NFS_CAP_SYMLINKS;
Trond Myklebust62ab460c2009-08-09 15:06:19 -04002648 if (res.attr_bitmask[0] & FATTR4_WORD0_FILEID)
2649 server->caps |= NFS_CAP_FILEID;
2650 if (res.attr_bitmask[1] & FATTR4_WORD1_MODE)
2651 server->caps |= NFS_CAP_MODE;
2652 if (res.attr_bitmask[1] & FATTR4_WORD1_NUMLINKS)
2653 server->caps |= NFS_CAP_NLINK;
2654 if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER)
2655 server->caps |= NFS_CAP_OWNER;
2656 if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER_GROUP)
2657 server->caps |= NFS_CAP_OWNER_GROUP;
2658 if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_ACCESS)
2659 server->caps |= NFS_CAP_ATIME;
2660 if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_METADATA)
2661 server->caps |= NFS_CAP_CTIME;
2662 if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY)
2663 server->caps |= NFS_CAP_MTIME;
David Quigleyaa9c2662013-05-22 12:50:44 -04002664#ifdef CONFIG_NFS_V4_SECURITY_LABEL
2665 if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
2666 server->caps |= NFS_CAP_SECURITY_LABEL;
2667#endif
2668 memcpy(server->attr_bitmask_nl, res.attr_bitmask,
2669 sizeof(server->attr_bitmask));
Trond Myklebust62ab460c2009-08-09 15:06:19 -04002670
David Quigleyaa9c2662013-05-22 12:50:44 -04002671 if (server->caps & NFS_CAP_SECURITY_LABEL) {
2672 server->attr_bitmask_nl[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
2673 res.attr_bitmask[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
2674 }
Trond Myklebusta65318b2009-03-11 14:10:28 -04002675 memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
2676 server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
2677 server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002678 server->acl_bitmask = res.acl_bitmask;
Chuck Lever264e6352012-03-01 17:02:05 -05002679 server->fh_expire_type = res.fh_expire_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002680 }
Andy Adamsoncccef3b2009-04-01 09:22:03 -04002681
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 return status;
2683}
2684
Trond Myklebust55a97592006-06-09 09:34:19 -04002685int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686{
2687 struct nfs4_exception exception = { };
2688 int err;
2689 do {
2690 err = nfs4_handle_exception(server,
2691 _nfs4_server_capabilities(server, fhandle),
2692 &exception);
2693 } while (exception.retry);
2694 return err;
2695}
2696
2697static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
2698 struct nfs_fsinfo *info)
2699{
David Quigleyaa9c2662013-05-22 12:50:44 -04002700 u32 bitmask[3];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 struct nfs4_lookup_root_arg args = {
David Quigleyaa9c2662013-05-22 12:50:44 -04002702 .bitmask = bitmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 };
2704 struct nfs4_lookup_res res = {
2705 .server = server,
Trond Myklebust0e574af2005-10-27 22:12:38 -04002706 .fattr = info->fattr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 .fh = fhandle,
2708 };
2709 struct rpc_message msg = {
2710 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT],
2711 .rpc_argp = &args,
2712 .rpc_resp = &res,
2713 };
Benny Halevy008f55d2009-04-01 09:22:50 -04002714
David Quigleyaa9c2662013-05-22 12:50:44 -04002715 bitmask[0] = nfs4_fattr_bitmap[0];
2716 bitmask[1] = nfs4_fattr_bitmap[1];
2717 /*
2718 * Process the label in the upcoming getfattr
2719 */
2720 bitmask[2] = nfs4_fattr_bitmap[2] & ~FATTR4_WORD2_SECURITY_LABEL;
2721
Trond Myklebust0e574af2005-10-27 22:12:38 -04002722 nfs_fattr_init(info->fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00002723 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724}
2725
2726static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
2727 struct nfs_fsinfo *info)
2728{
2729 struct nfs4_exception exception = { };
2730 int err;
2731 do {
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04002732 err = _nfs4_lookup_root(server, fhandle, info);
Trond Myklebustb5f875a2013-08-13 13:01:39 -04002733 trace_nfs4_lookup_root(server, fhandle, info->fattr, err);
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04002734 switch (err) {
2735 case 0:
2736 case -NFS4ERR_WRONGSEC:
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04002737 goto out;
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04002738 default:
2739 err = nfs4_handle_exception(server, err, &exception);
2740 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002741 } while (exception.retry);
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04002742out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 return err;
2744}
2745
Bryan Schumaker8f70e952011-03-24 17:12:31 +00002746static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
2747 struct nfs_fsinfo *info, rpc_authflavor_t flavor)
2748{
Trond Myklebustc2190662013-08-26 19:23:04 -04002749 struct rpc_auth_create_args auth_args = {
2750 .pseudoflavor = flavor,
2751 };
Bryan Schumaker8f70e952011-03-24 17:12:31 +00002752 struct rpc_auth *auth;
2753 int ret;
2754
Trond Myklebustc2190662013-08-26 19:23:04 -04002755 auth = rpcauth_create(&auth_args, server->client);
Wei Yongjune8d920c2012-09-21 12:27:41 +08002756 if (IS_ERR(auth)) {
Chuck Lever75bc8822013-03-16 15:55:36 -04002757 ret = -EACCES;
Bryan Schumaker8f70e952011-03-24 17:12:31 +00002758 goto out;
2759 }
2760 ret = nfs4_lookup_root(server, fhandle, info);
Bryan Schumaker8f70e952011-03-24 17:12:31 +00002761out:
2762 return ret;
2763}
2764
Chuck Lever9a744ba2013-03-16 15:56:02 -04002765/*
2766 * Retry pseudoroot lookup with various security flavors. We do this when:
2767 *
2768 * NFSv4.0: the PUTROOTFH operation returns NFS4ERR_WRONGSEC
2769 * NFSv4.1: the server does not support the SECINFO_NO_NAME operation
2770 *
2771 * Returns zero on success, or a negative NFS4ERR value, or a
2772 * negative errno value.
2773 */
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04002774static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
David Howells54ceac42006-08-22 20:06:13 -04002775 struct nfs_fsinfo *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776{
Chuck Lever9a744ba2013-03-16 15:56:02 -04002777 /* Per 3530bis 15.33.5 */
2778 static const rpc_authflavor_t flav_array[] = {
2779 RPC_AUTH_GSS_KRB5P,
2780 RPC_AUTH_GSS_KRB5I,
2781 RPC_AUTH_GSS_KRB5,
Chuck Leverc4eafe12013-03-16 15:56:11 -04002782 RPC_AUTH_UNIX, /* courtesy */
Chuck Lever9a744ba2013-03-16 15:56:02 -04002783 RPC_AUTH_NULL,
2784 };
2785 int status = -EPERM;
2786 size_t i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787
Chuck Lever9a744ba2013-03-16 15:56:02 -04002788 for (i = 0; i < ARRAY_SIZE(flav_array); i++) {
Bryan Schumaker8f70e952011-03-24 17:12:31 +00002789 status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04002790 if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
Bryan Schumakerd1a80162011-04-13 14:31:28 -04002791 continue;
2792 break;
Bryan Schumaker8f70e952011-03-24 17:12:31 +00002793 }
Chuck Lever9a744ba2013-03-16 15:56:02 -04002794
Bryan Schumakerfb8a5ba2011-04-18 16:52:25 -04002795 /*
2796 * -EACCESS could mean that the user doesn't have correct permissions
2797 * to access the mount. It could also mean that we tried to mount
2798 * with a gss auth flavor, but rpc.gssd isn't running. Either way,
2799 * existing mount programs don't handle -EACCES very well so it should
2800 * be mapped to -EPERM instead.
2801 */
2802 if (status == -EACCES)
2803 status = -EPERM;
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04002804 return status;
2805}
2806
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04002807static int nfs4_do_find_root_sec(struct nfs_server *server,
2808 struct nfs_fh *fhandle, struct nfs_fsinfo *info)
2809{
2810 int mv = server->nfs_client->cl_minorversion;
2811 return nfs_v4_minor_ops[mv]->find_root_sec(server, fhandle, info);
2812}
2813
2814/**
2815 * nfs4_proc_get_rootfh - get file handle for server's pseudoroot
2816 * @server: initialized nfs_server handle
2817 * @fhandle: we fill in the pseudo-fs root file handle
2818 * @info: we fill in an FSINFO struct
2819 *
2820 * Returns zero on success, or a negative errno.
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04002821 */
Bryan Schumaker3028eb22012-05-10 15:07:30 -04002822int nfs4_proc_get_rootfh(struct nfs_server *server, struct nfs_fh *fhandle,
2823 struct nfs_fsinfo *info)
Bryan Schumaker801a16dc2011-04-13 14:31:30 -04002824{
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04002825 int status;
2826
2827 status = nfs4_lookup_root(server, fhandle, info);
2828 if ((status == -NFS4ERR_WRONGSEC) &&
2829 !(server->flags & NFS_MOUNT_SECFLAVOUR))
2830 status = nfs4_do_find_root_sec(server, fhandle, info);
2831
Linus Torvalds1da177e2005-04-16 15:20:36 -07002832 if (status == 0)
2833 status = nfs4_server_capabilities(server, fhandle);
2834 if (status == 0)
2835 status = nfs4_do_fsinfo(server, fhandle, info);
Chuck Lever2ed4b95b2013-03-16 15:55:45 -04002836
Trond Myklebustc12e87f2006-03-13 21:20:47 -08002837 return nfs4_map_errors(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002838}
2839
Bryan Schumakerbae36242012-05-10 15:07:31 -04002840static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *mntfh,
2841 struct nfs_fsinfo *info)
2842{
2843 int error;
2844 struct nfs_fattr *fattr = info->fattr;
David Quigley1775fd32013-05-22 12:50:42 -04002845 struct nfs4_label *label = NULL;
Bryan Schumakerbae36242012-05-10 15:07:31 -04002846
2847 error = nfs4_server_capabilities(server, mntfh);
2848 if (error < 0) {
2849 dprintk("nfs4_get_root: getcaps error = %d\n", -error);
2850 return error;
2851 }
2852
David Quigley14c43f72013-05-22 12:50:43 -04002853 label = nfs4_label_alloc(server, GFP_KERNEL);
2854 if (IS_ERR(label))
2855 return PTR_ERR(label);
2856
David Quigley1775fd32013-05-22 12:50:42 -04002857 error = nfs4_proc_getattr(server, mntfh, fattr, label);
Bryan Schumakerbae36242012-05-10 15:07:31 -04002858 if (error < 0) {
2859 dprintk("nfs4_get_root: getattr error = %d\n", -error);
David Quigley14c43f72013-05-22 12:50:43 -04002860 goto err_free_label;
Bryan Schumakerbae36242012-05-10 15:07:31 -04002861 }
2862
2863 if (fattr->valid & NFS_ATTR_FATTR_FSID &&
2864 !nfs_fsid_equal(&server->fsid, &fattr->fsid))
2865 memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid));
2866
David Quigley14c43f72013-05-22 12:50:43 -04002867err_free_label:
2868 nfs4_label_free(label);
2869
Bryan Schumakerbae36242012-05-10 15:07:31 -04002870 return error;
2871}
2872
Manoj Naik6b97fd32006-06-09 09:34:29 -04002873/*
2874 * Get locations and (maybe) other attributes of a referral.
2875 * Note that we'll actually follow the referral later when
2876 * we detect fsid mismatch in inode revalidation
2877 */
Bryan Schumakerf05d1472012-04-27 13:27:41 -04002878static int nfs4_get_referral(struct rpc_clnt *client, struct inode *dir,
2879 const struct qstr *name, struct nfs_fattr *fattr,
2880 struct nfs_fh *fhandle)
Manoj Naik6b97fd32006-06-09 09:34:29 -04002881{
2882 int status = -ENOMEM;
2883 struct page *page = NULL;
2884 struct nfs4_fs_locations *locations = NULL;
Manoj Naik6b97fd32006-06-09 09:34:29 -04002885
2886 page = alloc_page(GFP_KERNEL);
2887 if (page == NULL)
2888 goto out;
2889 locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
2890 if (locations == NULL)
2891 goto out;
2892
Bryan Schumakerf05d1472012-04-27 13:27:41 -04002893 status = nfs4_proc_fs_locations(client, dir, name, locations, page);
Manoj Naik6b97fd32006-06-09 09:34:29 -04002894 if (status != 0)
2895 goto out;
2896 /* Make sure server returned a different fsid for the referral */
2897 if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
Andy Adamson533eb462011-06-13 18:25:56 -04002898 dprintk("%s: server did not return a different fsid for"
2899 " a referral at %s\n", __func__, name->name);
Manoj Naik6b97fd32006-06-09 09:34:29 -04002900 status = -EIO;
2901 goto out;
2902 }
Andy Adamson533eb462011-06-13 18:25:56 -04002903 /* Fixup attributes for the nfs_lookup() call to nfs_fhget() */
2904 nfs_fixup_referral_attributes(&locations->fattr);
Manoj Naik6b97fd32006-06-09 09:34:29 -04002905
Andy Adamson533eb462011-06-13 18:25:56 -04002906 /* replace the lookup nfs_fattr with the locations nfs_fattr */
Manoj Naik6b97fd32006-06-09 09:34:29 -04002907 memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
Manoj Naik6b97fd32006-06-09 09:34:29 -04002908 memset(fhandle, 0, sizeof(struct nfs_fh));
2909out:
2910 if (page)
2911 __free_page(page);
Davidlohr Bueso5d7ca352010-08-11 12:42:15 -04002912 kfree(locations);
Manoj Naik6b97fd32006-06-09 09:34:29 -04002913 return status;
2914}
2915
David Quigley1775fd32013-05-22 12:50:42 -04002916static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
2917 struct nfs_fattr *fattr, struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002918{
2919 struct nfs4_getattr_arg args = {
2920 .fh = fhandle,
2921 .bitmask = server->attr_bitmask,
2922 };
2923 struct nfs4_getattr_res res = {
2924 .fattr = fattr,
David Quigley1775fd32013-05-22 12:50:42 -04002925 .label = label,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 .server = server,
2927 };
2928 struct rpc_message msg = {
2929 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
2930 .rpc_argp = &args,
2931 .rpc_resp = &res,
2932 };
David Quigleyaa9c2662013-05-22 12:50:44 -04002933
2934 args.bitmask = nfs4_bitmask(server, label);
2935
Trond Myklebust0e574af2005-10-27 22:12:38 -04002936 nfs_fattr_init(fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00002937 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002938}
2939
David Quigley1775fd32013-05-22 12:50:42 -04002940static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
2941 struct nfs_fattr *fattr, struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002942{
2943 struct nfs4_exception exception = { };
2944 int err;
2945 do {
Trond Myklebustb5f875a2013-08-13 13:01:39 -04002946 err = _nfs4_proc_getattr(server, fhandle, fattr, label);
2947 trace_nfs4_getattr(server, fhandle, fattr, err);
2948 err = nfs4_handle_exception(server, err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949 &exception);
2950 } while (exception.retry);
2951 return err;
2952}
2953
2954/*
2955 * The file is not closed if it is opened due to the a request to change
2956 * the size of the file. The open call will not be needed once the
2957 * VFS layer lookup-intents are implemented.
2958 *
2959 * Close is called when the inode is destroyed.
2960 * If we haven't opened the file for O_WRONLY, we
2961 * need to in the size_change case to obtain a stateid.
2962 *
2963 * Got race?
2964 * Because OPEN is always done by name in nfsv4, it is
2965 * possible that we opened a different file by the same
2966 * name. We can recognize this race condition, but we
2967 * can't do anything about it besides returning an error.
2968 *
2969 * This will be fixed with VFS changes (lookup-intent).
2970 */
2971static int
2972nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
2973 struct iattr *sattr)
2974{
Trond Myklebust08e9eac2005-06-22 17:16:29 +00002975 struct inode *inode = dentry->d_inode;
Trond Myklebust659bfcd2008-06-10 19:39:41 -04002976 struct rpc_cred *cred = NULL;
Trond Myklebustd5308382005-11-04 15:33:38 -05002977 struct nfs4_state *state = NULL;
David Quigley14c43f72013-05-22 12:50:43 -04002978 struct nfs4_label *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002979 int status;
2980
Benny Halevy8a1636c2010-07-14 15:43:57 -04002981 if (pnfs_ld_layoutret_on_setattr(inode))
Trond Myklebust24028672013-03-20 13:23:33 -04002982 pnfs_commit_and_return_layout(inode);
Benny Halevy8a1636c2010-07-14 15:43:57 -04002983
Trond Myklebust0e574af2005-10-27 22:12:38 -04002984 nfs_fattr_init(fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985
Andy Adamson26699402012-05-30 16:12:24 -04002986 /* Deal with open(O_TRUNC) */
2987 if (sattr->ia_valid & ATTR_OPEN)
Nadav Shemercc7936f2013-07-21 17:21:43 +03002988 sattr->ia_valid &= ~(ATTR_MTIME|ATTR_CTIME);
Andy Adamson26699402012-05-30 16:12:24 -04002989
2990 /* Optimization: if the end result is no change, don't RPC */
Nadav Shemercc7936f2013-07-21 17:21:43 +03002991 if ((sattr->ia_valid & ~(ATTR_FILE|ATTR_OPEN)) == 0)
Andy Adamson26699402012-05-30 16:12:24 -04002992 return 0;
2993
Trond Myklebustd5308382005-11-04 15:33:38 -05002994 /* Search for an existing open(O_WRITE) file */
Trond Myklebust659bfcd2008-06-10 19:39:41 -04002995 if (sattr->ia_valid & ATTR_FILE) {
2996 struct nfs_open_context *ctx;
Trond Myklebust08e9eac2005-06-22 17:16:29 +00002997
Trond Myklebust659bfcd2008-06-10 19:39:41 -04002998 ctx = nfs_file_open_context(sattr->ia_file);
Neil Brown504e5182008-10-16 14:15:16 +11002999 if (ctx) {
3000 cred = ctx->cred;
3001 state = ctx->state;
3002 }
Trond Myklebust659bfcd2008-06-10 19:39:41 -04003003 }
3004
David Quigley14c43f72013-05-22 12:50:43 -04003005 label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
3006 if (IS_ERR(label))
3007 return PTR_ERR(label);
3008
3009 status = nfs4_do_setattr(inode, cred, fattr, sattr, state, NULL, label);
David Quigleyaa9c2662013-05-22 12:50:44 -04003010 if (status == 0) {
Trond Myklebust65e43082005-08-16 11:49:44 -04003011 nfs_setattr_update_inode(inode, sattr);
David Quigleyaa9c2662013-05-22 12:50:44 -04003012 nfs_setsecurity(inode, fattr, label);
3013 }
David Quigley14c43f72013-05-22 12:50:43 -04003014 nfs4_label_free(label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003015 return status;
3016}
3017
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003018static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
3019 const struct qstr *name, struct nfs_fh *fhandle,
David Quigley1775fd32013-05-22 12:50:42 -04003020 struct nfs_fattr *fattr, struct nfs4_label *label)
David Howells2b3de442006-08-22 20:06:09 -04003021{
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003022 struct nfs_server *server = NFS_SERVER(dir);
David Howells2b3de442006-08-22 20:06:09 -04003023 int status;
3024 struct nfs4_lookup_arg args = {
3025 .bitmask = server->attr_bitmask,
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003026 .dir_fh = NFS_FH(dir),
David Howells2b3de442006-08-22 20:06:09 -04003027 .name = name,
3028 };
3029 struct nfs4_lookup_res res = {
3030 .server = server,
3031 .fattr = fattr,
David Quigleyaa9c2662013-05-22 12:50:44 -04003032 .label = label,
David Howells2b3de442006-08-22 20:06:09 -04003033 .fh = fhandle,
3034 };
3035 struct rpc_message msg = {
3036 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
3037 .rpc_argp = &args,
3038 .rpc_resp = &res,
3039 };
3040
David Quigleyaa9c2662013-05-22 12:50:44 -04003041 args.bitmask = nfs4_bitmask(server, label);
3042
David Howells2b3de442006-08-22 20:06:09 -04003043 nfs_fattr_init(fattr);
3044
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 dprintk("NFS call lookup %s\n", name->name);
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003046 status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 dprintk("NFS reply lookup: %d\n", status);
3048 return status;
3049}
3050
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003051static void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr)
Bryan Schumaker7ebb9312011-03-24 17:12:30 +00003052{
Bryan Schumaker7ebb9312011-03-24 17:12:30 +00003053 fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003054 NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_MOUNTPOINT;
Bryan Schumaker7ebb9312011-03-24 17:12:30 +00003055 fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
3056 fattr->nlink = 2;
3057}
3058
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003059static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
3060 struct qstr *name, struct nfs_fh *fhandle,
David Quigley1775fd32013-05-22 12:50:42 -04003061 struct nfs_fattr *fattr, struct nfs4_label *label)
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003062{
3063 struct nfs4_exception exception = { };
3064 struct rpc_clnt *client = *clnt;
3065 int err;
3066 do {
David Quigley1775fd32013-05-22 12:50:42 -04003067 err = _nfs4_proc_lookup(client, dir, name, fhandle, fattr, label);
Trond Myklebust078ea3d2013-08-12 16:45:55 -04003068 trace_nfs4_lookup(dir, name, err);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003069 switch (err) {
3070 case -NFS4ERR_BADNAME:
3071 err = -ENOENT;
3072 goto out;
3073 case -NFS4ERR_MOVED:
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003074 err = nfs4_get_referral(client, dir, name, fattr, fhandle);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003075 goto out;
3076 case -NFS4ERR_WRONGSEC:
3077 err = -EPERM;
3078 if (client != *clnt)
3079 goto out;
3080
3081 client = nfs4_create_sec_client(client, dir, name);
3082 if (IS_ERR(client))
3083 return PTR_ERR(client);
3084
3085 exception.retry = 1;
3086 break;
3087 default:
3088 err = nfs4_handle_exception(NFS_SERVER(dir), err, &exception);
3089 }
3090 } while (exception.retry);
3091
3092out:
3093 if (err == 0)
3094 *clnt = client;
3095 else if (client != *clnt)
3096 rpc_shutdown_client(client);
3097
3098 return err;
3099}
3100
Bryan Schumaker80a16b22012-04-27 13:27:46 -04003101static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
David Quigley1775fd32013-05-22 12:50:42 -04003102 struct nfs_fh *fhandle, struct nfs_fattr *fattr,
3103 struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003104{
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003105 int status;
3106 struct rpc_clnt *client = NFS_CLIENT(dir);
Trond Myklebust0c2e53f2011-10-18 16:11:22 -07003107
David Quigley1775fd32013-05-22 12:50:42 -04003108 status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, label);
Bryan Schumaker72de53e2012-04-27 13:27:40 -04003109 if (client != NFS_CLIENT(dir)) {
3110 rpc_shutdown_client(client);
3111 nfs_fixup_secinfo_attributes(fattr);
3112 }
3113 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114}
3115
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003116struct rpc_clnt *
3117nfs4_proc_lookup_mountpoint(struct inode *dir, struct qstr *name,
3118 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
3119{
3120 int status;
3121 struct rpc_clnt *client = rpc_clone_client(NFS_CLIENT(dir));
3122
David Quigley1775fd32013-05-22 12:50:42 -04003123 status = nfs4_proc_lookup_common(&client, dir, name, fhandle, fattr, NULL);
Bryan Schumakerf05d1472012-04-27 13:27:41 -04003124 if (status < 0) {
3125 rpc_shutdown_client(client);
3126 return ERR_PTR(status);
3127 }
3128 return client;
3129}
3130
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
3132{
Trond Myklebust76b32992007-08-10 17:45:11 -04003133 struct nfs_server *server = NFS_SERVER(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 struct nfs4_accessargs args = {
3135 .fh = NFS_FH(inode),
Trond Myklebusta4980e72012-01-30 15:43:56 -05003136 .bitmask = server->cache_consistency_bitmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003137 };
Trond Myklebust76b32992007-08-10 17:45:11 -04003138 struct nfs4_accessres res = {
3139 .server = server,
Trond Myklebust76b32992007-08-10 17:45:11 -04003140 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003141 struct rpc_message msg = {
3142 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
3143 .rpc_argp = &args,
3144 .rpc_resp = &res,
3145 .rpc_cred = entry->cred,
3146 };
3147 int mode = entry->mask;
David Quigleyaa9c2662013-05-22 12:50:44 -04003148 int status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003149
3150 /*
3151 * Determine which access bits we want to ask for...
3152 */
3153 if (mode & MAY_READ)
3154 args.access |= NFS4_ACCESS_READ;
3155 if (S_ISDIR(inode->i_mode)) {
3156 if (mode & MAY_WRITE)
3157 args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;
3158 if (mode & MAY_EXEC)
3159 args.access |= NFS4_ACCESS_LOOKUP;
3160 } else {
3161 if (mode & MAY_WRITE)
3162 args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;
3163 if (mode & MAY_EXEC)
3164 args.access |= NFS4_ACCESS_EXECUTE;
3165 }
Trond Myklebustc407d412010-04-16 16:22:48 -04003166
3167 res.fattr = nfs_alloc_fattr();
3168 if (res.fattr == NULL)
3169 return -ENOMEM;
3170
Bryan Schumaker7c513052011-03-24 17:12:24 +00003171 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003172 if (!status) {
Weston Andros Adamson6168f622012-09-10 14:00:46 -04003173 nfs_access_set_mask(entry, res.access);
Trond Myklebustc407d412010-04-16 16:22:48 -04003174 nfs_refresh_inode(inode, res.fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003175 }
Trond Myklebustc407d412010-04-16 16:22:48 -04003176 nfs_free_fattr(res.fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003177 return status;
3178}
3179
3180static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
3181{
3182 struct nfs4_exception exception = { };
3183 int err;
3184 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04003185 err = _nfs4_proc_access(inode, entry);
3186 trace_nfs4_access(inode, err);
3187 err = nfs4_handle_exception(NFS_SERVER(inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003188 &exception);
3189 } while (exception.retry);
3190 return err;
3191}
3192
3193/*
3194 * TODO: For the time being, we don't try to get any attributes
3195 * along with any of the zero-copy operations READ, READDIR,
3196 * READLINK, WRITE.
3197 *
3198 * In the case of the first three, we want to put the GETATTR
3199 * after the read-type operation -- this is because it is hard
3200 * to predict the length of a GETATTR response in v4, and thus
3201 * align the READ data correctly. This means that the GETATTR
3202 * may end up partially falling into the page cache, and we should
3203 * shift it into the 'tail' of the xdr_buf before processing.
3204 * To do this efficiently, we need to know the total length
3205 * of data received, which doesn't seem to be available outside
3206 * of the RPC layer.
3207 *
3208 * In the case of WRITE, we also want to put the GETATTR after
3209 * the operation -- in this case because we want to make sure
Trond Myklebust140150d2012-06-05 15:20:25 -04003210 * we get the post-operation mtime and size.
Linus Torvalds1da177e2005-04-16 15:20:36 -07003211 *
3212 * Both of these changes to the XDR layer would in fact be quite
3213 * minor, but I decided to leave them for a subsequent patch.
3214 */
3215static int _nfs4_proc_readlink(struct inode *inode, struct page *page,
3216 unsigned int pgbase, unsigned int pglen)
3217{
3218 struct nfs4_readlink args = {
3219 .fh = NFS_FH(inode),
3220 .pgbase = pgbase,
3221 .pglen = pglen,
3222 .pages = &page,
3223 };
Benny Halevyf50c7002009-04-01 09:21:55 -04003224 struct nfs4_readlink_res res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003225 struct rpc_message msg = {
3226 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK],
3227 .rpc_argp = &args,
Benny Halevyf50c7002009-04-01 09:21:55 -04003228 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003229 };
3230
Bryan Schumaker7c513052011-03-24 17:12:24 +00003231 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 -07003232}
3233
3234static int nfs4_proc_readlink(struct inode *inode, struct page *page,
3235 unsigned int pgbase, unsigned int pglen)
3236{
3237 struct nfs4_exception exception = { };
3238 int err;
3239 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04003240 err = _nfs4_proc_readlink(inode, page, pgbase, pglen);
3241 trace_nfs4_readlink(inode, err);
3242 err = nfs4_handle_exception(NFS_SERVER(inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003243 &exception);
3244 } while (exception.retry);
3245 return err;
3246}
3247
Linus Torvalds1da177e2005-04-16 15:20:36 -07003248/*
Miklos Szeredi8867fe52012-06-05 15:10:19 +02003249 * This is just for mknod. open(O_CREAT) will always do ->open_context().
Linus Torvalds1da177e2005-04-16 15:20:36 -07003250 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003251static int
3252nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
Miklos Szeredi8867fe52012-06-05 15:10:19 +02003253 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003254{
David Quigleyaa9c2662013-05-22 12:50:44 -04003255 struct nfs4_label l, *ilabel = NULL;
Miklos Szeredi8867fe52012-06-05 15:10:19 +02003256 struct nfs_open_context *ctx;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003257 struct nfs4_state *state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003258 int status = 0;
3259
Miklos Szeredi8867fe52012-06-05 15:10:19 +02003260 ctx = alloc_nfs_open_context(dentry, FMODE_READ);
3261 if (IS_ERR(ctx))
3262 return PTR_ERR(ctx);
3263
David Quigleyaa9c2662013-05-22 12:50:44 -04003264 ilabel = nfs4_label_init_security(dir, dentry, sattr, &l);
3265
Aneesh Kumar K.Va8a5da92010-12-09 11:35:14 +00003266 sattr->ia_mode &= ~current_umask();
Trond Myklebust959d9212013-06-28 16:29:51 -04003267 state = nfs4_do_open(dir, ctx, flags, sattr, ilabel);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003268 if (IS_ERR(state)) {
3269 status = PTR_ERR(state);
Trond Myklebustc0204fd2010-09-17 10:56:51 -04003270 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003272out:
David Quigleyaa9c2662013-05-22 12:50:44 -04003273 nfs4_label_release_security(ilabel);
Miklos Szeredi8867fe52012-06-05 15:10:19 +02003274 put_nfs_open_context(ctx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003275 return status;
3276}
3277
3278static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
3279{
Trond Myklebust16e42952005-10-27 22:12:44 -04003280 struct nfs_server *server = NFS_SERVER(dir);
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04003281 struct nfs_removeargs args = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003282 .fh = NFS_FH(dir),
Linus Torvalds26fe5752012-05-10 13:14:12 -07003283 .name = *name,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003284 };
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04003285 struct nfs_removeres res = {
Trond Myklebust16e42952005-10-27 22:12:44 -04003286 .server = server,
Trond Myklebust16e42952005-10-27 22:12:44 -04003287 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003288 struct rpc_message msg = {
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04003289 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
3290 .rpc_argp = &args,
3291 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003292 };
Trond Myklebust778d2812012-04-27 13:48:19 -04003293 int status;
Trond Myklebustd3468902010-04-16 16:22:50 -04003294
Bryan Schumaker7c513052011-03-24 17:12:24 +00003295 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
Trond Myklebust778d2812012-04-27 13:48:19 -04003296 if (status == 0)
Trond Myklebust16e42952005-10-27 22:12:44 -04003297 update_changeattr(dir, &res.cinfo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003298 return status;
3299}
3300
3301static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
3302{
3303 struct nfs4_exception exception = { };
3304 int err;
3305 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04003306 err = _nfs4_proc_remove(dir, name);
3307 trace_nfs4_remove(dir, name, err);
3308 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003309 &exception);
3310 } while (exception.retry);
3311 return err;
3312}
3313
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04003314static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003315{
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04003316 struct nfs_server *server = NFS_SERVER(dir);
3317 struct nfs_removeargs *args = msg->rpc_argp;
3318 struct nfs_removeres *res = msg->rpc_resp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003319
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04003320 res->server = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003321 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
Chuck Levera9c92d62013-08-09 12:48:18 -04003322 nfs4_init_sequence(&args->seq_args, &res->seq_res, 1);
David Quigleyaa9c2662013-05-22 12:50:44 -04003323
3324 nfs_fattr_init(res->dir_attr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003325}
3326
Bryan Schumaker34e137c2012-03-19 14:54:41 -04003327static void nfs4_proc_unlink_rpc_prepare(struct rpc_task *task, struct nfs_unlinkdata *data)
3328{
Trond Myklebustd9afbd12012-10-22 20:28:44 -04003329 nfs4_setup_sequence(NFS_SERVER(data->dir),
3330 &data->args.seq_args,
3331 &data->res.seq_res,
3332 task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003333}
3334
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04003335static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003336{
Trond Myklebust078ea3d2013-08-12 16:45:55 -04003337 struct nfs_unlinkdata *data = task->tk_calldata;
3338 struct nfs_removeres *res = &data->res;
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04003339
Trond Myklebust14516c32010-07-31 14:29:06 -04003340 if (!nfs4_sequence_done(task, &res->seq_res))
3341 return 0;
Trond Myklebust9e33bed2008-12-23 15:21:46 -05003342 if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04003343 return 0;
3344 update_changeattr(dir, &res->cinfo);
Trond Myklebuste4eff1a2007-07-14 15:39:58 -04003345 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003346}
3347
Jeff Laytond3d41522010-09-17 17:31:57 -04003348static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
3349{
3350 struct nfs_server *server = NFS_SERVER(dir);
3351 struct nfs_renameargs *arg = msg->rpc_argp;
3352 struct nfs_renameres *res = msg->rpc_resp;
3353
3354 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
Jeff Laytond3d41522010-09-17 17:31:57 -04003355 res->server = server;
Chuck Levera9c92d62013-08-09 12:48:18 -04003356 nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1);
Jeff Laytond3d41522010-09-17 17:31:57 -04003357}
3358
Bryan Schumakerc6bfa1a2012-03-19 14:54:42 -04003359static void nfs4_proc_rename_rpc_prepare(struct rpc_task *task, struct nfs_renamedata *data)
3360{
Trond Myklebustd9afbd12012-10-22 20:28:44 -04003361 nfs4_setup_sequence(NFS_SERVER(data->old_dir),
3362 &data->args.seq_args,
3363 &data->res.seq_res,
3364 task);
Jeff Laytond3d41522010-09-17 17:31:57 -04003365}
3366
3367static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
3368 struct inode *new_dir)
3369{
Trond Myklebustfbc6f7c2013-08-12 17:08:26 -04003370 struct nfs_renamedata *data = task->tk_calldata;
3371 struct nfs_renameres *res = &data->res;
Jeff Laytond3d41522010-09-17 17:31:57 -04003372
3373 if (!nfs4_sequence_done(task, &res->seq_res))
3374 return 0;
3375 if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
3376 return 0;
3377
3378 update_changeattr(old_dir, &res->old_cinfo);
Jeff Laytond3d41522010-09-17 17:31:57 -04003379 update_changeattr(new_dir, &res->new_cinfo);
Jeff Laytond3d41522010-09-17 17:31:57 -04003380 return 1;
3381}
3382
Linus Torvalds1da177e2005-04-16 15:20:36 -07003383static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
3384 struct inode *new_dir, struct qstr *new_name)
3385{
Trond Myklebust6caf2c82005-10-27 22:12:43 -04003386 struct nfs_server *server = NFS_SERVER(old_dir);
Jeff Layton920769f2010-09-17 17:30:25 -04003387 struct nfs_renameargs arg = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003388 .old_dir = NFS_FH(old_dir),
3389 .new_dir = NFS_FH(new_dir),
3390 .old_name = old_name,
3391 .new_name = new_name,
3392 };
Jeff Laytone8582a82010-09-17 17:31:06 -04003393 struct nfs_renameres res = {
Trond Myklebust6caf2c82005-10-27 22:12:43 -04003394 .server = server,
Trond Myklebust6caf2c82005-10-27 22:12:43 -04003395 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003396 struct rpc_message msg = {
3397 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME],
3398 .rpc_argp = &arg,
3399 .rpc_resp = &res,
3400 };
Trond Myklebust011fff72010-04-16 16:22:49 -04003401 int status = -ENOMEM;
David Quigley14c43f72013-05-22 12:50:43 -04003402
Bryan Schumaker7c513052011-03-24 17:12:24 +00003403 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003404 if (!status) {
3405 update_changeattr(old_dir, &res.old_cinfo);
3406 update_changeattr(new_dir, &res.new_cinfo);
3407 }
3408 return status;
3409}
3410
3411static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
3412 struct inode *new_dir, struct qstr *new_name)
3413{
3414 struct nfs4_exception exception = { };
3415 int err;
3416 do {
Trond Myklebustfbc6f7c2013-08-12 17:08:26 -04003417 err = _nfs4_proc_rename(old_dir, old_name,
3418 new_dir, new_name);
3419 trace_nfs4_rename(old_dir, old_name, new_dir, new_name, err);
3420 err = nfs4_handle_exception(NFS_SERVER(old_dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003421 &exception);
3422 } while (exception.retry);
3423 return err;
3424}
3425
3426static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
3427{
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04003428 struct nfs_server *server = NFS_SERVER(inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003429 struct nfs4_link_arg arg = {
3430 .fh = NFS_FH(inode),
3431 .dir_fh = NFS_FH(dir),
3432 .name = name,
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04003433 .bitmask = server->attr_bitmask,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003434 };
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04003435 struct nfs4_link_res res = {
3436 .server = server,
David Quigley1775fd32013-05-22 12:50:42 -04003437 .label = NULL,
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04003438 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003439 struct rpc_message msg = {
3440 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
3441 .rpc_argp = &arg,
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04003442 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003443 };
Trond Myklebust136f2622010-04-16 16:22:49 -04003444 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003445
Trond Myklebust136f2622010-04-16 16:22:49 -04003446 res.fattr = nfs_alloc_fattr();
Trond Myklebust778d2812012-04-27 13:48:19 -04003447 if (res.fattr == NULL)
Trond Myklebust136f2622010-04-16 16:22:49 -04003448 goto out;
3449
David Quigley14c43f72013-05-22 12:50:43 -04003450 res.label = nfs4_label_alloc(server, GFP_KERNEL);
3451 if (IS_ERR(res.label)) {
3452 status = PTR_ERR(res.label);
3453 goto out;
3454 }
David Quigleyaa9c2662013-05-22 12:50:44 -04003455 arg.bitmask = nfs4_bitmask(server, res.label);
David Quigley14c43f72013-05-22 12:50:43 -04003456
Bryan Schumaker7c513052011-03-24 17:12:24 +00003457 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04003458 if (!status) {
3459 update_changeattr(dir, &res.cinfo);
David Quigleyaa9c2662013-05-22 12:50:44 -04003460 status = nfs_post_op_update_inode(inode, res.fattr);
3461 if (!status)
3462 nfs_setsecurity(inode, res.fattr, res.label);
Trond Myklebust91ba2ee2005-10-27 22:12:42 -04003463 }
David Quigley14c43f72013-05-22 12:50:43 -04003464
3465
3466 nfs4_label_free(res.label);
3467
Trond Myklebust136f2622010-04-16 16:22:49 -04003468out:
Trond Myklebust136f2622010-04-16 16:22:49 -04003469 nfs_free_fattr(res.fattr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003470 return status;
3471}
3472
3473static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
3474{
3475 struct nfs4_exception exception = { };
3476 int err;
3477 do {
3478 err = nfs4_handle_exception(NFS_SERVER(inode),
3479 _nfs4_proc_link(inode, dir, name),
3480 &exception);
3481 } while (exception.retry);
3482 return err;
3483}
3484
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003485struct nfs4_createdata {
3486 struct rpc_message msg;
3487 struct nfs4_create_arg arg;
3488 struct nfs4_create_res res;
3489 struct nfs_fh fh;
3490 struct nfs_fattr fattr;
David Quigley1775fd32013-05-22 12:50:42 -04003491 struct nfs4_label *label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003492};
3493
3494static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
3495 struct qstr *name, struct iattr *sattr, u32 ftype)
3496{
3497 struct nfs4_createdata *data;
3498
3499 data = kzalloc(sizeof(*data), GFP_KERNEL);
3500 if (data != NULL) {
3501 struct nfs_server *server = NFS_SERVER(dir);
3502
David Quigley14c43f72013-05-22 12:50:43 -04003503 data->label = nfs4_label_alloc(server, GFP_KERNEL);
3504 if (IS_ERR(data->label))
3505 goto out_free;
3506
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003507 data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
3508 data->msg.rpc_argp = &data->arg;
3509 data->msg.rpc_resp = &data->res;
3510 data->arg.dir_fh = NFS_FH(dir);
3511 data->arg.server = server;
3512 data->arg.name = name;
3513 data->arg.attrs = sattr;
3514 data->arg.ftype = ftype;
David Quigleyaa9c2662013-05-22 12:50:44 -04003515 data->arg.bitmask = nfs4_bitmask(server, data->label);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003516 data->res.server = server;
3517 data->res.fh = &data->fh;
3518 data->res.fattr = &data->fattr;
David Quigley1775fd32013-05-22 12:50:42 -04003519 data->res.label = data->label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003520 nfs_fattr_init(data->res.fattr);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003521 }
3522 return data;
David Quigley14c43f72013-05-22 12:50:43 -04003523out_free:
3524 kfree(data);
3525 return NULL;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003526}
3527
3528static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
3529{
Bryan Schumaker7c513052011-03-24 17:12:24 +00003530 int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
Bryan Schumakere73b83f2011-03-24 17:12:23 +00003531 &data->arg.seq_args, &data->res.seq_res, 1);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003532 if (status == 0) {
3533 update_changeattr(dir, &data->res.dir_cinfo);
David Quigley1775fd32013-05-22 12:50:42 -04003534 status = nfs_instantiate(dentry, data->res.fh, data->res.fattr, data->res.label);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003535 }
3536 return status;
3537}
3538
3539static void nfs4_free_createdata(struct nfs4_createdata *data)
3540{
David Quigley14c43f72013-05-22 12:50:43 -04003541 nfs4_label_free(data->label);
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003542 kfree(data);
3543}
3544
Chuck Lever4f390c12006-08-22 20:06:22 -04003545static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
David Quigley1775fd32013-05-22 12:50:42 -04003546 struct page *page, unsigned int len, struct iattr *sattr,
3547 struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003548{
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003549 struct nfs4_createdata *data;
3550 int status = -ENAMETOOLONG;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003551
Chuck Lever94a6d752006-08-22 20:06:23 -04003552 if (len > NFS4_MAXPATHLEN)
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003553 goto out;
Chuck Lever4f390c12006-08-22 20:06:22 -04003554
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003555 status = -ENOMEM;
3556 data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4LNK);
3557 if (data == NULL)
3558 goto out;
3559
3560 data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
3561 data->arg.u.symlink.pages = &page;
3562 data->arg.u.symlink.len = len;
David Quigley1775fd32013-05-22 12:50:42 -04003563 data->arg.label = label;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003564
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003565 status = nfs4_do_create(dir, dentry, data);
3566
3567 nfs4_free_createdata(data);
3568out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003569 return status;
3570}
3571
Chuck Lever4f390c12006-08-22 20:06:22 -04003572static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
Chuck Lever94a6d752006-08-22 20:06:23 -04003573 struct page *page, unsigned int len, struct iattr *sattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003574{
3575 struct nfs4_exception exception = { };
David Quigleyaa9c2662013-05-22 12:50:44 -04003576 struct nfs4_label l, *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003577 int err;
David Quigleyaa9c2662013-05-22 12:50:44 -04003578
3579 label = nfs4_label_init_security(dir, dentry, sattr, &l);
3580
Linus Torvalds1da177e2005-04-16 15:20:36 -07003581 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04003582 err = _nfs4_proc_symlink(dir, dentry, page, len, sattr, label);
3583 trace_nfs4_symlink(dir, &dentry->d_name, err);
3584 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003585 &exception);
3586 } while (exception.retry);
David Quigleyaa9c2662013-05-22 12:50:44 -04003587
3588 nfs4_label_release_security(label);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003589 return err;
3590}
3591
3592static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
David Quigley1775fd32013-05-22 12:50:42 -04003593 struct iattr *sattr, struct nfs4_label *label)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003594{
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003595 struct nfs4_createdata *data;
3596 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003597
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003598 data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR);
3599 if (data == NULL)
3600 goto out;
3601
David Quigley1775fd32013-05-22 12:50:42 -04003602 data->arg.label = label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003603 status = nfs4_do_create(dir, dentry, data);
3604
3605 nfs4_free_createdata(data);
3606out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607 return status;
3608}
3609
3610static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
3611 struct iattr *sattr)
3612{
3613 struct nfs4_exception exception = { };
David Quigleyaa9c2662013-05-22 12:50:44 -04003614 struct nfs4_label l, *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003615 int err;
Aneesh Kumar K.Va8a5da92010-12-09 11:35:14 +00003616
David Quigleyaa9c2662013-05-22 12:50:44 -04003617 label = nfs4_label_init_security(dir, dentry, sattr, &l);
3618
Aneesh Kumar K.Va8a5da92010-12-09 11:35:14 +00003619 sattr->ia_mode &= ~current_umask();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003620 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04003621 err = _nfs4_proc_mkdir(dir, dentry, sattr, label);
3622 trace_nfs4_mkdir(dir, &dentry->d_name, err);
3623 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003624 &exception);
3625 } while (exception.retry);
David Quigleyaa9c2662013-05-22 12:50:44 -04003626 nfs4_label_release_security(label);
3627
Linus Torvalds1da177e2005-04-16 15:20:36 -07003628 return err;
3629}
3630
3631static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
Bryan Schumaker56e4ebf2010-10-20 15:44:37 -04003632 u64 cookie, struct page **pages, unsigned int count, int plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003633{
3634 struct inode *dir = dentry->d_inode;
3635 struct nfs4_readdir_arg args = {
3636 .fh = NFS_FH(dir),
Bryan Schumaker56e4ebf2010-10-20 15:44:37 -04003637 .pages = pages,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003638 .pgbase = 0,
3639 .count = count,
Trond Myklebust96d25e52009-11-11 16:15:42 +09003640 .bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
Bryan Schumaker82f2e542010-10-21 16:33:18 -04003641 .plus = plus,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003642 };
3643 struct nfs4_readdir_res res;
3644 struct rpc_message msg = {
3645 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
3646 .rpc_argp = &args,
3647 .rpc_resp = &res,
3648 .rpc_cred = cred,
3649 };
3650 int status;
3651
Harvey Harrison3110ff82008-05-02 13:42:44 -07003652 dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __func__,
Trond Myklebusteadf4592005-06-22 17:16:39 +00003653 dentry->d_parent->d_name.name,
3654 dentry->d_name.name,
3655 (unsigned long long)cookie);
Trond Myklebustc3f52af2012-09-03 14:56:02 -04003656 nfs4_setup_readdir(cookie, NFS_I(dir)->cookieverf, dentry, &args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003657 res.pgbase = args.pgbase;
Bryan Schumaker7c513052011-03-24 17:12:24 +00003658 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 -05003659 if (status >= 0) {
Trond Myklebustc3f52af2012-09-03 14:56:02 -04003660 memcpy(NFS_I(dir)->cookieverf, res.verifier.data, NFS4_VERIFIER_SIZE);
Trond Myklebustac396122010-11-15 20:26:22 -05003661 status += args.pgbase;
3662 }
Trond Myklebustc4812992007-09-28 17:11:45 -04003663
3664 nfs_invalidate_atime(dir);
3665
Harvey Harrison3110ff82008-05-02 13:42:44 -07003666 dprintk("%s: returns %d\n", __func__, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003667 return status;
3668}
3669
3670static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
Bryan Schumaker56e4ebf2010-10-20 15:44:37 -04003671 u64 cookie, struct page **pages, unsigned int count, int plus)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003672{
3673 struct nfs4_exception exception = { };
3674 int err;
3675 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04003676 err = _nfs4_proc_readdir(dentry, cred, cookie,
3677 pages, count, plus);
3678 trace_nfs4_readdir(dentry->d_inode, err);
3679 err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003680 &exception);
3681 } while (exception.retry);
3682 return err;
3683}
3684
3685static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
David Quigleyaa9c2662013-05-22 12:50:44 -04003686 struct iattr *sattr, struct nfs4_label *label, dev_t rdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003687{
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003688 struct nfs4_createdata *data;
3689 int mode = sattr->ia_mode;
3690 int status = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003691
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003692 data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK);
3693 if (data == NULL)
3694 goto out;
3695
Linus Torvalds1da177e2005-04-16 15:20:36 -07003696 if (S_ISFIFO(mode))
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003697 data->arg.ftype = NF4FIFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003698 else if (S_ISBLK(mode)) {
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003699 data->arg.ftype = NF4BLK;
3700 data->arg.u.device.specdata1 = MAJOR(rdev);
3701 data->arg.u.device.specdata2 = MINOR(rdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003702 }
3703 else if (S_ISCHR(mode)) {
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003704 data->arg.ftype = NF4CHR;
3705 data->arg.u.device.specdata1 = MAJOR(rdev);
3706 data->arg.u.device.specdata2 = MINOR(rdev);
Trond Myklebust4ea8fed2012-10-15 15:47:41 -04003707 } else if (!S_ISSOCK(mode)) {
3708 status = -EINVAL;
3709 goto out_free;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003710 }
David Quigley1775fd32013-05-22 12:50:42 -04003711
David Quigleyaa9c2662013-05-22 12:50:44 -04003712 data->arg.label = label;
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003713 status = nfs4_do_create(dir, dentry, data);
Trond Myklebust4ea8fed2012-10-15 15:47:41 -04003714out_free:
Trond Myklebust57dc9a52008-06-20 15:35:32 -04003715 nfs4_free_createdata(data);
3716out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003717 return status;
3718}
3719
3720static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
3721 struct iattr *sattr, dev_t rdev)
3722{
3723 struct nfs4_exception exception = { };
David Quigleyaa9c2662013-05-22 12:50:44 -04003724 struct nfs4_label l, *label = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003725 int err;
Aneesh Kumar K.Va8a5da92010-12-09 11:35:14 +00003726
David Quigleyaa9c2662013-05-22 12:50:44 -04003727 label = nfs4_label_init_security(dir, dentry, sattr, &l);
3728
Aneesh Kumar K.Va8a5da92010-12-09 11:35:14 +00003729 sattr->ia_mode &= ~current_umask();
Linus Torvalds1da177e2005-04-16 15:20:36 -07003730 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04003731 err = _nfs4_proc_mknod(dir, dentry, sattr, label, rdev);
3732 trace_nfs4_mknod(dir, &dentry->d_name, err);
3733 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003734 &exception);
3735 } while (exception.retry);
David Quigleyaa9c2662013-05-22 12:50:44 -04003736
3737 nfs4_label_release_security(label);
3738
Linus Torvalds1da177e2005-04-16 15:20:36 -07003739 return err;
3740}
3741
3742static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
3743 struct nfs_fsstat *fsstat)
3744{
3745 struct nfs4_statfs_arg args = {
3746 .fh = fhandle,
3747 .bitmask = server->attr_bitmask,
3748 };
Benny Halevy24ad1482009-04-01 09:21:56 -04003749 struct nfs4_statfs_res res = {
3750 .fsstat = fsstat,
3751 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003752 struct rpc_message msg = {
3753 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS],
3754 .rpc_argp = &args,
Benny Halevy24ad1482009-04-01 09:21:56 -04003755 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003756 };
3757
Trond Myklebust0e574af2005-10-27 22:12:38 -04003758 nfs_fattr_init(fsstat->fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00003759 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760}
3761
3762static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
3763{
3764 struct nfs4_exception exception = { };
3765 int err;
3766 do {
3767 err = nfs4_handle_exception(server,
3768 _nfs4_proc_statfs(server, fhandle, fsstat),
3769 &exception);
3770 } while (exception.retry);
3771 return err;
3772}
3773
3774static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
3775 struct nfs_fsinfo *fsinfo)
3776{
3777 struct nfs4_fsinfo_arg args = {
3778 .fh = fhandle,
3779 .bitmask = server->attr_bitmask,
3780 };
Benny Halevy3dda5e42009-04-01 09:21:57 -04003781 struct nfs4_fsinfo_res res = {
3782 .fsinfo = fsinfo,
3783 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003784 struct rpc_message msg = {
3785 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO],
3786 .rpc_argp = &args,
Benny Halevy3dda5e42009-04-01 09:21:57 -04003787 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003788 };
3789
Bryan Schumaker7c513052011-03-24 17:12:24 +00003790 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003791}
3792
3793static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
3794{
3795 struct nfs4_exception exception = { };
Chuck Lever83ca7f52013-03-16 15:55:53 -04003796 unsigned long now = jiffies;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003797 int err;
3798
3799 do {
Chuck Lever83ca7f52013-03-16 15:55:53 -04003800 err = _nfs4_do_fsinfo(server, fhandle, fsinfo);
Trond Myklebustb5f875a2013-08-13 13:01:39 -04003801 trace_nfs4_fsinfo(server, fhandle, fsinfo->fattr, err);
Chuck Lever83ca7f52013-03-16 15:55:53 -04003802 if (err == 0) {
3803 struct nfs_client *clp = server->nfs_client;
3804
3805 spin_lock(&clp->cl_lock);
3806 clp->cl_lease_time = fsinfo->lease_time * HZ;
3807 clp->cl_last_renewal = now;
3808 spin_unlock(&clp->cl_lock);
3809 break;
3810 }
3811 err = nfs4_handle_exception(server, err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003812 } while (exception.retry);
3813 return err;
3814}
3815
3816static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
3817{
Bryan Schumakere38eb652012-06-20 15:53:40 -04003818 int error;
3819
Trond Myklebust0e574af2005-10-27 22:12:38 -04003820 nfs_fattr_init(fsinfo->fattr);
Bryan Schumakere38eb652012-06-20 15:53:40 -04003821 error = nfs4_do_fsinfo(server, fhandle, fsinfo);
Peng Taodc182542012-08-24 00:27:49 +08003822 if (error == 0) {
3823 /* block layout checks this! */
3824 server->pnfs_blksize = fsinfo->blksize;
Bryan Schumakere38eb652012-06-20 15:53:40 -04003825 set_pnfs_layoutdriver(server, fhandle, fsinfo->layouttype);
Peng Taodc182542012-08-24 00:27:49 +08003826 }
Bryan Schumakere38eb652012-06-20 15:53:40 -04003827
3828 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829}
3830
3831static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
3832 struct nfs_pathconf *pathconf)
3833{
3834 struct nfs4_pathconf_arg args = {
3835 .fh = fhandle,
3836 .bitmask = server->attr_bitmask,
3837 };
Benny Halevyd45b2982009-04-01 09:21:58 -04003838 struct nfs4_pathconf_res res = {
3839 .pathconf = pathconf,
3840 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 struct rpc_message msg = {
3842 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF],
3843 .rpc_argp = &args,
Benny Halevyd45b2982009-04-01 09:21:58 -04003844 .rpc_resp = &res,
Linus Torvalds1da177e2005-04-16 15:20:36 -07003845 };
3846
3847 /* None of the pathconf attributes are mandatory to implement */
3848 if ((args.bitmask[0] & nfs4_pathconf_bitmap[0]) == 0) {
3849 memset(pathconf, 0, sizeof(*pathconf));
3850 return 0;
3851 }
3852
Trond Myklebust0e574af2005-10-27 22:12:38 -04003853 nfs_fattr_init(pathconf->fattr);
Bryan Schumaker7c513052011-03-24 17:12:24 +00003854 return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003855}
3856
3857static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
3858 struct nfs_pathconf *pathconf)
3859{
3860 struct nfs4_exception exception = { };
3861 int err;
3862
3863 do {
3864 err = nfs4_handle_exception(server,
3865 _nfs4_proc_pathconf(server, fhandle, pathconf),
3866 &exception);
3867 } while (exception.retry);
3868 return err;
3869}
3870
Trond Myklebust5521abf2013-03-16 20:54:34 -04003871int nfs4_set_rw_stateid(nfs4_stateid *stateid,
Trond Myklebust9b206142013-03-17 15:52:00 -04003872 const struct nfs_open_context *ctx,
3873 const struct nfs_lock_context *l_ctx,
3874 fmode_t fmode)
3875{
3876 const struct nfs_lockowner *lockowner = NULL;
3877
3878 if (l_ctx != NULL)
3879 lockowner = &l_ctx->lockowner;
Trond Myklebust5521abf2013-03-16 20:54:34 -04003880 return nfs4_select_rw_stateid(stateid, ctx->state, fmode, lockowner);
Trond Myklebust9b206142013-03-17 15:52:00 -04003881}
3882EXPORT_SYMBOL_GPL(nfs4_set_rw_stateid);
3883
Trond Myklebust5521abf2013-03-16 20:54:34 -04003884static bool nfs4_stateid_is_current(nfs4_stateid *stateid,
3885 const struct nfs_open_context *ctx,
3886 const struct nfs_lock_context *l_ctx,
3887 fmode_t fmode)
3888{
3889 nfs4_stateid current_stateid;
3890
3891 if (nfs4_set_rw_stateid(&current_stateid, ctx, l_ctx, fmode))
3892 return false;
3893 return nfs4_stateid_match(stateid, &current_stateid);
3894}
3895
3896static bool nfs4_error_stateid_expired(int err)
3897{
3898 switch (err) {
3899 case -NFS4ERR_DELEG_REVOKED:
3900 case -NFS4ERR_ADMIN_REVOKED:
3901 case -NFS4ERR_BAD_STATEID:
3902 case -NFS4ERR_STALE_STATEID:
3903 case -NFS4ERR_OLD_STATEID:
3904 case -NFS4ERR_OPENMODE:
3905 case -NFS4ERR_EXPIRED:
3906 return true;
3907 }
3908 return false;
3909}
3910
Benny Halevyd20581a2011-05-22 19:52:03 +03003911void __nfs4_read_done_cb(struct nfs_read_data *data)
3912{
Fred Isamancd841602012-04-20 14:47:44 -04003913 nfs_invalidate_atime(data->header->inode);
Benny Halevyd20581a2011-05-22 19:52:03 +03003914}
3915
Andy Adamsoncbdabc7f2011-03-01 01:34:20 +00003916static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003917{
Fred Isamancd841602012-04-20 14:47:44 -04003918 struct nfs_server *server = NFS_SERVER(data->header->inode);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003919
Trond Myklebustcc668ab2013-08-14 15:31:28 -04003920 trace_nfs4_read(data, task->tk_status);
Trond Myklebust9e33bed2008-12-23 15:21:46 -05003921 if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
Trond Myklebustd00c5d42011-10-19 12:17:29 -07003922 rpc_restart_call_prepare(task);
Trond Myklebustec06c092006-03-20 13:44:27 -05003923 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003924 }
Trond Myklebust8850df92007-09-28 17:20:07 -04003925
Benny Halevyd20581a2011-05-22 19:52:03 +03003926 __nfs4_read_done_cb(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003927 if (task->tk_status > 0)
Trond Myklebustec06c092006-03-20 13:44:27 -05003928 renew_lease(server, data->timestamp);
3929 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003930}
3931
Trond Myklebust5521abf2013-03-16 20:54:34 -04003932static bool nfs4_read_stateid_changed(struct rpc_task *task,
3933 struct nfs_readargs *args)
3934{
3935
3936 if (!nfs4_error_stateid_expired(task->tk_status) ||
3937 nfs4_stateid_is_current(&args->stateid,
3938 args->context,
3939 args->lock_context,
3940 FMODE_READ))
3941 return false;
3942 rpc_restart_call_prepare(task);
3943 return true;
3944}
3945
Andy Adamsoncbdabc7f2011-03-01 01:34:20 +00003946static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
3947{
3948
3949 dprintk("--> %s\n", __func__);
3950
3951 if (!nfs4_sequence_done(task, &data->res.seq_res))
3952 return -EAGAIN;
Trond Myklebust5521abf2013-03-16 20:54:34 -04003953 if (nfs4_read_stateid_changed(task, &data->args))
3954 return -EAGAIN;
Benny Halevyd20581a2011-05-22 19:52:03 +03003955 return data->read_done_cb ? data->read_done_cb(task, data) :
3956 nfs4_read_done_cb(task, data);
Andy Adamsoncbdabc7f2011-03-01 01:34:20 +00003957}
3958
Trond Myklebustbdc7f022007-07-14 15:40:00 -04003959static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960{
Linus Torvalds1da177e2005-04-16 15:20:36 -07003961 data->timestamp = jiffies;
Andy Adamsoncbdabc7f2011-03-01 01:34:20 +00003962 data->read_done_cb = nfs4_read_done_cb;
Trond Myklebustbdc7f022007-07-14 15:40:00 -04003963 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
Chuck Levera9c92d62013-08-09 12:48:18 -04003964 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003965}
3966
Bryan Schumakerea7c3302012-03-19 14:54:40 -04003967static void nfs4_proc_read_rpc_prepare(struct rpc_task *task, struct nfs_read_data *data)
3968{
Trond Myklebust9b206142013-03-17 15:52:00 -04003969 if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
Trond Myklebustd9afbd12012-10-22 20:28:44 -04003970 &data->args.seq_args,
3971 &data->res.seq_res,
Trond Myklebust9b206142013-03-17 15:52:00 -04003972 task))
3973 return;
3974 nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
3975 data->args.lock_context, FMODE_READ);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003976}
3977
Fred Isamanb029bc92011-03-03 15:13:42 +00003978static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003979{
Fred Isamancd841602012-04-20 14:47:44 -04003980 struct inode *inode = data->header->inode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003981
Trond Myklebustcc668ab2013-08-14 15:31:28 -04003982 trace_nfs4_write(data, task->tk_status);
Trond Myklebust9e33bed2008-12-23 15:21:46 -05003983 if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
Trond Myklebustd00c5d42011-10-19 12:17:29 -07003984 rpc_restart_call_prepare(task);
Trond Myklebust788e7a82006-03-20 13:44:27 -05003985 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003986 }
Trond Myklebust4f9838c2005-10-27 22:12:44 -04003987 if (task->tk_status >= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 renew_lease(NFS_SERVER(inode), data->timestamp);
Trond Myklebust5a37f852012-04-28 14:55:16 -04003989 nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
Trond Myklebust4f9838c2005-10-27 22:12:44 -04003990 }
Trond Myklebust788e7a82006-03-20 13:44:27 -05003991 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003992}
3993
Trond Myklebust5521abf2013-03-16 20:54:34 -04003994static bool nfs4_write_stateid_changed(struct rpc_task *task,
3995 struct nfs_writeargs *args)
3996{
3997
3998 if (!nfs4_error_stateid_expired(task->tk_status) ||
3999 nfs4_stateid_is_current(&args->stateid,
4000 args->context,
4001 args->lock_context,
4002 FMODE_WRITE))
4003 return false;
4004 rpc_restart_call_prepare(task);
4005 return true;
4006}
4007
Fred Isamanb029bc92011-03-03 15:13:42 +00004008static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
4009{
4010 if (!nfs4_sequence_done(task, &data->res.seq_res))
4011 return -EAGAIN;
Trond Myklebust5521abf2013-03-16 20:54:34 -04004012 if (nfs4_write_stateid_changed(task, &data->args))
4013 return -EAGAIN;
Benny Halevyd20581a2011-05-22 19:52:03 +03004014 return data->write_done_cb ? data->write_done_cb(task, data) :
4015 nfs4_write_done_cb(task, data);
Fred Isamanb029bc92011-03-03 15:13:42 +00004016}
4017
Trond Myklebust5a37f852012-04-28 14:55:16 -04004018static
4019bool nfs4_write_need_cache_consistency_data(const struct nfs_write_data *data)
Fred Isamana69aef12011-03-03 15:13:47 +00004020{
Trond Myklebust5a37f852012-04-28 14:55:16 -04004021 const struct nfs_pgio_header *hdr = data->header;
4022
4023 /* Don't request attributes for pNFS or O_DIRECT writes */
4024 if (data->ds_clp != NULL || hdr->dreq != NULL)
4025 return false;
4026 /* Otherwise, request attributes if and only if we don't hold
4027 * a delegation
4028 */
Bryan Schumaker011e2a72012-06-20 15:53:43 -04004029 return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0;
Fred Isamana69aef12011-03-03 15:13:47 +00004030}
Fred Isamana69aef12011-03-03 15:13:47 +00004031
Trond Myklebustbdc7f022007-07-14 15:40:00 -04004032static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033{
Fred Isamancd841602012-04-20 14:47:44 -04004034 struct nfs_server *server = NFS_SERVER(data->header->inode);
Trond Myklebustbdc7f022007-07-14 15:40:00 -04004035
Trond Myklebust5a37f852012-04-28 14:55:16 -04004036 if (!nfs4_write_need_cache_consistency_data(data)) {
Fred Isaman7ffd1062011-03-03 15:13:46 +00004037 data->args.bitmask = NULL;
4038 data->res.fattr = NULL;
4039 } else
4040 data->args.bitmask = server->cache_consistency_bitmask;
Trond Myklebust5a37f852012-04-28 14:55:16 -04004041
Fred Isamanb029bc92011-03-03 15:13:42 +00004042 if (!data->write_done_cb)
4043 data->write_done_cb = nfs4_write_done_cb;
Trond Myklebust4f9838c2005-10-27 22:12:44 -04004044 data->res.server = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 data->timestamp = jiffies;
4046
Trond Myklebustbdc7f022007-07-14 15:40:00 -04004047 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
Chuck Levera9c92d62013-08-09 12:48:18 -04004048 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004049}
4050
Bryan Schumakerc6cb80d2012-03-19 14:54:39 -04004051static void nfs4_proc_write_rpc_prepare(struct rpc_task *task, struct nfs_write_data *data)
4052{
Trond Myklebust9b206142013-03-17 15:52:00 -04004053 if (nfs4_setup_sequence(NFS_SERVER(data->header->inode),
Trond Myklebustd9afbd12012-10-22 20:28:44 -04004054 &data->args.seq_args,
4055 &data->res.seq_res,
Trond Myklebust9b206142013-03-17 15:52:00 -04004056 task))
4057 return;
4058 nfs4_set_rw_stateid(&data->args.stateid, data->args.context,
4059 data->args.lock_context, FMODE_WRITE);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004060}
4061
Fred Isaman0b7c0152012-04-20 14:47:39 -04004062static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data)
4063{
Trond Myklebustd9afbd12012-10-22 20:28:44 -04004064 nfs4_setup_sequence(NFS_SERVER(data->inode),
4065 &data->args.seq_args,
4066 &data->res.seq_res,
4067 task);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068}
4069
Fred Isaman0b7c0152012-04-20 14:47:39 -04004070static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004071{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004072 struct inode *inode = data->inode;
Trond Myklebust14516c32010-07-31 14:29:06 -04004073
Trond Myklebustcc668ab2013-08-14 15:31:28 -04004074 trace_nfs4_commit(data, task->tk_status);
Trond Myklebust9e33bed2008-12-23 15:21:46 -05004075 if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
Trond Myklebustd00c5d42011-10-19 12:17:29 -07004076 rpc_restart_call_prepare(task);
Trond Myklebust788e7a82006-03-20 13:44:27 -05004077 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004078 }
Trond Myklebust788e7a82006-03-20 13:44:27 -05004079 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080}
4081
Fred Isaman0b7c0152012-04-20 14:47:39 -04004082static int nfs4_commit_done(struct rpc_task *task, struct nfs_commit_data *data)
Fred Isaman5f452432011-03-23 13:27:46 +00004083{
4084 if (!nfs4_sequence_done(task, &data->res.seq_res))
4085 return -EAGAIN;
Fred Isaman0b7c0152012-04-20 14:47:39 -04004086 return data->commit_done_cb(task, data);
Fred Isaman5f452432011-03-23 13:27:46 +00004087}
4088
Fred Isaman0b7c0152012-04-20 14:47:39 -04004089static void nfs4_proc_commit_setup(struct nfs_commit_data *data, struct rpc_message *msg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004090{
Trond Myklebust788e7a82006-03-20 13:44:27 -05004091 struct nfs_server *server = NFS_SERVER(data->inode);
Fred Isaman988b6dc2011-03-23 13:27:52 +00004092
Fred Isaman0b7c0152012-04-20 14:47:39 -04004093 if (data->commit_done_cb == NULL)
4094 data->commit_done_cb = nfs4_commit_done_cb;
Trond Myklebust4f9838c2005-10-27 22:12:44 -04004095 data->res.server = server;
Trond Myklebustbdc7f022007-07-14 15:40:00 -04004096 msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
Chuck Levera9c92d62013-08-09 12:48:18 -04004097 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098}
4099
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004100struct nfs4_renewdata {
4101 struct nfs_client *client;
4102 unsigned long timestamp;
4103};
4104
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105/*
4106 * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special
4107 * standalone procedure for queueing an asynchronous RENEW.
4108 */
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004109static void nfs4_renew_release(void *calldata)
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08004110{
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004111 struct nfs4_renewdata *data = calldata;
4112 struct nfs_client *clp = data->client;
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08004113
Alexandros Batsakis0851de062010-02-05 03:45:06 -08004114 if (atomic_read(&clp->cl_count) > 1)
4115 nfs4_schedule_state_renewal(clp);
4116 nfs_put_client(clp);
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004117 kfree(data);
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08004118}
4119
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004120static void nfs4_renew_done(struct rpc_task *task, void *calldata)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121{
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004122 struct nfs4_renewdata *data = calldata;
4123 struct nfs_client *clp = data->client;
4124 unsigned long timestamp = data->timestamp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125
Trond Myklebustc6d01c62013-08-09 11:51:26 -04004126 trace_nfs4_renew_async(clp, task->tk_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 if (task->tk_status < 0) {
Trond Myklebust95baa252009-05-26 14:51:00 -04004128 /* Unless we're shutting down, schedule state recovery! */
Trond Myklebust042b60b2011-08-24 15:07:37 -04004129 if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0)
4130 return;
4131 if (task->tk_status != NFS4ERR_CB_PATH_DOWN) {
Trond Myklebust0400a6b2011-03-09 16:00:53 -05004132 nfs4_schedule_lease_recovery(clp);
Trond Myklebust042b60b2011-08-24 15:07:37 -04004133 return;
4134 }
4135 nfs4_schedule_path_down_recovery(clp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004136 }
Trond Myklebust452e9352010-07-31 14:29:06 -04004137 do_renew_lease(clp, timestamp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138}
4139
Trond Myklebust963d8fe2006-01-03 09:55:04 +01004140static const struct rpc_call_ops nfs4_renew_ops = {
4141 .rpc_call_done = nfs4_renew_done,
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08004142 .rpc_release = nfs4_renew_release,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01004143};
4144
Trond Myklebust2f60ea62011-08-24 15:07:37 -04004145static int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146{
4147 struct rpc_message msg = {
4148 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
4149 .rpc_argp = clp,
Trond Myklebustb4454fe2006-01-03 09:55:25 +01004150 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004151 };
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004152 struct nfs4_renewdata *data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004153
Trond Myklebust2f60ea62011-08-24 15:07:37 -04004154 if (renew_flags == 0)
4155 return 0;
Alexandros Batsakis0851de062010-02-05 03:45:06 -08004156 if (!atomic_inc_not_zero(&clp->cl_count))
4157 return -EIO;
Trond Myklebustb569ad32011-08-24 15:07:35 -04004158 data = kmalloc(sizeof(*data), GFP_NOFS);
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004159 if (data == NULL)
4160 return -ENOMEM;
4161 data->client = clp;
4162 data->timestamp = jiffies;
Trond Myklebustbc7a05c2013-04-08 17:50:28 -04004163 return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT,
Chuck Lever9bc4e3c2010-05-07 13:34:17 -04004164 &nfs4_renew_ops, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004165}
4166
Trond Myklebust8534d4e2011-08-24 15:07:37 -04004167static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168{
4169 struct rpc_message msg = {
4170 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
4171 .rpc_argp = clp,
Trond Myklebustb4454fe2006-01-03 09:55:25 +01004172 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 };
4174 unsigned long now = jiffies;
4175 int status;
4176
Trond Myklebustbc7a05c2013-04-08 17:50:28 -04004177 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004178 if (status < 0)
4179 return status;
Trond Myklebust452e9352010-07-31 14:29:06 -04004180 do_renew_lease(clp, now);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004181 return 0;
4182}
4183
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004184static inline int nfs4_server_supports_acls(struct nfs_server *server)
4185{
4186 return (server->caps & NFS_CAP_ACLS)
4187 && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
4188 && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
4189}
4190
Trond Myklebust21f498c2012-08-24 10:59:25 -04004191/* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
4192 * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_SIZE) bytes on
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004193 * the stack.
4194 */
Trond Myklebust21f498c2012-08-24 10:59:25 -04004195#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004196
Neil Hormane9e3d722011-03-04 19:26:03 -05004197static int buf_to_pages_noslab(const void *buf, size_t buflen,
4198 struct page **pages, unsigned int *pgbase)
4199{
4200 struct page *newpage, **spages;
4201 int rc = 0;
4202 size_t len;
4203 spages = pages;
4204
4205 do {
Trond Myklebust21f498c2012-08-24 10:59:25 -04004206 len = min_t(size_t, PAGE_SIZE, buflen);
Neil Hormane9e3d722011-03-04 19:26:03 -05004207 newpage = alloc_page(GFP_KERNEL);
4208
4209 if (newpage == NULL)
4210 goto unwind;
4211 memcpy(page_address(newpage), buf, len);
4212 buf += len;
4213 buflen -= len;
4214 *pages++ = newpage;
4215 rc++;
4216 } while (buflen != 0);
4217
4218 return rc;
4219
4220unwind:
4221 for(; rc > 0; rc--)
4222 __free_page(spages[rc-1]);
4223 return -ENOMEM;
4224}
4225
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004226struct nfs4_cached_acl {
4227 int cached;
4228 size_t len;
Andrew Morton3e9d4152005-06-22 17:16:28 +00004229 char data[0];
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004230};
4231
4232static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl)
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004233{
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004234 struct nfs_inode *nfsi = NFS_I(inode);
4235
4236 spin_lock(&inode->i_lock);
4237 kfree(nfsi->nfs4_acl);
4238 nfsi->nfs4_acl = acl;
4239 spin_unlock(&inode->i_lock);
4240}
4241
4242static void nfs4_zap_acl_attr(struct inode *inode)
4243{
4244 nfs4_set_cached_acl(inode, NULL);
4245}
4246
4247static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen)
4248{
4249 struct nfs_inode *nfsi = NFS_I(inode);
4250 struct nfs4_cached_acl *acl;
4251 int ret = -ENOENT;
4252
4253 spin_lock(&inode->i_lock);
4254 acl = nfsi->nfs4_acl;
4255 if (acl == NULL)
4256 goto out;
4257 if (buf == NULL) /* user is just asking for length */
4258 goto out_len;
4259 if (acl->cached == 0)
4260 goto out;
4261 ret = -ERANGE; /* see getxattr(2) man page */
4262 if (acl->len > buflen)
4263 goto out;
4264 memcpy(buf, acl->data, acl->len);
4265out_len:
4266 ret = acl->len;
4267out:
4268 spin_unlock(&inode->i_lock);
4269 return ret;
4270}
4271
Sachin Prabhu5794d212012-04-17 14:36:40 +01004272static 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 +00004273{
4274 struct nfs4_cached_acl *acl;
Trond Myklebustb291f1b2012-08-14 18:30:41 -04004275 size_t buflen = sizeof(*acl) + acl_len;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004276
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07004277 if (buflen <= PAGE_SIZE) {
Trond Myklebustb291f1b2012-08-14 18:30:41 -04004278 acl = kmalloc(buflen, GFP_KERNEL);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004279 if (acl == NULL)
4280 goto out;
4281 acl->cached = 1;
Sachin Prabhu5794d212012-04-17 14:36:40 +01004282 _copy_from_pages(acl->data, pages, pgbase, acl_len);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004283 } else {
4284 acl = kmalloc(sizeof(*acl), GFP_KERNEL);
4285 if (acl == NULL)
4286 goto out;
4287 acl->cached = 0;
4288 }
4289 acl->len = acl_len;
4290out:
4291 nfs4_set_cached_acl(inode, acl);
4292}
4293
Andy Adamsonbf118a32011-12-07 11:55:27 -05004294/*
4295 * The getxattr API returns the required buffer length when called with a
4296 * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating
4297 * the required buf. On a NULL buf, we send a page of data to the server
4298 * guessing that the ACL request can be serviced by a page. If so, we cache
4299 * up to the page of ACL data, and the 2nd call to getxattr is serviced by
4300 * the cache. If not so, we throw away the page, and cache the required
4301 * length. The next getxattr call will then produce another round trip to
4302 * the server, this time with the input buf of the required size.
4303 */
Trond Myklebust16b4289c2006-08-24 12:27:15 -04004304static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004305{
Andy Adamsonbf118a32011-12-07 11:55:27 -05004306 struct page *pages[NFS4ACL_MAXPAGES] = {NULL, };
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004307 struct nfs_getaclargs args = {
4308 .fh = NFS_FH(inode),
4309 .acl_pages = pages,
4310 .acl_len = buflen,
4311 };
Benny Halevy663c79b2009-04-01 09:21:59 -04004312 struct nfs_getaclres res = {
4313 .acl_len = buflen,
4314 };
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004315 struct rpc_message msg = {
4316 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],
4317 .rpc_argp = &args,
Benny Halevy663c79b2009-04-01 09:21:59 -04004318 .rpc_resp = &res,
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004319 };
Trond Myklebust21f498c2012-08-24 10:59:25 -04004320 unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
4321 int ret = -ENOMEM, i;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004322
Andy Adamsonbf118a32011-12-07 11:55:27 -05004323 /* As long as we're doing a round trip to the server anyway,
4324 * let's be prepared for a page of acl data. */
4325 if (npages == 0)
4326 npages = 1;
Trond Myklebust21f498c2012-08-24 10:59:25 -04004327 if (npages > ARRAY_SIZE(pages))
4328 return -ERANGE;
Sachin Prabhu5a006892012-04-17 14:35:39 +01004329
Andy Adamsonbf118a32011-12-07 11:55:27 -05004330 for (i = 0; i < npages; i++) {
4331 pages[i] = alloc_page(GFP_KERNEL);
4332 if (!pages[i])
4333 goto out_free;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004334 }
Sachin Prabhu5a006892012-04-17 14:35:39 +01004335
4336 /* for decoding across pages */
4337 res.acl_scratch = alloc_page(GFP_KERNEL);
4338 if (!res.acl_scratch)
4339 goto out_free;
4340
Andy Adamsonbf118a32011-12-07 11:55:27 -05004341 args.acl_len = npages * PAGE_SIZE;
4342 args.acl_pgbase = 0;
Sachin Prabhu5a006892012-04-17 14:35:39 +01004343
Peng Taode040be2012-01-10 22:42:47 +08004344 dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n",
Andy Adamsonbf118a32011-12-07 11:55:27 -05004345 __func__, buf, buflen, npages, args.acl_len);
4346 ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
4347 &msg, &args.seq_args, &res.seq_res, 0);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004348 if (ret)
4349 goto out_free;
Andy Adamsonbf118a32011-12-07 11:55:27 -05004350
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07004351 /* Handle the case where the passed-in buffer is too short */
4352 if (res.acl_flags & NFS4_ACL_TRUNC) {
4353 /* Did the user only issue a request for the acl length? */
4354 if (buf == NULL)
4355 goto out_ok;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004356 ret = -ERANGE;
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07004357 goto out_free;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004358 }
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07004359 nfs4_write_cached_acl(inode, pages, res.acl_data_offset, res.acl_len);
Sven Wegener7d3e91a2012-12-08 15:30:18 +01004360 if (buf) {
4361 if (res.acl_len > buflen) {
4362 ret = -ERANGE;
4363 goto out_free;
4364 }
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07004365 _copy_from_pages(buf, pages, res.acl_data_offset, res.acl_len);
Sven Wegener7d3e91a2012-12-08 15:30:18 +01004366 }
Trond Myklebust1f1ea6c2012-08-26 11:44:43 -07004367out_ok:
4368 ret = res.acl_len;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004369out_free:
Andy Adamsonbf118a32011-12-07 11:55:27 -05004370 for (i = 0; i < npages; i++)
4371 if (pages[i])
4372 __free_page(pages[i]);
Trond Myklebust331818f2012-02-03 18:30:53 -05004373 if (res.acl_scratch)
4374 __free_page(res.acl_scratch);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004375 return ret;
4376}
4377
Trond Myklebust16b4289c2006-08-24 12:27:15 -04004378static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
4379{
4380 struct nfs4_exception exception = { };
4381 ssize_t ret;
4382 do {
4383 ret = __nfs4_get_acl_uncached(inode, buf, buflen);
Trond Myklebustc1578b72013-08-12 16:58:42 -04004384 trace_nfs4_get_acl(inode, ret);
Trond Myklebust16b4289c2006-08-24 12:27:15 -04004385 if (ret >= 0)
4386 break;
4387 ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
4388 } while (exception.retry);
4389 return ret;
4390}
4391
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004392static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
4393{
4394 struct nfs_server *server = NFS_SERVER(inode);
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004395 int ret;
4396
4397 if (!nfs4_server_supports_acls(server))
4398 return -EOPNOTSUPP;
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004399 ret = nfs_revalidate_inode(server, inode);
4400 if (ret < 0)
4401 return ret;
Aneesh Kumar K.V08a22b32010-12-01 10:42:16 +00004402 if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
4403 nfs_zap_acl_cache(inode);
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004404 ret = nfs4_read_cached_acl(inode, buf, buflen);
4405 if (ret != -ENOENT)
Andy Adamsonbf118a32011-12-07 11:55:27 -05004406 /* -ENOENT is returned if there is no ACL or if there is an ACL
4407 * but no cached acl data, just the acl length */
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00004408 return ret;
4409 return nfs4_get_acl_uncached(inode, buf, buflen);
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00004410}
4411
Trond Myklebust16b4289c2006-08-24 12:27:15 -04004412static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00004413{
4414 struct nfs_server *server = NFS_SERVER(inode);
4415 struct page *pages[NFS4ACL_MAXPAGES];
4416 struct nfs_setaclargs arg = {
4417 .fh = NFS_FH(inode),
4418 .acl_pages = pages,
4419 .acl_len = buflen,
4420 };
Benny Halevy73c403a2009-04-01 09:22:01 -04004421 struct nfs_setaclres res;
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00004422 struct rpc_message msg = {
4423 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL],
4424 .rpc_argp = &arg,
Benny Halevy73c403a2009-04-01 09:22:01 -04004425 .rpc_resp = &res,
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00004426 };
Trond Myklebust21f498c2012-08-24 10:59:25 -04004427 unsigned int npages = DIV_ROUND_UP(buflen, PAGE_SIZE);
Neil Hormane9e3d722011-03-04 19:26:03 -05004428 int ret, i;
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00004429
4430 if (!nfs4_server_supports_acls(server))
4431 return -EOPNOTSUPP;
Trond Myklebust21f498c2012-08-24 10:59:25 -04004432 if (npages > ARRAY_SIZE(pages))
4433 return -ERANGE;
Neil Hormane9e3d722011-03-04 19:26:03 -05004434 i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
4435 if (i < 0)
4436 return i;
Bryan Schumaker57ec14c2012-06-20 15:53:44 -04004437 nfs4_inode_return_delegation(inode);
Bryan Schumaker7c513052011-03-24 17:12:24 +00004438 ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Neil Hormane9e3d722011-03-04 19:26:03 -05004439
4440 /*
4441 * Free each page after tx, so the only ref left is
4442 * held by the network stack
4443 */
4444 for (; i > 0; i--)
4445 put_page(pages[i-1]);
4446
Aneesh Kumar K.V08a22b32010-12-01 10:42:16 +00004447 /*
4448 * Acl update can result in inode attribute update.
4449 * so mark the attribute cache invalid.
4450 */
4451 spin_lock(&inode->i_lock);
4452 NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
4453 spin_unlock(&inode->i_lock);
Trond Myklebustf41f7412008-06-11 17:39:04 -04004454 nfs_access_zap_cache(inode);
4455 nfs_zap_acl_cache(inode);
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00004456 return ret;
4457}
4458
Trond Myklebust16b4289c2006-08-24 12:27:15 -04004459static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
4460{
4461 struct nfs4_exception exception = { };
4462 int err;
4463 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04004464 err = __nfs4_proc_set_acl(inode, buf, buflen);
4465 trace_nfs4_set_acl(inode, err);
4466 err = nfs4_handle_exception(NFS_SERVER(inode), err,
Trond Myklebust16b4289c2006-08-24 12:27:15 -04004467 &exception);
4468 } while (exception.retry);
4469 return err;
4470}
4471
David Quigleyaa9c2662013-05-22 12:50:44 -04004472#ifdef CONFIG_NFS_V4_SECURITY_LABEL
4473static int _nfs4_get_security_label(struct inode *inode, void *buf,
4474 size_t buflen)
4475{
4476 struct nfs_server *server = NFS_SERVER(inode);
4477 struct nfs_fattr fattr;
4478 struct nfs4_label label = {0, 0, buflen, buf};
4479
4480 u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
4481 struct nfs4_getattr_arg args = {
4482 .fh = NFS_FH(inode),
4483 .bitmask = bitmask,
4484 };
4485 struct nfs4_getattr_res res = {
4486 .fattr = &fattr,
4487 .label = &label,
4488 .server = server,
4489 };
4490 struct rpc_message msg = {
4491 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
4492 .rpc_argp = &args,
4493 .rpc_resp = &res,
4494 };
4495 int ret;
4496
4497 nfs_fattr_init(&fattr);
4498
4499 ret = rpc_call_sync(server->client, &msg, 0);
4500 if (ret)
4501 return ret;
4502 if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))
4503 return -ENOENT;
4504 if (buflen < label.len)
4505 return -ERANGE;
4506 return 0;
4507}
4508
4509static int nfs4_get_security_label(struct inode *inode, void *buf,
4510 size_t buflen)
4511{
4512 struct nfs4_exception exception = { };
4513 int err;
4514
4515 if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
4516 return -EOPNOTSUPP;
4517
4518 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04004519 err = _nfs4_get_security_label(inode, buf, buflen);
4520 trace_nfs4_get_security_label(inode, err);
4521 err = nfs4_handle_exception(NFS_SERVER(inode), err,
David Quigleyaa9c2662013-05-22 12:50:44 -04004522 &exception);
4523 } while (exception.retry);
4524 return err;
4525}
4526
4527static int _nfs4_do_set_security_label(struct inode *inode,
4528 struct nfs4_label *ilabel,
4529 struct nfs_fattr *fattr,
4530 struct nfs4_label *olabel)
4531{
4532
4533 struct iattr sattr = {0};
4534 struct nfs_server *server = NFS_SERVER(inode);
4535 const u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
4536 struct nfs_setattrargs args = {
4537 .fh = NFS_FH(inode),
4538 .iap = &sattr,
4539 .server = server,
4540 .bitmask = bitmask,
4541 .label = ilabel,
4542 };
4543 struct nfs_setattrres res = {
4544 .fattr = fattr,
4545 .label = olabel,
4546 .server = server,
4547 };
4548 struct rpc_message msg = {
4549 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
4550 .rpc_argp = &args,
4551 .rpc_resp = &res,
4552 };
4553 int status;
4554
4555 nfs4_stateid_copy(&args.stateid, &zero_stateid);
4556
4557 status = rpc_call_sync(server->client, &msg, 0);
4558 if (status)
4559 dprintk("%s failed: %d\n", __func__, status);
4560
4561 return status;
4562}
4563
4564static int nfs4_do_set_security_label(struct inode *inode,
4565 struct nfs4_label *ilabel,
4566 struct nfs_fattr *fattr,
4567 struct nfs4_label *olabel)
4568{
4569 struct nfs4_exception exception = { };
4570 int err;
4571
4572 do {
Trond Myklebustc1578b72013-08-12 16:58:42 -04004573 err = _nfs4_do_set_security_label(inode, ilabel,
4574 fattr, olabel);
4575 trace_nfs4_set_security_label(inode, err);
4576 err = nfs4_handle_exception(NFS_SERVER(inode), err,
David Quigleyaa9c2662013-05-22 12:50:44 -04004577 &exception);
4578 } while (exception.retry);
4579 return err;
4580}
4581
4582static int
4583nfs4_set_security_label(struct dentry *dentry, const void *buf, size_t buflen)
4584{
4585 struct nfs4_label ilabel, *olabel = NULL;
4586 struct nfs_fattr fattr;
4587 struct rpc_cred *cred;
4588 struct inode *inode = dentry->d_inode;
4589 int status;
4590
4591 if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
4592 return -EOPNOTSUPP;
4593
4594 nfs_fattr_init(&fattr);
4595
4596 ilabel.pi = 0;
4597 ilabel.lfs = 0;
4598 ilabel.label = (char *)buf;
4599 ilabel.len = buflen;
4600
4601 cred = rpc_lookup_cred();
4602 if (IS_ERR(cred))
4603 return PTR_ERR(cred);
4604
4605 olabel = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
4606 if (IS_ERR(olabel)) {
4607 status = -PTR_ERR(olabel);
4608 goto out;
4609 }
4610
4611 status = nfs4_do_set_security_label(inode, &ilabel, &fattr, olabel);
4612 if (status == 0)
4613 nfs_setsecurity(inode, &fattr, olabel);
4614
4615 nfs4_label_free(olabel);
4616out:
4617 put_rpccred(cred);
4618 return status;
4619}
4620#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
4621
4622
Linus Torvalds1da177e2005-04-16 15:20:36 -07004623static int
Trond Myklebustaa5190d2010-06-16 09:52:25 -04004624nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625{
Trond Myklebustaa5190d2010-06-16 09:52:25 -04004626 struct nfs_client *clp = server->nfs_client;
4627
4628 if (task->tk_status >= 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 return 0;
4630 switch(task->tk_status) {
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -05004631 case -NFS4ERR_DELEG_REVOKED:
Trond Myklebust9e33bed2008-12-23 15:21:46 -05004632 case -NFS4ERR_ADMIN_REVOKED:
4633 case -NFS4ERR_BAD_STATEID:
Trond Myklebust14977482012-03-27 18:31:25 -04004634 if (state == NULL)
4635 break;
4636 nfs_remove_bad_delegation(state->inode);
Trond Myklebust9e33bed2008-12-23 15:21:46 -05004637 case -NFS4ERR_OPENMODE:
4638 if (state == NULL)
4639 break;
Trond Myklebust5d422302013-03-14 16:57:48 -04004640 if (nfs4_schedule_stateid_recovery(server, state) < 0)
4641 goto stateid_invalid;
Trond Myklebust0400a6b2011-03-09 16:00:53 -05004642 goto wait_on_recovery;
Trond Myklebust0ced63d2011-05-26 14:26:35 -04004643 case -NFS4ERR_EXPIRED:
Trond Myklebust5d422302013-03-14 16:57:48 -04004644 if (state != NULL) {
4645 if (nfs4_schedule_stateid_recovery(server, state) < 0)
4646 goto stateid_invalid;
4647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004648 case -NFS4ERR_STALE_STATEID:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -05004649 case -NFS4ERR_STALE_CLIENTID:
Trond Myklebust0400a6b2011-03-09 16:00:53 -05004650 nfs4_schedule_lease_recovery(clp);
4651 goto wait_on_recovery;
Andy Adamson4745e312009-04-01 09:22:42 -04004652#if defined(CONFIG_NFS_V4_1)
4653 case -NFS4ERR_BADSESSION:
4654 case -NFS4ERR_BADSLOT:
4655 case -NFS4ERR_BAD_HIGH_SLOT:
4656 case -NFS4ERR_DEADSESSION:
4657 case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
4658 case -NFS4ERR_SEQ_FALSE_RETRY:
4659 case -NFS4ERR_SEQ_MISORDERED:
4660 dprintk("%s ERROR %d, Reset session\n", __func__,
4661 task->tk_status);
Trond Myklebust9f594792012-05-27 13:02:53 -04004662 nfs4_schedule_session_recovery(clp->cl_session, task->tk_status);
Andy Adamson4745e312009-04-01 09:22:42 -04004663 task->tk_status = 0;
4664 return -EAGAIN;
4665#endif /* CONFIG_NFS_V4_1 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004666 case -NFS4ERR_DELAY:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04004667 nfs_inc_server_stats(server, NFSIOS_DELAY);
Chuck Lever006ea732006-03-20 13:44:14 -05004668 case -NFS4ERR_GRACE:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 rpc_delay(task, NFS4_POLL_RETRY_MAX);
4670 task->tk_status = 0;
4671 return -EAGAIN;
Andy Adamsona8a4ae32011-05-03 13:43:03 -04004672 case -NFS4ERR_RETRY_UNCACHED_REP:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673 case -NFS4ERR_OLD_STATEID:
4674 task->tk_status = 0;
4675 return -EAGAIN;
4676 }
4677 task->tk_status = nfs4_map_errors(task->tk_status);
4678 return 0;
Trond Myklebust5d422302013-03-14 16:57:48 -04004679stateid_invalid:
4680 task->tk_status = -EIO;
4681 return 0;
Trond Myklebust0400a6b2011-03-09 16:00:53 -05004682wait_on_recovery:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -05004683 rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -05004684 if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
4685 rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
4686 task->tk_status = 0;
4687 return -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004688}
4689
Chuck Leverf0920752012-05-21 22:45:41 -04004690static void nfs4_init_boot_verifier(const struct nfs_client *clp,
4691 nfs4_verifier *bootverf)
Chuck Levercd937102012-03-02 17:14:31 -05004692{
4693 __be32 verf[2];
4694
Chuck Lever2c820d92012-05-21 22:45:33 -04004695 if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
4696 /* An impossible timestamp guarantees this value
4697 * will never match a generated boot time. */
4698 verf[0] = 0;
Trond Myklebust17f26b12013-08-21 15:48:42 -04004699 verf[1] = cpu_to_be32(NSEC_PER_SEC + 1);
Chuck Lever2c820d92012-05-21 22:45:33 -04004700 } else {
Chuck Leverf0920752012-05-21 22:45:41 -04004701 struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
Trond Myklebust17f26b12013-08-21 15:48:42 -04004702 verf[0] = cpu_to_be32(nn->boot_time.tv_sec);
4703 verf[1] = cpu_to_be32(nn->boot_time.tv_nsec);
Chuck Lever2c820d92012-05-21 22:45:33 -04004704 }
Chuck Levercd937102012-03-02 17:14:31 -05004705 memcpy(bootverf->data, verf, sizeof(bootverf->data));
4706}
4707
Chuck Levere984a552012-09-14 17:24:21 -04004708static unsigned int
4709nfs4_init_nonuniform_client_string(const struct nfs_client *clp,
4710 char *buf, size_t len)
4711{
4712 unsigned int result;
4713
4714 rcu_read_lock();
4715 result = scnprintf(buf, len, "Linux NFSv4.0 %s/%s %s",
4716 clp->cl_ipaddr,
4717 rpc_peeraddr2str(clp->cl_rpcclient,
4718 RPC_DISPLAY_ADDR),
4719 rpc_peeraddr2str(clp->cl_rpcclient,
4720 RPC_DISPLAY_PROTO));
4721 rcu_read_unlock();
4722 return result;
4723}
4724
4725static unsigned int
4726nfs4_init_uniform_client_string(const struct nfs_client *clp,
4727 char *buf, size_t len)
4728{
Trond Myklebust55b59292013-07-24 16:36:35 -04004729 const char *nodename = clp->cl_rpcclient->cl_nodename;
Chuck Lever6f2ea7f2012-09-14 17:24:41 -04004730
4731 if (nfs4_client_id_uniquifier[0] != '\0')
Trond Myklebust55b59292013-07-24 16:36:35 -04004732 return scnprintf(buf, len, "Linux NFSv%u.%u %s/%s",
4733 clp->rpc_ops->version,
4734 clp->cl_minorversion,
4735 nfs4_client_id_uniquifier,
4736 nodename);
Chuck Levere984a552012-09-14 17:24:21 -04004737 return scnprintf(buf, len, "Linux NFSv%u.%u %s",
4738 clp->rpc_ops->version, clp->cl_minorversion,
Chuck Lever6f2ea7f2012-09-14 17:24:41 -04004739 nodename);
Chuck Levere984a552012-09-14 17:24:21 -04004740}
4741
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04004742/**
4743 * nfs4_proc_setclientid - Negotiate client ID
4744 * @clp: state data structure
4745 * @program: RPC program for NFSv4 callback service
4746 * @port: IP port number for NFS4 callback service
4747 * @cred: RPC credential to use for this call
4748 * @res: where to place the result
4749 *
4750 * Returns zero, a negative errno, or a negative NFS4ERR status code.
4751 */
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04004752int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
4753 unsigned short port, struct rpc_cred *cred,
4754 struct nfs4_setclientid_res *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755{
4756 nfs4_verifier sc_verifier;
4757 struct nfs4_setclientid setclientid = {
4758 .sc_verifier = &sc_verifier,
4759 .sc_prog = program,
Andy Adamsonf4eecd52011-01-06 02:04:30 +00004760 .sc_cb_ident = clp->cl_cb_ident,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761 };
4762 struct rpc_message msg = {
4763 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
4764 .rpc_argp = &setclientid,
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04004765 .rpc_resp = res,
Trond Myklebust286d7d62006-01-03 09:55:26 +01004766 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767 };
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04004768 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769
Chuck Leverde734832012-07-11 16:30:50 -04004770 /* nfs_client_id4 */
Chuck Leverf0920752012-05-21 22:45:41 -04004771 nfs4_init_boot_verifier(clp, &sc_verifier);
Chuck Levere984a552012-09-14 17:24:21 -04004772 if (test_bit(NFS_CS_MIGRATION, &clp->cl_flags))
4773 setclientid.sc_name_len =
4774 nfs4_init_uniform_client_string(clp,
4775 setclientid.sc_name,
4776 sizeof(setclientid.sc_name));
4777 else
4778 setclientid.sc_name_len =
4779 nfs4_init_nonuniform_client_string(clp,
4780 setclientid.sc_name,
4781 sizeof(setclientid.sc_name));
Chuck Leverde734832012-07-11 16:30:50 -04004782 /* cb_client4 */
Chuck Levere984a552012-09-14 17:24:21 -04004783 rcu_read_lock();
Chuck Leverde734832012-07-11 16:30:50 -04004784 setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
Djalal Harounife2d5392013-06-18 17:58:12 +01004785 sizeof(setclientid.sc_netid), "%s",
Chuck Leverd4d3c502007-12-10 14:57:09 -05004786 rpc_peeraddr2str(clp->cl_rpcclient,
4787 RPC_DISPLAY_NETID));
Chuck Leverde734832012-07-11 16:30:50 -04004788 rcu_read_unlock();
4789 setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
Chuck Leverd4d3c502007-12-10 14:57:09 -05004790 sizeof(setclientid.sc_uaddr), "%s.%u.%u",
Linus Torvalds1da177e2005-04-16 15:20:36 -07004791 clp->cl_ipaddr, port >> 8, port & 255);
4792
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04004793 dprintk("NFS call setclientid auth=%s, '%.*s'\n",
4794 clp->cl_rpcclient->cl_auth->au_ops->au_name,
4795 setclientid.sc_name_len, setclientid.sc_name);
4796 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04004797 trace_nfs4_setclientid(clp, status);
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04004798 dprintk("NFS reply setclientid: %d\n", status);
4799 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800}
4801
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04004802/**
4803 * nfs4_proc_setclientid_confirm - Confirm client ID
4804 * @clp: state data structure
4805 * @res: result of a previous SETCLIENTID
4806 * @cred: RPC credential to use for this call
4807 *
4808 * Returns zero, a negative errno, or a negative NFS4ERR status code.
4809 */
Trond Myklebustfd954ae2011-04-24 14:28:18 -04004810int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04004811 struct nfs4_setclientid_res *arg,
4812 struct rpc_cred *cred)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004814 struct rpc_message msg = {
4815 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
Trond Myklebustbb8b27e2010-04-16 16:43:06 -04004816 .rpc_argp = arg,
Trond Myklebust286d7d62006-01-03 09:55:26 +01004817 .rpc_cred = cred,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004819 int status;
4820
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04004821 dprintk("NFS call setclientid_confirm auth=%s, (client ID %llx)\n",
4822 clp->cl_rpcclient->cl_auth->au_ops->au_name,
4823 clp->cl_clientid);
Trond Myklebust1bd714f2011-04-24 14:29:33 -04004824 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04004825 trace_nfs4_setclientid_confirm(clp, status);
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04004826 dprintk("NFS reply setclientid_confirm: %d\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827 return status;
4828}
4829
Trond Myklebustfe650402006-01-03 09:55:18 +01004830struct nfs4_delegreturndata {
4831 struct nfs4_delegreturnargs args;
Trond Myklebustfa178f22006-01-03 09:55:38 +01004832 struct nfs4_delegreturnres res;
Trond Myklebustfe650402006-01-03 09:55:18 +01004833 struct nfs_fh fh;
4834 nfs4_stateid stateid;
Trond Myklebust26e976a2006-01-03 09:55:21 +01004835 unsigned long timestamp;
Trond Myklebustfa178f22006-01-03 09:55:38 +01004836 struct nfs_fattr fattr;
Trond Myklebustfe650402006-01-03 09:55:18 +01004837 int rpc_status;
4838};
4839
Trond Myklebustfe650402006-01-03 09:55:18 +01004840static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
4841{
4842 struct nfs4_delegreturndata *data = calldata;
Andy Adamson938e1012009-04-01 09:22:28 -04004843
Trond Myklebust14516c32010-07-31 14:29:06 -04004844 if (!nfs4_sequence_done(task, &data->res.seq_res))
4845 return;
Andy Adamson938e1012009-04-01 09:22:28 -04004846
Trond Myklebustca8acf82013-08-13 10:36:56 -04004847 trace_nfs4_delegreturn_exit(&data->args, &data->res, task->tk_status);
Ricardo Labiaga79708862009-12-07 09:23:21 -05004848 switch (task->tk_status) {
4849 case -NFS4ERR_STALE_STATEID:
4850 case -NFS4ERR_EXPIRED:
4851 case 0:
Trond Myklebustfa178f22006-01-03 09:55:38 +01004852 renew_lease(data->res.server, data->timestamp);
Ricardo Labiaga79708862009-12-07 09:23:21 -05004853 break;
4854 default:
4855 if (nfs4_async_handle_error(task, data->res.server, NULL) ==
4856 -EAGAIN) {
Trond Myklebustd00c5d42011-10-19 12:17:29 -07004857 rpc_restart_call_prepare(task);
Ricardo Labiaga79708862009-12-07 09:23:21 -05004858 return;
4859 }
4860 }
4861 data->rpc_status = task->tk_status;
Trond Myklebustfe650402006-01-03 09:55:18 +01004862}
4863
4864static void nfs4_delegreturn_release(void *calldata)
4865{
Trond Myklebustfe650402006-01-03 09:55:18 +01004866 kfree(calldata);
4867}
4868
Andy Adamson938e1012009-04-01 09:22:28 -04004869#if defined(CONFIG_NFS_V4_1)
4870static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
4871{
4872 struct nfs4_delegreturndata *d_data;
4873
4874 d_data = (struct nfs4_delegreturndata *)data;
4875
Trond Myklebustd9afbd12012-10-22 20:28:44 -04004876 nfs4_setup_sequence(d_data->res.server,
4877 &d_data->args.seq_args,
4878 &d_data->res.seq_res,
4879 task);
Andy Adamson938e1012009-04-01 09:22:28 -04004880}
4881#endif /* CONFIG_NFS_V4_1 */
4882
Jesper Juhlc8d149f2006-03-20 13:44:07 -05004883static const struct rpc_call_ops nfs4_delegreturn_ops = {
Andy Adamson938e1012009-04-01 09:22:28 -04004884#if defined(CONFIG_NFS_V4_1)
4885 .rpc_call_prepare = nfs4_delegreturn_prepare,
4886#endif /* CONFIG_NFS_V4_1 */
Trond Myklebustfe650402006-01-03 09:55:18 +01004887 .rpc_call_done = nfs4_delegreturn_done,
4888 .rpc_release = nfs4_delegreturn_release,
4889};
4890
Trond Myklebuste6f81072008-01-24 18:14:34 -05004891static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync)
Trond Myklebustfe650402006-01-03 09:55:18 +01004892{
4893 struct nfs4_delegreturndata *data;
Trond Myklebustfa178f22006-01-03 09:55:38 +01004894 struct nfs_server *server = NFS_SERVER(inode);
Trond Myklebustfe650402006-01-03 09:55:18 +01004895 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04004896 struct rpc_message msg = {
4897 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN],
4898 .rpc_cred = cred,
4899 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04004900 struct rpc_task_setup task_setup_data = {
4901 .rpc_client = server->client,
Trond Myklebust5138fde2007-07-14 15:40:01 -04004902 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04004903 .callback_ops = &nfs4_delegreturn_ops,
4904 .flags = RPC_TASK_ASYNC,
4905 };
Trond Myklebuste6f81072008-01-24 18:14:34 -05004906 int status = 0;
Trond Myklebustfe650402006-01-03 09:55:18 +01004907
Trond Myklebust8535b2b2010-05-13 12:51:01 -04004908 data = kzalloc(sizeof(*data), GFP_NOFS);
Trond Myklebustfe650402006-01-03 09:55:18 +01004909 if (data == NULL)
4910 return -ENOMEM;
Chuck Levera9c92d62013-08-09 12:48:18 -04004911 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
Trond Myklebustfe650402006-01-03 09:55:18 +01004912 data->args.fhandle = &data->fh;
4913 data->args.stateid = &data->stateid;
Trond Myklebust9e907fe2012-04-27 13:48:17 -04004914 data->args.bitmask = server->cache_consistency_bitmask;
Trond Myklebustfe650402006-01-03 09:55:18 +01004915 nfs_copy_fh(&data->fh, NFS_FH(inode));
Trond Myklebustf597c532012-03-04 18:13:56 -05004916 nfs4_stateid_copy(&data->stateid, stateid);
Trond Myklebustfa178f22006-01-03 09:55:38 +01004917 data->res.fattr = &data->fattr;
4918 data->res.server = server;
Trond Myklebust5138fde2007-07-14 15:40:01 -04004919 nfs_fattr_init(data->res.fattr);
Trond Myklebust26e976a2006-01-03 09:55:21 +01004920 data->timestamp = jiffies;
Trond Myklebustfe650402006-01-03 09:55:18 +01004921 data->rpc_status = 0;
4922
Trond Myklebustc970aa82007-07-14 15:39:59 -04004923 task_setup_data.callback_data = data;
Trond Myklebust1174dd12010-12-21 10:52:24 -05004924 msg.rpc_argp = &data->args;
4925 msg.rpc_resp = &data->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04004926 task = rpc_run_task(&task_setup_data);
Trond Myklebust7a1218a2006-03-20 18:11:10 -05004927 if (IS_ERR(task))
Trond Myklebustfe650402006-01-03 09:55:18 +01004928 return PTR_ERR(task);
Trond Myklebuste6f81072008-01-24 18:14:34 -05004929 if (!issync)
4930 goto out;
Trond Myklebustfe650402006-01-03 09:55:18 +01004931 status = nfs4_wait_for_completion_rpc_task(task);
Trond Myklebuste6f81072008-01-24 18:14:34 -05004932 if (status != 0)
4933 goto out;
4934 status = data->rpc_status;
Trond Myklebuste144cbc2012-04-28 16:05:03 -04004935 if (status == 0)
4936 nfs_post_op_update_inode_force_wcc(inode, &data->fattr);
4937 else
4938 nfs_refresh_inode(inode, &data->fattr);
Trond Myklebuste6f81072008-01-24 18:14:34 -05004939out:
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05004940 rpc_put_task(task);
Trond Myklebustfe650402006-01-03 09:55:18 +01004941 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004942}
4943
Trond Myklebuste6f81072008-01-24 18:14:34 -05004944int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004945{
4946 struct nfs_server *server = NFS_SERVER(inode);
4947 struct nfs4_exception exception = { };
4948 int err;
4949 do {
Trond Myklebuste6f81072008-01-24 18:14:34 -05004950 err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
Trond Myklebustca8acf82013-08-13 10:36:56 -04004951 trace_nfs4_delegreturn(inode, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004952 switch (err) {
4953 case -NFS4ERR_STALE_STATEID:
4954 case -NFS4ERR_EXPIRED:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004955 case 0:
4956 return 0;
4957 }
4958 err = nfs4_handle_exception(server, err, &exception);
4959 } while (exception.retry);
4960 return err;
4961}
4962
4963#define NFS4_LOCK_MINTIMEOUT (1 * HZ)
4964#define NFS4_LOCK_MAXTIMEOUT (30 * HZ)
4965
4966/*
4967 * sleep, with exponential backoff, and retry the LOCK operation.
4968 */
4969static unsigned long
4970nfs4_set_lock_task_retry(unsigned long timeout)
4971{
Colin Cross416ad3c2013-05-06 23:50:06 +00004972 freezable_schedule_timeout_killable_unsafe(timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004973 timeout <<= 1;
4974 if (timeout > NFS4_LOCK_MAXTIMEOUT)
4975 return NFS4_LOCK_MAXTIMEOUT;
4976 return timeout;
4977}
4978
Linus Torvalds1da177e2005-04-16 15:20:36 -07004979static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
4980{
4981 struct inode *inode = state->inode;
4982 struct nfs_server *server = NFS_SERVER(inode);
David Howells7539bba2006-08-22 20:06:09 -04004983 struct nfs_client *clp = server->nfs_client;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01004984 struct nfs_lockt_args arg = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985 .fh = NFS_FH(inode),
Trond Myklebust911d1aa2006-01-03 09:55:16 +01004986 .fl = request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987 };
Trond Myklebust911d1aa2006-01-03 09:55:16 +01004988 struct nfs_lockt_res res = {
4989 .denied = request,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004990 };
4991 struct rpc_message msg = {
4992 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKT],
4993 .rpc_argp = &arg,
4994 .rpc_resp = &res,
4995 .rpc_cred = state->owner->so_cred,
4996 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07004997 struct nfs4_lock_state *lsp;
4998 int status;
4999
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005000 arg.lock_owner.clientid = clp->cl_clientid;
Trond Myklebust8d0a8a92005-06-22 17:16:32 +00005001 status = nfs4_set_lock_state(state, request);
5002 if (status != 0)
5003 goto out;
5004 lsp = request->fl_u.nfs4_fl.owner;
Trond Myklebust48c22eb2012-01-17 22:04:25 -05005005 arg.lock_owner.id = lsp->ls_seqid.owner_id;
Trond Myklebustd035c362010-12-21 10:45:27 -05005006 arg.lock_owner.s_dev = server->s_dev;
Bryan Schumaker7c513052011-03-24 17:12:24 +00005007 status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005008 switch (status) {
5009 case 0:
5010 request->fl_type = F_UNLCK;
5011 break;
5012 case -NFS4ERR_DENIED:
5013 status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014 }
J. Bruce Fields70cc6482007-02-22 18:48:53 -05005015 request->fl_ops->fl_release_private(request);
Trond Myklebust8d0a8a92005-06-22 17:16:32 +00005016out:
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 return status;
5018}
5019
5020static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
5021{
5022 struct nfs4_exception exception = { };
5023 int err;
5024
5025 do {
Trond Myklebustd1b748a2013-08-12 16:35:20 -04005026 err = _nfs4_proc_getlk(state, cmd, request);
5027 trace_nfs4_get_lock(request, state, cmd, err);
5028 err = nfs4_handle_exception(NFS_SERVER(state->inode), err,
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029 &exception);
5030 } while (exception.retry);
5031 return err;
5032}
5033
5034static int do_vfs_lock(struct file *file, struct file_lock *fl)
5035{
5036 int res = 0;
5037 switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
5038 case FL_POSIX:
5039 res = posix_lock_file_wait(file, fl);
5040 break;
5041 case FL_FLOCK:
5042 res = flock_lock_file_wait(file, fl);
5043 break;
5044 default:
5045 BUG();
5046 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005047 return res;
5048}
5049
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005050struct nfs4_unlockdata {
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005051 struct nfs_locku_args arg;
5052 struct nfs_locku_res res;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005053 struct nfs4_lock_state *lsp;
5054 struct nfs_open_context *ctx;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005055 struct file_lock fl;
5056 const struct nfs_server *server;
Trond Myklebust26e976a2006-01-03 09:55:21 +01005057 unsigned long timestamp;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005058};
5059
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005060static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
5061 struct nfs_open_context *ctx,
5062 struct nfs4_lock_state *lsp,
5063 struct nfs_seqid *seqid)
5064{
5065 struct nfs4_unlockdata *p;
5066 struct inode *inode = lsp->ls_state->inode;
5067
Trond Myklebust8535b2b2010-05-13 12:51:01 -04005068 p = kzalloc(sizeof(*p), GFP_NOFS);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005069 if (p == NULL)
5070 return NULL;
5071 p->arg.fh = NFS_FH(inode);
5072 p->arg.fl = &p->fl;
5073 p->arg.seqid = seqid;
Trond Myklebustc1d51932008-04-07 13:20:54 -04005074 p->res.seqid = seqid;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005075 p->arg.stateid = &lsp->ls_stateid;
5076 p->lsp = lsp;
5077 atomic_inc(&lsp->ls_count);
5078 /* Ensure we don't close file until we're done freeing locks! */
5079 p->ctx = get_nfs_open_context(ctx);
5080 memcpy(&p->fl, fl, sizeof(p->fl));
5081 p->server = NFS_SERVER(inode);
5082 return p;
5083}
5084
Trond Myklebust06f814a2006-01-03 09:55:07 +01005085static void nfs4_locku_release_calldata(void *data)
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005086{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005087 struct nfs4_unlockdata *calldata = data;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005088 nfs_free_seqid(calldata->arg.seqid);
Trond Myklebust06f814a2006-01-03 09:55:07 +01005089 nfs4_put_lock_state(calldata->lsp);
5090 put_nfs_open_context(calldata->ctx);
5091 kfree(calldata);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005092}
5093
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005094static void nfs4_locku_done(struct rpc_task *task, void *data)
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005095{
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005096 struct nfs4_unlockdata *calldata = data;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005097
Trond Myklebust14516c32010-07-31 14:29:06 -04005098 if (!nfs4_sequence_done(task, &calldata->res.seq_res))
5099 return;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005100 switch (task->tk_status) {
5101 case 0:
Trond Myklebustf597c532012-03-04 18:13:56 -05005102 nfs4_stateid_copy(&calldata->lsp->ls_stateid,
5103 &calldata->res.stateid);
Trond Myklebust26e976a2006-01-03 09:55:21 +01005104 renew_lease(calldata->server, calldata->timestamp);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005105 break;
Trond Myklebust9e33bed2008-12-23 15:21:46 -05005106 case -NFS4ERR_BAD_STATEID:
5107 case -NFS4ERR_OLD_STATEID:
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005108 case -NFS4ERR_STALE_STATEID:
5109 case -NFS4ERR_EXPIRED:
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005110 break;
5111 default:
Trond Myklebust9e33bed2008-12-23 15:21:46 -05005112 if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
Trond Myklebustd00c5d42011-10-19 12:17:29 -07005113 rpc_restart_call_prepare(task);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005114 }
Trond Myklebust2b1bc302012-10-29 18:53:23 -04005115 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005116}
5117
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01005118static void nfs4_locku_prepare(struct rpc_task *task, void *data)
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005119{
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01005120 struct nfs4_unlockdata *calldata = data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005121
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005122 if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05005123 goto out_wait;
Trond Myklebust795a88c2012-09-10 13:26:49 -04005124 if (test_bit(NFS_LOCK_INITIALIZED, &calldata->lsp->ls_flags) == 0) {
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005125 /* Note: exit _without_ running nfs4_locku_done */
Trond Myklebustc8da19b2013-02-11 19:01:21 -05005126 goto out_no_action;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005127 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01005128 calldata->timestamp = jiffies;
Trond Myklebust035168a2010-06-16 09:52:26 -04005129 if (nfs4_setup_sequence(calldata->server,
Andy Adamsona8936932009-04-01 09:22:23 -04005130 &calldata->arg.seq_args,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04005131 &calldata->res.seq_res,
5132 task) != 0)
5133 nfs_release_seqid(calldata->arg.seqid);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05005134 return;
5135out_no_action:
5136 task->tk_action = NULL;
5137out_wait:
5138 nfs4_sequence_done(task, &calldata->res.seq_res);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005139}
5140
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005141static const struct rpc_call_ops nfs4_locku_ops = {
Trond Myklebust4ce70ad2006-01-03 09:55:05 +01005142 .rpc_call_prepare = nfs4_locku_prepare,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005143 .rpc_call_done = nfs4_locku_done,
Trond Myklebust06f814a2006-01-03 09:55:07 +01005144 .rpc_release = nfs4_locku_release_calldata,
Trond Myklebust963d8fe2006-01-03 09:55:04 +01005145};
5146
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005147static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
5148 struct nfs_open_context *ctx,
5149 struct nfs4_lock_state *lsp,
5150 struct nfs_seqid *seqid)
5151{
5152 struct nfs4_unlockdata *data;
Trond Myklebust5138fde2007-07-14 15:40:01 -04005153 struct rpc_message msg = {
5154 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU],
5155 .rpc_cred = ctx->cred,
5156 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04005157 struct rpc_task_setup task_setup_data = {
5158 .rpc_client = NFS_CLIENT(lsp->ls_state->inode),
Trond Myklebust5138fde2007-07-14 15:40:01 -04005159 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04005160 .callback_ops = &nfs4_locku_ops,
Trond Myklebust101070c2008-02-19 20:04:23 -05005161 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04005162 .flags = RPC_TASK_ASYNC,
5163 };
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005164
Frank Filz137d6ac2007-07-09 15:32:29 -07005165 /* Ensure this is an unlock - when canceling a lock, the
5166 * canceled lock is passed in, and it won't be an unlock.
5167 */
5168 fl->fl_type = F_UNLCK;
5169
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005170 data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
5171 if (data == NULL) {
5172 nfs_free_seqid(seqid);
5173 return ERR_PTR(-ENOMEM);
5174 }
5175
Chuck Levera9c92d62013-08-09 12:48:18 -04005176 nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
Trond Myklebust1174dd12010-12-21 10:52:24 -05005177 msg.rpc_argp = &data->arg;
5178 msg.rpc_resp = &data->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04005179 task_setup_data.callback_data = data;
5180 return rpc_run_task(&task_setup_data);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005181}
5182
Linus Torvalds1da177e2005-04-16 15:20:36 -07005183static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
5184{
Trond Myklebust65b62a22013-02-07 10:54:07 -05005185 struct inode *inode = state->inode;
5186 struct nfs4_state_owner *sp = state->owner;
5187 struct nfs_inode *nfsi = NFS_I(inode);
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005188 struct nfs_seqid *seqid;
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005189 struct nfs4_lock_state *lsp;
Trond Myklebust06f814a2006-01-03 09:55:07 +01005190 struct rpc_task *task;
5191 int status = 0;
Trond Myklebust536ff0f2008-04-04 15:08:02 -04005192 unsigned char fl_flags = request->fl_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005193
Trond Myklebust9b073572006-06-29 16:38:34 -04005194 status = nfs4_set_lock_state(state, request);
5195 /* Unlock _before_ we do the RPC call */
5196 request->fl_flags |= FL_EXISTS;
Trond Myklebust65b62a22013-02-07 10:54:07 -05005197 /* Exclude nfs_delegation_claim_locks() */
5198 mutex_lock(&sp->so_delegreturn_mutex);
5199 /* Exclude nfs4_reclaim_open_stateid() - note nesting! */
Trond Myklebust19e03c52008-12-23 15:21:44 -05005200 down_read(&nfsi->rwsem);
5201 if (do_vfs_lock(request->fl_file, request) == -ENOENT) {
5202 up_read(&nfsi->rwsem);
Trond Myklebust65b62a22013-02-07 10:54:07 -05005203 mutex_unlock(&sp->so_delegreturn_mutex);
Trond Myklebust9b073572006-06-29 16:38:34 -04005204 goto out;
Trond Myklebust19e03c52008-12-23 15:21:44 -05005205 }
5206 up_read(&nfsi->rwsem);
Trond Myklebust65b62a22013-02-07 10:54:07 -05005207 mutex_unlock(&sp->so_delegreturn_mutex);
Trond Myklebust9b073572006-06-29 16:38:34 -04005208 if (status != 0)
5209 goto out;
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05005210 /* Is this a delegated lock? */
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005211 lsp = request->fl_u.nfs4_fl.owner;
Trond Myklebustc5a2a152013-04-30 12:43:42 -04005212 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) == 0)
5213 goto out;
Trond Myklebust8535b2b2010-05-13 12:51:01 -04005214 seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL);
Trond Myklebust9b073572006-06-29 16:38:34 -04005215 status = -ENOMEM;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005216 if (seqid == NULL)
Trond Myklebust9b073572006-06-29 16:38:34 -04005217 goto out;
Trond Myklebustcd3758e2007-08-10 17:44:32 -04005218 task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005219 status = PTR_ERR(task);
5220 if (IS_ERR(task))
Trond Myklebust9b073572006-06-29 16:38:34 -04005221 goto out;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005222 status = nfs4_wait_for_completion_rpc_task(task);
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05005223 rpc_put_task(task);
Trond Myklebust9b073572006-06-29 16:38:34 -04005224out:
Trond Myklebust536ff0f2008-04-04 15:08:02 -04005225 request->fl_flags = fl_flags;
Trond Myklebustd1b748a2013-08-12 16:35:20 -04005226 trace_nfs4_unlock(request, state, F_SETLK, status);
Trond Myklebustfaf5f492005-10-18 14:20:15 -07005227 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005228}
5229
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005230struct nfs4_lockdata {
5231 struct nfs_lock_args arg;
Trond Myklebust911d1aa2006-01-03 09:55:16 +01005232 struct nfs_lock_res res;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005233 struct nfs4_lock_state *lsp;
5234 struct nfs_open_context *ctx;
5235 struct file_lock fl;
Trond Myklebust26e976a2006-01-03 09:55:21 +01005236 unsigned long timestamp;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005237 int rpc_status;
5238 int cancelled;
Andy Adamson66179ef2009-04-01 09:22:22 -04005239 struct nfs_server *server;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005240};
5241
5242static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
Trond Myklebust8535b2b2010-05-13 12:51:01 -04005243 struct nfs_open_context *ctx, struct nfs4_lock_state *lsp,
5244 gfp_t gfp_mask)
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005245{
5246 struct nfs4_lockdata *p;
5247 struct inode *inode = lsp->ls_state->inode;
5248 struct nfs_server *server = NFS_SERVER(inode);
5249
Trond Myklebust8535b2b2010-05-13 12:51:01 -04005250 p = kzalloc(sizeof(*p), gfp_mask);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005251 if (p == NULL)
5252 return NULL;
5253
5254 p->arg.fh = NFS_FH(inode);
5255 p->arg.fl = &p->fl;
Trond Myklebust8535b2b2010-05-13 12:51:01 -04005256 p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask);
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05005257 if (p->arg.open_seqid == NULL)
5258 goto out_free;
Trond Myklebust8535b2b2010-05-13 12:51:01 -04005259 p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid, gfp_mask);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005260 if (p->arg.lock_seqid == NULL)
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05005261 goto out_free_seqid;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005262 p->arg.lock_stateid = &lsp->ls_stateid;
David Howells7539bba2006-08-22 20:06:09 -04005263 p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
Trond Myklebust48c22eb2012-01-17 22:04:25 -05005264 p->arg.lock_owner.id = lsp->ls_seqid.owner_id;
Trond Myklebustd035c362010-12-21 10:45:27 -05005265 p->arg.lock_owner.s_dev = server->s_dev;
Trond Myklebustc1d51932008-04-07 13:20:54 -04005266 p->res.lock_seqid = p->arg.lock_seqid;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005267 p->lsp = lsp;
Andy Adamson66179ef2009-04-01 09:22:22 -04005268 p->server = server;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005269 atomic_inc(&lsp->ls_count);
5270 p->ctx = get_nfs_open_context(ctx);
5271 memcpy(&p->fl, fl, sizeof(p->fl));
5272 return p;
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05005273out_free_seqid:
5274 nfs_free_seqid(p->arg.open_seqid);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005275out_free:
5276 kfree(p);
5277 return NULL;
5278}
5279
5280static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
5281{
5282 struct nfs4_lockdata *data = calldata;
5283 struct nfs4_state *state = data->lsp->ls_state;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005284
Harvey Harrison3110ff82008-05-02 13:42:44 -07005285 dprintk("%s: begin!\n", __func__);
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05005286 if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
Trond Myklebustc8da19b2013-02-11 19:01:21 -05005287 goto out_wait;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005288 /* Do we need to do an open_to_lock_owner? */
5289 if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04005290 if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0) {
Trond Myklebust2240a9e2012-10-29 18:37:40 -04005291 goto out_release_lock_seqid;
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04005292 }
Trond Myklebust8e472f32013-04-20 01:30:53 -04005293 data->arg.open_stateid = &state->open_stateid;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005294 data->arg.new_lock_owner = 1;
Trond Myklebustc1d51932008-04-07 13:20:54 -04005295 data->res.open_seqid = data->arg.open_seqid;
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05005296 } else
5297 data->arg.new_lock_owner = 0;
Trond Myklebust5d422302013-03-14 16:57:48 -04005298 if (!nfs4_valid_open_stateid(state)) {
5299 data->rpc_status = -EBADF;
5300 task->tk_action = NULL;
5301 goto out_release_open_seqid;
5302 }
Trond Myklebust26e976a2006-01-03 09:55:21 +01005303 data->timestamp = jiffies;
Trond Myklebust035168a2010-06-16 09:52:26 -04005304 if (nfs4_setup_sequence(data->server,
5305 &data->arg.seq_args,
Trond Myklebust2240a9e2012-10-29 18:37:40 -04005306 &data->res.seq_res,
Trond Myklebustd9afbd12012-10-22 20:28:44 -04005307 task) == 0)
Andy Adamson66179ef2009-04-01 09:22:22 -04005308 return;
Trond Myklebust5d422302013-03-14 16:57:48 -04005309out_release_open_seqid:
Trond Myklebust2240a9e2012-10-29 18:37:40 -04005310 nfs_release_seqid(data->arg.open_seqid);
5311out_release_lock_seqid:
5312 nfs_release_seqid(data->arg.lock_seqid);
Trond Myklebustc8da19b2013-02-11 19:01:21 -05005313out_wait:
5314 nfs4_sequence_done(task, &data->res.seq_res);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04005315 dprintk("%s: done!, ret = %d\n", __func__, data->rpc_status);
Alexandros Batsakisb2579572009-12-14 21:27:57 -08005316}
5317
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005318static void nfs4_lock_done(struct rpc_task *task, void *calldata)
5319{
5320 struct nfs4_lockdata *data = calldata;
5321
Harvey Harrison3110ff82008-05-02 13:42:44 -07005322 dprintk("%s: begin!\n", __func__);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005323
Trond Myklebust14516c32010-07-31 14:29:06 -04005324 if (!nfs4_sequence_done(task, &data->res.seq_res))
5325 return;
Andy Adamson66179ef2009-04-01 09:22:22 -04005326
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005327 data->rpc_status = task->tk_status;
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005328 if (data->arg.new_lock_owner != 0) {
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005329 if (data->rpc_status == 0)
5330 nfs_confirm_seqid(&data->lsp->ls_seqid, 0);
5331 else
5332 goto out;
5333 }
5334 if (data->rpc_status == 0) {
Trond Myklebustf597c532012-03-04 18:13:56 -05005335 nfs4_stateid_copy(&data->lsp->ls_stateid, &data->res.stateid);
Trond Myklebust795a88c2012-09-10 13:26:49 -04005336 set_bit(NFS_LOCK_INITIALIZED, &data->lsp->ls_flags);
Al Viro3d4ff432011-06-22 18:40:12 -04005337 renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005338 }
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005339out:
Harvey Harrison3110ff82008-05-02 13:42:44 -07005340 dprintk("%s: done, ret = %d!\n", __func__, data->rpc_status);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005341}
5342
5343static void nfs4_lock_release(void *calldata)
5344{
5345 struct nfs4_lockdata *data = calldata;
5346
Harvey Harrison3110ff82008-05-02 13:42:44 -07005347 dprintk("%s: begin!\n", __func__);
Trond Myklebust2f74c0a2008-01-08 17:56:07 -05005348 nfs_free_seqid(data->arg.open_seqid);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005349 if (data->cancelled != 0) {
5350 struct rpc_task *task;
5351 task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
5352 data->arg.lock_seqid);
5353 if (!IS_ERR(task))
Trond Myklebustbf294b42011-02-21 11:05:41 -08005354 rpc_put_task_async(task);
Harvey Harrison3110ff82008-05-02 13:42:44 -07005355 dprintk("%s: cancelling lock!\n", __func__);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005356 } else
5357 nfs_free_seqid(data->arg.lock_seqid);
5358 nfs4_put_lock_state(data->lsp);
5359 put_nfs_open_context(data->ctx);
5360 kfree(data);
Harvey Harrison3110ff82008-05-02 13:42:44 -07005361 dprintk("%s: done!\n", __func__);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005362}
5363
5364static const struct rpc_call_ops nfs4_lock_ops = {
5365 .rpc_call_prepare = nfs4_lock_prepare,
5366 .rpc_call_done = nfs4_lock_done,
5367 .rpc_release = nfs4_lock_release,
5368};
5369
Trond Myklebust2bee72a2010-01-26 15:42:21 -05005370static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
5371{
Trond Myklebust2bee72a2010-01-26 15:42:21 -05005372 switch (error) {
5373 case -NFS4ERR_ADMIN_REVOKED:
5374 case -NFS4ERR_BAD_STATEID:
Trond Myklebustecac7992011-03-09 16:00:56 -05005375 lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
Trond Myklebust2bee72a2010-01-26 15:42:21 -05005376 if (new_lock_owner != 0 ||
Trond Myklebust795a88c2012-09-10 13:26:49 -04005377 test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0)
Trond Myklebustecac7992011-03-09 16:00:56 -05005378 nfs4_schedule_stateid_recovery(server, lsp->ls_state);
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -05005379 break;
5380 case -NFS4ERR_STALE_STATEID:
Trond Myklebusta2c0b9e2010-01-26 15:42:47 -05005381 lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
Trond Myklebustecac7992011-03-09 16:00:56 -05005382 case -NFS4ERR_EXPIRED:
5383 nfs4_schedule_lease_recovery(server->nfs_client);
Trond Myklebust2bee72a2010-01-26 15:42:21 -05005384 };
5385}
5386
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08005387static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type)
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005388{
5389 struct nfs4_lockdata *data;
5390 struct rpc_task *task;
Trond Myklebust5138fde2007-07-14 15:40:01 -04005391 struct rpc_message msg = {
5392 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK],
5393 .rpc_cred = state->owner->so_cred,
5394 };
Trond Myklebustc970aa82007-07-14 15:39:59 -04005395 struct rpc_task_setup task_setup_data = {
5396 .rpc_client = NFS_CLIENT(state->inode),
Trond Myklebust5138fde2007-07-14 15:40:01 -04005397 .rpc_message = &msg,
Trond Myklebustc970aa82007-07-14 15:39:59 -04005398 .callback_ops = &nfs4_lock_ops,
Trond Myklebust101070c2008-02-19 20:04:23 -05005399 .workqueue = nfsiod_workqueue,
Trond Myklebustc970aa82007-07-14 15:39:59 -04005400 .flags = RPC_TASK_ASYNC,
5401 };
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005402 int ret;
5403
Harvey Harrison3110ff82008-05-02 13:42:44 -07005404 dprintk("%s: begin!\n", __func__);
Trond Myklebustcd3758e2007-08-10 17:44:32 -04005405 data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
Trond Myklebust8535b2b2010-05-13 12:51:01 -04005406 fl->fl_u.nfs4_fl.owner,
5407 recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005408 if (data == NULL)
5409 return -ENOMEM;
5410 if (IS_SETLKW(cmd))
5411 data->arg.block = 1;
Chuck Levera9c92d62013-08-09 12:48:18 -04005412 nfs4_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
Trond Myklebust1174dd12010-12-21 10:52:24 -05005413 msg.rpc_argp = &data->arg;
5414 msg.rpc_resp = &data->res;
Trond Myklebustc970aa82007-07-14 15:39:59 -04005415 task_setup_data.callback_data = data;
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04005416 if (recovery_type > NFS_LOCK_NEW) {
5417 if (recovery_type == NFS_LOCK_RECLAIM)
5418 data->arg.reclaim = NFS_LOCK_RECLAIM;
5419 nfs4_set_sequence_privileged(&data->arg.seq_args);
5420 }
Trond Myklebustc970aa82007-07-14 15:39:59 -04005421 task = rpc_run_task(&task_setup_data);
Trond Myklebust7a1218a2006-03-20 18:11:10 -05005422 if (IS_ERR(task))
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005423 return PTR_ERR(task);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005424 ret = nfs4_wait_for_completion_rpc_task(task);
5425 if (ret == 0) {
5426 ret = data->rpc_status;
Trond Myklebust2bee72a2010-01-26 15:42:21 -05005427 if (ret)
5428 nfs4_handle_setlk_error(data->server, data->lsp,
5429 data->arg.new_lock_owner, ret);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005430 } else
5431 data->cancelled = 1;
Trond Myklebuste6b3c4d2006-11-11 22:18:03 -05005432 rpc_put_task(task);
Harvey Harrison3110ff82008-05-02 13:42:44 -07005433 dprintk("%s: done, ret = %d!\n", __func__, ret);
Trond Myklebusta5d16a42006-01-03 09:55:17 +01005434 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005435}
5436
5437static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
5438{
Trond Myklebust202b50d2005-06-22 17:16:29 +00005439 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust05ffe242012-04-18 12:20:10 -04005440 struct nfs4_exception exception = {
5441 .inode = state->inode,
5442 };
Trond Myklebust202b50d2005-06-22 17:16:29 +00005443 int err;
5444
5445 do {
Trond Myklebust42a2d132006-06-29 16:38:36 -04005446 /* Cache the lock if possible... */
5447 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
5448 return 0;
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08005449 err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
Trond Myklebustd1b748a2013-08-12 16:35:20 -04005450 trace_nfs4_lock_reclaim(request, state, F_SETLK, err);
Trond Myklebust168667c2010-10-19 19:47:49 -04005451 if (err != -NFS4ERR_DELAY)
Trond Myklebust202b50d2005-06-22 17:16:29 +00005452 break;
5453 nfs4_handle_exception(server, err, &exception);
5454 } while (exception.retry);
5455 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456}
5457
5458static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request)
5459{
Trond Myklebust202b50d2005-06-22 17:16:29 +00005460 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust05ffe242012-04-18 12:20:10 -04005461 struct nfs4_exception exception = {
5462 .inode = state->inode,
5463 };
Trond Myklebust202b50d2005-06-22 17:16:29 +00005464 int err;
5465
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05005466 err = nfs4_set_lock_state(state, request);
5467 if (err != 0)
5468 return err;
Trond Myklebust202b50d2005-06-22 17:16:29 +00005469 do {
Trond Myklebust42a2d132006-06-29 16:38:36 -04005470 if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
5471 return 0;
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08005472 err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
Trond Myklebustd1b748a2013-08-12 16:35:20 -04005473 trace_nfs4_lock_expired(request, state, F_SETLK, err);
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05005474 switch (err) {
5475 default:
5476 goto out;
5477 case -NFS4ERR_GRACE:
5478 case -NFS4ERR_DELAY:
5479 nfs4_handle_exception(server, err, &exception);
5480 err = 0;
5481 }
Trond Myklebust202b50d2005-06-22 17:16:29 +00005482 } while (exception.retry);
Trond Myklebusta9ed2e22009-12-03 15:53:21 -05005483out:
Trond Myklebust202b50d2005-06-22 17:16:29 +00005484 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485}
5486
Bryan Schumakerf062eb62011-06-02 14:59:10 -04005487#if defined(CONFIG_NFS_V4_1)
Chuck Lever3e60ffd2012-07-11 16:30:14 -04005488/**
5489 * nfs41_check_expired_locks - possibly free a lock stateid
5490 *
5491 * @state: NFSv4 state for an inode
5492 *
5493 * Returns NFS_OK if recovery for this stateid is now finished.
5494 * Otherwise a negative NFS4ERR value is returned.
5495 */
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05005496static int nfs41_check_expired_locks(struct nfs4_state *state)
Bryan Schumakerf062eb62011-06-02 14:59:10 -04005497{
Chuck Levereb64cf92012-07-11 16:30:05 -04005498 int status, ret = -NFS4ERR_BAD_STATEID;
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05005499 struct nfs4_lock_state *lsp;
Bryan Schumakerf062eb62011-06-02 14:59:10 -04005500 struct nfs_server *server = NFS_SERVER(state->inode);
5501
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05005502 list_for_each_entry(lsp, &state->lock_states, ls_locks) {
Trond Myklebust795a88c2012-09-10 13:26:49 -04005503 if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04005504 struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
5505
5506 status = nfs41_test_stateid(server,
5507 &lsp->ls_stateid,
5508 cred);
Trond Myklebust08cb47f2013-08-20 21:59:40 -04005509 trace_nfs4_test_lock_stateid(state, lsp, status);
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05005510 if (status != NFS_OK) {
Chuck Lever3e60ffd2012-07-11 16:30:14 -04005511 /* Free the stateid unless the server
5512 * informs us the stateid is unrecognized. */
Chuck Lever89af2732012-07-11 16:29:56 -04005513 if (status != -NFS4ERR_BAD_STATEID)
5514 nfs41_free_stateid(server,
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04005515 &lsp->ls_stateid,
5516 cred);
Trond Myklebust795a88c2012-09-10 13:26:49 -04005517 clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
Bryan Schumakerb01dd1d2012-01-31 10:39:30 -05005518 ret = status;
5519 }
5520 }
5521 };
5522
5523 return ret;
5524}
5525
5526static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
5527{
5528 int status = NFS_OK;
5529
5530 if (test_bit(LK_STATE_IN_USE, &state->flags))
5531 status = nfs41_check_expired_locks(state);
Chuck Levereb64cf92012-07-11 16:30:05 -04005532 if (status != NFS_OK)
5533 status = nfs4_lock_expired(state, request);
5534 return status;
Bryan Schumakerf062eb62011-06-02 14:59:10 -04005535}
5536#endif
5537
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
5539{
Trond Myklebust9a99af492013-02-04 20:17:49 -05005540 struct nfs4_state_owner *sp = state->owner;
Trond Myklebust19e03c52008-12-23 15:21:44 -05005541 struct nfs_inode *nfsi = NFS_I(state->inode);
Trond Myklebust01c3b862006-06-29 16:38:39 -04005542 unsigned char fl_flags = request->fl_flags;
Trond Myklebust9a99af492013-02-04 20:17:49 -05005543 unsigned int seq;
Trond Myklebust8e469eb2010-01-26 15:42:30 -05005544 int status = -ENOLCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005545
Trond Myklebust8e469eb2010-01-26 15:42:30 -05005546 if ((fl_flags & FL_POSIX) &&
5547 !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags))
5548 goto out;
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05005549 /* Is this a delegated open? */
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05005550 status = nfs4_set_lock_state(state, request);
5551 if (status != 0)
5552 goto out;
Trond Myklebust01c3b862006-06-29 16:38:39 -04005553 request->fl_flags |= FL_ACCESS;
5554 status = do_vfs_lock(request->fl_file, request);
5555 if (status < 0)
5556 goto out;
Trond Myklebust19e03c52008-12-23 15:21:44 -05005557 down_read(&nfsi->rwsem);
Trond Myklebust01c3b862006-06-29 16:38:39 -04005558 if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
Trond Myklebust01c3b862006-06-29 16:38:39 -04005559 /* Yes: cache locks! */
Trond Myklebust01c3b862006-06-29 16:38:39 -04005560 /* ...but avoid races with delegation recall... */
Trond Myklebust19e03c52008-12-23 15:21:44 -05005561 request->fl_flags = fl_flags & ~FL_SLEEP;
5562 status = do_vfs_lock(request->fl_file, request);
5563 goto out_unlock;
Trond Myklebust01c3b862006-06-29 16:38:39 -04005564 }
Trond Myklebust9a99af492013-02-04 20:17:49 -05005565 seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
5566 up_read(&nfsi->rwsem);
Alexandros Batsakisafe6c272009-12-09 01:50:14 -08005567 status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05005568 if (status != 0)
Trond Myklebust9a99af492013-02-04 20:17:49 -05005569 goto out;
5570 down_read(&nfsi->rwsem);
5571 if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) {
5572 status = -NFS4ERR_DELAY;
Trond Myklebust01c3b862006-06-29 16:38:39 -04005573 goto out_unlock;
Trond Myklebust9a99af492013-02-04 20:17:49 -05005574 }
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05005575 /* Note: we always want to sleep here! */
Trond Myklebust01c3b862006-06-29 16:38:39 -04005576 request->fl_flags = fl_flags | FL_SLEEP;
Trond Myklebust6bfc93e2005-11-04 15:39:36 -05005577 if (do_vfs_lock(request->fl_file, request) < 0)
Weston Andros Adamsona0308892012-01-26 13:32:23 -05005578 printk(KERN_WARNING "NFS: %s: VFS is out of sync with lock "
5579 "manager!\n", __func__);
Trond Myklebust01c3b862006-06-29 16:38:39 -04005580out_unlock:
Trond Myklebust19e03c52008-12-23 15:21:44 -05005581 up_read(&nfsi->rwsem);
Trond Myklebust01c3b862006-06-29 16:38:39 -04005582out:
5583 request->fl_flags = fl_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005584 return status;
5585}
5586
5587static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
5588{
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -05005589 struct nfs4_exception exception = {
5590 .state = state,
Trond Myklebust05ffe242012-04-18 12:20:10 -04005591 .inode = state->inode,
Trond Myklebusta1d0b5e2012-03-05 19:56:44 -05005592 };
Linus Torvalds1da177e2005-04-16 15:20:36 -07005593 int err;
5594
5595 do {
Trond Myklebust965b5d62009-06-17 13:22:59 -07005596 err = _nfs4_proc_setlk(state, cmd, request);
Trond Myklebustd1b748a2013-08-12 16:35:20 -04005597 trace_nfs4_set_lock(request, state, cmd, err);
Trond Myklebust965b5d62009-06-17 13:22:59 -07005598 if (err == -NFS4ERR_DENIED)
5599 err = -EAGAIN;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005600 err = nfs4_handle_exception(NFS_SERVER(state->inode),
Trond Myklebust965b5d62009-06-17 13:22:59 -07005601 err, &exception);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005602 } while (exception.retry);
5603 return err;
5604}
5605
5606static int
5607nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
5608{
5609 struct nfs_open_context *ctx;
5610 struct nfs4_state *state;
5611 unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
5612 int status;
5613
5614 /* verify open state */
Trond Myklebustcd3758e2007-08-10 17:44:32 -04005615 ctx = nfs_file_open_context(filp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005616 state = ctx->state;
5617
5618 if (request->fl_start < 0 || request->fl_end < 0)
5619 return -EINVAL;
5620
Trond Myklebustd9531262009-07-21 19:22:38 -04005621 if (IS_GETLK(cmd)) {
5622 if (state != NULL)
5623 return nfs4_proc_getlk(state, F_GETLK, request);
5624 return 0;
5625 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005626
5627 if (!(IS_SETLK(cmd) || IS_SETLKW(cmd)))
5628 return -EINVAL;
5629
Trond Myklebustd9531262009-07-21 19:22:38 -04005630 if (request->fl_type == F_UNLCK) {
5631 if (state != NULL)
5632 return nfs4_proc_unlck(state, cmd, request);
5633 return 0;
5634 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005635
Trond Myklebustd9531262009-07-21 19:22:38 -04005636 if (state == NULL)
5637 return -ENOLCK;
Trond Myklebust55725512012-04-18 12:48:35 -04005638 /*
5639 * Don't rely on the VFS having checked the file open mode,
5640 * since it won't do this for flock() locks.
5641 */
Jeff Laytonf44106e2012-07-23 15:49:56 -04005642 switch (request->fl_type) {
Trond Myklebust55725512012-04-18 12:48:35 -04005643 case F_RDLCK:
5644 if (!(filp->f_mode & FMODE_READ))
5645 return -EBADF;
5646 break;
5647 case F_WRLCK:
5648 if (!(filp->f_mode & FMODE_WRITE))
5649 return -EBADF;
5650 }
5651
Linus Torvalds1da177e2005-04-16 15:20:36 -07005652 do {
5653 status = nfs4_proc_setlk(state, cmd, request);
5654 if ((status != -EAGAIN) || IS_SETLK(cmd))
5655 break;
5656 timeout = nfs4_set_lock_task_retry(timeout);
5657 status = -ERESTARTSYS;
5658 if (signalled())
5659 break;
5660 } while(status < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005661 return status;
5662}
5663
Trond Myklebustdb4f2e632013-04-01 15:56:46 -04005664int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid)
Trond Myklebust888e6942005-11-04 15:38:11 -05005665{
5666 struct nfs_server *server = NFS_SERVER(state->inode);
Trond Myklebust888e6942005-11-04 15:38:11 -05005667 int err;
5668
5669 err = nfs4_set_lock_state(state, fl);
5670 if (err != 0)
Trond Myklebustdb4f2e632013-04-01 15:56:46 -04005671 return err;
Trond Myklebust4a706fa2013-04-01 14:47:22 -04005672 err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
Trond Myklebustdb4f2e632013-04-01 15:56:46 -04005673 return nfs4_handle_delegation_recall_error(server, state, stateid, err);
Trond Myklebust888e6942005-11-04 15:38:11 -05005674}
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00005675
Trond Myklebustcf470c32012-03-07 13:49:12 -05005676struct nfs_release_lockowner_data {
5677 struct nfs4_lock_state *lsp;
Trond Myklebust5ae67c42012-03-19 16:17:18 -04005678 struct nfs_server *server;
Trond Myklebustcf470c32012-03-07 13:49:12 -05005679 struct nfs_release_lockowner_args args;
5680};
5681
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04005682static void nfs4_release_lockowner_release(void *calldata)
5683{
Trond Myklebustcf470c32012-03-07 13:49:12 -05005684 struct nfs_release_lockowner_data *data = calldata;
Trond Myklebust5ae67c42012-03-19 16:17:18 -04005685 nfs4_free_lock_state(data->server, data->lsp);
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04005686 kfree(calldata);
5687}
5688
Trond Myklebust17280172012-03-11 13:11:00 -04005689static const struct rpc_call_ops nfs4_release_lockowner_ops = {
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04005690 .rpc_release = nfs4_release_lockowner_release,
5691};
5692
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04005693static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04005694{
Trond Myklebustcf470c32012-03-07 13:49:12 -05005695 struct nfs_release_lockowner_data *data;
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04005696 struct rpc_message msg = {
5697 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
5698 };
5699
5700 if (server->nfs_client->cl_mvops->minor_version != 0)
Trond Myklebustcf470c32012-03-07 13:49:12 -05005701 return -EINVAL;
5702 data = kmalloc(sizeof(*data), GFP_NOFS);
5703 if (!data)
5704 return -ENOMEM;
5705 data->lsp = lsp;
Trond Myklebust5ae67c42012-03-19 16:17:18 -04005706 data->server = server;
Trond Myklebustcf470c32012-03-07 13:49:12 -05005707 data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
5708 data->args.lock_owner.id = lsp->ls_seqid.owner_id;
5709 data->args.lock_owner.s_dev = server->s_dev;
5710 msg.rpc_argp = &data->args;
5711 rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
5712 return 0;
Trond Myklebustd3c7b7c2010-07-01 12:49:01 -04005713}
5714
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005715#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
5716
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00005717static int nfs4_xattr_set_nfs4_acl(struct dentry *dentry, const char *key,
5718 const void *buf, size_t buflen,
5719 int flags, int type)
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00005720{
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00005721 if (strcmp(key, "") != 0)
5722 return -EINVAL;
J. Bruce Fields4b580ee2005-06-22 17:16:23 +00005723
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00005724 return nfs4_proc_set_acl(dentry->d_inode, buf, buflen);
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00005725}
5726
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00005727static int nfs4_xattr_get_nfs4_acl(struct dentry *dentry, const char *key,
5728 void *buf, size_t buflen, int type)
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00005729{
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00005730 if (strcmp(key, "") != 0)
5731 return -EINVAL;
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005732
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00005733 return nfs4_proc_get_acl(dentry->d_inode, buf, buflen);
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00005734}
5735
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00005736static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
5737 size_t list_len, const char *name,
5738 size_t name_len, int type)
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00005739{
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00005740 size_t len = sizeof(XATTR_NAME_NFSV4_ACL);
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00005741
J. Bruce Fields096455a2006-03-20 23:23:42 -05005742 if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
5743 return 0;
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00005744
5745 if (list && len <= list_len)
5746 memcpy(list, XATTR_NAME_NFSV4_ACL, len);
J. Bruce Fieldsaa1870a2005-06-22 17:16:22 +00005747 return len;
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00005748}
5749
David Quigleyc9bccef2013-05-22 12:50:45 -04005750#ifdef CONFIG_NFS_V4_SECURITY_LABEL
5751static inline int nfs4_server_supports_labels(struct nfs_server *server)
5752{
5753 return server->caps & NFS_CAP_SECURITY_LABEL;
5754}
5755
5756static int nfs4_xattr_set_nfs4_label(struct dentry *dentry, const char *key,
5757 const void *buf, size_t buflen,
5758 int flags, int type)
5759{
5760 if (security_ismaclabel(key))
5761 return nfs4_set_security_label(dentry, buf, buflen);
5762
5763 return -EOPNOTSUPP;
5764}
5765
5766static int nfs4_xattr_get_nfs4_label(struct dentry *dentry, const char *key,
5767 void *buf, size_t buflen, int type)
5768{
5769 if (security_ismaclabel(key))
5770 return nfs4_get_security_label(dentry->d_inode, buf, buflen);
5771 return -EOPNOTSUPP;
5772}
5773
5774static size_t nfs4_xattr_list_nfs4_label(struct dentry *dentry, char *list,
5775 size_t list_len, const char *name,
5776 size_t name_len, int type)
5777{
5778 size_t len = 0;
5779
5780 if (nfs_server_capable(dentry->d_inode, NFS_CAP_SECURITY_LABEL)) {
5781 len = security_inode_listsecurity(dentry->d_inode, NULL, 0);
5782 if (list && len <= list_len)
5783 security_inode_listsecurity(dentry->d_inode, list, len);
5784 }
5785 return len;
5786}
5787
5788static const struct xattr_handler nfs4_xattr_nfs4_label_handler = {
5789 .prefix = XATTR_SECURITY_PREFIX,
5790 .list = nfs4_xattr_list_nfs4_label,
5791 .get = nfs4_xattr_get_nfs4_label,
5792 .set = nfs4_xattr_set_nfs4_label,
5793};
5794#endif
5795
5796
Andy Adamson533eb462011-06-13 18:25:56 -04005797/*
5798 * nfs_fhget will use either the mounted_on_fileid or the fileid
5799 */
Trond Myklebust69aaaae2009-03-11 14:10:28 -04005800static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
5801{
Andy Adamson533eb462011-06-13 18:25:56 -04005802 if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) ||
5803 (fattr->valid & NFS_ATTR_FATTR_FILEID)) &&
5804 (fattr->valid & NFS_ATTR_FATTR_FSID) &&
Chuck Lever81934dd2012-03-01 17:01:57 -05005805 (fattr->valid & NFS_ATTR_FATTR_V4_LOCATIONS)))
Trond Myklebust69aaaae2009-03-11 14:10:28 -04005806 return;
5807
5808 fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
Chuck Lever81934dd2012-03-01 17:01:57 -05005809 NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_V4_REFERRAL;
Trond Myklebust69aaaae2009-03-11 14:10:28 -04005810 fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
5811 fattr->nlink = 2;
5812}
5813
Bryan Schumakerf05d1472012-04-27 13:27:41 -04005814static int _nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
5815 const struct qstr *name,
5816 struct nfs4_fs_locations *fs_locations,
5817 struct page *page)
Trond Myklebust683b57b2006-06-09 09:34:22 -04005818{
5819 struct nfs_server *server = NFS_SERVER(dir);
David Quigleya09df2c2013-05-22 12:50:41 -04005820 u32 bitmask[3] = {
Manoj Naik361e6242006-06-09 09:34:24 -04005821 [0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
Trond Myklebust683b57b2006-06-09 09:34:22 -04005822 };
5823 struct nfs4_fs_locations_arg args = {
5824 .dir_fh = NFS_FH(dir),
Trond Myklebustc228fd32007-01-13 02:28:11 -05005825 .name = name,
Trond Myklebust683b57b2006-06-09 09:34:22 -04005826 .page = page,
5827 .bitmask = bitmask,
5828 };
Benny Halevy22958462009-04-01 09:22:02 -04005829 struct nfs4_fs_locations_res res = {
5830 .fs_locations = fs_locations,
5831 };
Trond Myklebust683b57b2006-06-09 09:34:22 -04005832 struct rpc_message msg = {
5833 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
5834 .rpc_argp = &args,
Benny Halevy22958462009-04-01 09:22:02 -04005835 .rpc_resp = &res,
Trond Myklebust683b57b2006-06-09 09:34:22 -04005836 };
5837 int status;
5838
Harvey Harrison3110ff82008-05-02 13:42:44 -07005839 dprintk("%s: start\n", __func__);
Andy Adamson533eb462011-06-13 18:25:56 -04005840
5841 /* Ask for the fileid of the absent filesystem if mounted_on_fileid
5842 * is not supported */
5843 if (NFS_SERVER(dir)->attr_bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
5844 bitmask[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
5845 else
5846 bitmask[0] |= FATTR4_WORD0_FILEID;
5847
Trond Myklebustc228fd32007-01-13 02:28:11 -05005848 nfs_fattr_init(&fs_locations->fattr);
Trond Myklebust683b57b2006-06-09 09:34:22 -04005849 fs_locations->server = server;
Manoj Naik830b8e32006-06-09 09:34:25 -04005850 fs_locations->nlocations = 0;
Bryan Schumakerf05d1472012-04-27 13:27:41 -04005851 status = nfs4_call_sync(client, server, &msg, &args.seq_args, &res.seq_res, 0);
Harvey Harrison3110ff82008-05-02 13:42:44 -07005852 dprintk("%s: returned status = %d\n", __func__, status);
Trond Myklebust683b57b2006-06-09 09:34:22 -04005853 return status;
5854}
5855
Bryan Schumakerf05d1472012-04-27 13:27:41 -04005856int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
5857 const struct qstr *name,
5858 struct nfs4_fs_locations *fs_locations,
5859 struct page *page)
Bryan Schumakerdb0a9592012-04-27 13:27:39 -04005860{
5861 struct nfs4_exception exception = { };
5862 int err;
5863 do {
Trond Myklebust078ea3d2013-08-12 16:45:55 -04005864 err = _nfs4_proc_fs_locations(client, dir, name,
5865 fs_locations, page);
5866 trace_nfs4_get_fs_locations(dir, name, err);
5867 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Bryan Schumakerdb0a9592012-04-27 13:27:39 -04005868 &exception);
5869 } while (exception.retry);
5870 return err;
5871}
5872
Andy Adamson5ec16a82013-08-08 10:57:55 -04005873/**
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04005874 * If 'use_integrity' is true and the state managment nfs_client
5875 * cl_rpcclient is using krb5i/p, use the integrity protected cl_rpcclient
5876 * and the machine credential as per RFC3530bis and RFC5661 Security
5877 * Considerations sections. Otherwise, just use the user cred with the
5878 * filesystem's rpc_client.
Andy Adamson5ec16a82013-08-08 10:57:55 -04005879 */
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04005880static 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 +00005881{
5882 int status;
5883 struct nfs4_secinfo_arg args = {
5884 .dir_fh = NFS_FH(dir),
5885 .name = name,
5886 };
5887 struct nfs4_secinfo_res res = {
5888 .flavors = flavors,
5889 };
5890 struct rpc_message msg = {
5891 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO],
5892 .rpc_argp = &args,
5893 .rpc_resp = &res,
5894 };
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04005895 struct rpc_clnt *clnt = NFS_SERVER(dir)->client;
5896
5897 if (use_integrity) {
5898 clnt = NFS_SERVER(dir)->nfs_client->cl_rpcclient;
5899 msg.rpc_cred = nfs4_get_clid_cred(NFS_SERVER(dir)->nfs_client);
5900 }
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00005901
5902 dprintk("NFS call secinfo %s\n", name->name);
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04005903 status = nfs4_call_sync(clnt, NFS_SERVER(dir), &msg, &args.seq_args,
5904 &res.seq_res, 0);
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00005905 dprintk("NFS reply secinfo: %d\n", status);
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04005906
5907 if (msg.rpc_cred)
5908 put_rpccred(msg.rpc_cred);
5909
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00005910 return status;
5911}
5912
Bryan Schumaker72de53e2012-04-27 13:27:40 -04005913int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
5914 struct nfs4_secinfo_flavors *flavors)
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00005915{
5916 struct nfs4_exception exception = { };
5917 int err;
5918 do {
Weston Andros Adamsona5250de2013-09-03 15:18:49 -04005919 err = -NFS4ERR_WRONGSEC;
5920
5921 /* try to use integrity protection with machine cred */
5922 if (_nfs4_is_integrity_protected(NFS_SERVER(dir)->nfs_client))
5923 err = _nfs4_proc_secinfo(dir, name, flavors, true);
5924
5925 /*
5926 * if unable to use integrity protection, or SECINFO with
5927 * integrity protection returns NFS4ERR_WRONGSEC (which is
5928 * disallowed by spec, but exists in deployed servers) use
5929 * the current filesystem's rpc_client and the user cred.
5930 */
5931 if (err == -NFS4ERR_WRONGSEC)
5932 err = _nfs4_proc_secinfo(dir, name, flavors, false);
5933
Trond Myklebust078ea3d2013-08-12 16:45:55 -04005934 trace_nfs4_secinfo(dir, name, err);
5935 err = nfs4_handle_exception(NFS_SERVER(dir), err,
Bryan Schumaker5a5ea0d2011-03-24 17:12:29 +00005936 &exception);
5937 } while (exception.retry);
5938 return err;
5939}
5940
Andy Adamson557134a2009-04-01 09:21:53 -04005941#ifdef CONFIG_NFS_V4_1
Benny Halevy99fe60d2009-04-01 09:22:29 -04005942/*
Andy Adamson357f54d2010-12-14 10:11:57 -05005943 * Check the exchange flags returned by the server for invalid flags, having
5944 * both PNFS and NON_PNFS flags set, and not having one of NON_PNFS, PNFS, or
5945 * DS flags set.
5946 */
5947static int nfs4_check_cl_exchange_flags(u32 flags)
5948{
5949 if (flags & ~EXCHGID4_FLAG_MASK_R)
5950 goto out_inval;
5951 if ((flags & EXCHGID4_FLAG_USE_PNFS_MDS) &&
5952 (flags & EXCHGID4_FLAG_USE_NON_PNFS))
5953 goto out_inval;
5954 if (!(flags & (EXCHGID4_FLAG_MASK_PNFS)))
5955 goto out_inval;
5956 return NFS_OK;
5957out_inval:
5958 return -NFS4ERR_INVAL;
5959}
5960
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04005961static bool
Chuck Lever79d4e1f2012-05-21 22:44:31 -04005962nfs41_same_server_scope(struct nfs41_server_scope *a,
5963 struct nfs41_server_scope *b)
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04005964{
5965 if (a->server_scope_sz == b->server_scope_sz &&
5966 memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0)
5967 return true;
5968
5969 return false;
5970}
5971
Andy Adamson357f54d2010-12-14 10:11:57 -05005972/*
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04005973 * nfs4_proc_bind_conn_to_session()
5974 *
5975 * The 4.1 client currently uses the same TCP connection for the
5976 * fore and backchannel.
5977 */
Trond Myklebust2cf047c2012-05-25 17:57:41 -04005978int nfs4_proc_bind_conn_to_session(struct nfs_client *clp, struct rpc_cred *cred)
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04005979{
5980 int status;
5981 struct nfs41_bind_conn_to_session_res res;
5982 struct rpc_message msg = {
5983 .rpc_proc =
5984 &nfs4_procedures[NFSPROC4_CLNT_BIND_CONN_TO_SESSION],
5985 .rpc_argp = clp,
5986 .rpc_resp = &res,
Trond Myklebust2cf047c2012-05-25 17:57:41 -04005987 .rpc_cred = cred,
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04005988 };
5989
5990 dprintk("--> %s\n", __func__);
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04005991
5992 res.session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
5993 if (unlikely(res.session == NULL)) {
5994 status = -ENOMEM;
5995 goto out;
5996 }
5997
5998 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04005999 trace_nfs4_bind_conn_to_session(clp, status);
Weston Andros Adamson7c44f1ae2012-05-24 13:22:50 -04006000 if (status == 0) {
6001 if (memcmp(res.session->sess_id.data,
6002 clp->cl_session->sess_id.data, NFS4_MAX_SESSIONID_LEN)) {
6003 dprintk("NFS: %s: Session ID mismatch\n", __func__);
6004 status = -EIO;
6005 goto out_session;
6006 }
6007 if (res.dir != NFS4_CDFS4_BOTH) {
6008 dprintk("NFS: %s: Unexpected direction from server\n",
6009 __func__);
6010 status = -EIO;
6011 goto out_session;
6012 }
6013 if (res.use_conn_in_rdma_mode) {
6014 dprintk("NFS: %s: Server returned RDMA mode = true\n",
6015 __func__);
6016 status = -EIO;
6017 goto out_session;
6018 }
6019 }
6020out_session:
6021 kfree(res.session);
6022out:
6023 dprintk("<-- %s status= %d\n", __func__, status);
6024 return status;
6025}
6026
6027/*
Benny Halevy99fe60d2009-04-01 09:22:29 -04006028 * nfs4_proc_exchange_id()
6029 *
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006030 * Returns zero, a negative errno, or a negative NFS4ERR status code.
6031 *
Benny Halevy99fe60d2009-04-01 09:22:29 -04006032 * Since the clientid has expired, all compounds using sessions
6033 * associated with the stale clientid will be returning
6034 * NFS4ERR_BADSESSION in the sequence operation, and will therefore
6035 * be in some phase of session reset.
6036 */
Andy Adamson4d643d12009-12-04 15:52:24 -05006037int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
Benny Halevy99fe60d2009-04-01 09:22:29 -04006038{
6039 nfs4_verifier verifier;
6040 struct nfs41_exchange_id_args args = {
Chuck Levercd937102012-03-02 17:14:31 -05006041 .verifier = &verifier,
Benny Halevy99fe60d2009-04-01 09:22:29 -04006042 .client = clp,
Trond Myklebust4f0b4292013-05-20 12:24:03 -04006043 .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER |
6044 EXCHGID4_FLAG_BIND_PRINC_STATEID,
Benny Halevy99fe60d2009-04-01 09:22:29 -04006045 };
6046 struct nfs41_exchange_id_res res = {
Trond Myklebust32b01312012-05-26 13:41:04 -04006047 0
Benny Halevy99fe60d2009-04-01 09:22:29 -04006048 };
6049 int status;
6050 struct rpc_message msg = {
6051 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID],
6052 .rpc_argp = &args,
6053 .rpc_resp = &res,
6054 .rpc_cred = cred,
6055 };
Benny Halevy99fe60d2009-04-01 09:22:29 -04006056
Chuck Leverf0920752012-05-21 22:45:41 -04006057 nfs4_init_boot_verifier(clp, &verifier);
Chuck Levere984a552012-09-14 17:24:21 -04006058 args.id_len = nfs4_init_uniform_client_string(clp, args.id,
6059 sizeof(args.id));
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006060 dprintk("NFS call exchange_id auth=%s, '%.*s'\n",
6061 clp->cl_rpcclient->cl_auth->au_ops->au_name,
6062 args.id_len, args.id);
Benny Halevy99fe60d2009-04-01 09:22:29 -04006063
Chuck Leveracdeb692012-05-21 22:46:16 -04006064 res.server_owner = kzalloc(sizeof(struct nfs41_server_owner),
Trond Myklebustbbafffd2012-05-24 16:31:39 -04006065 GFP_NOFS);
Chuck Leveracdeb692012-05-21 22:46:16 -04006066 if (unlikely(res.server_owner == NULL)) {
Weston Andros Adamsonabe9a6d2012-02-16 11:17:05 -05006067 status = -ENOMEM;
6068 goto out;
6069 }
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04006070
Chuck Lever79d4e1f2012-05-21 22:44:31 -04006071 res.server_scope = kzalloc(sizeof(struct nfs41_server_scope),
Trond Myklebustbbafffd2012-05-24 16:31:39 -04006072 GFP_NOFS);
Chuck Lever177313f2012-05-21 22:44:58 -04006073 if (unlikely(res.server_scope == NULL)) {
Benny Halevy99fe60d2009-04-01 09:22:29 -04006074 status = -ENOMEM;
Chuck Leveracdeb692012-05-21 22:46:16 -04006075 goto out_server_owner;
Benny Halevy99fe60d2009-04-01 09:22:29 -04006076 }
6077
Trond Myklebustbbafffd2012-05-24 16:31:39 -04006078 res.impl_id = kzalloc(sizeof(struct nfs41_impl_id), GFP_NOFS);
Chuck Lever177313f2012-05-21 22:44:58 -04006079 if (unlikely(res.impl_id == NULL)) {
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05006080 status = -ENOMEM;
6081 goto out_server_scope;
6082 }
6083
Trond Myklebust1bd714f2011-04-24 14:29:33 -04006084 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04006085 trace_nfs4_exchange_id(clp, status);
Chuck Lever177313f2012-05-21 22:44:58 -04006086 if (status == 0)
Trond Myklebust32b01312012-05-26 13:41:04 -04006087 status = nfs4_check_cl_exchange_flags(res.flags);
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04006088
Chuck Lever177313f2012-05-21 22:44:58 -04006089 if (status == 0) {
Trond Myklebust32b01312012-05-26 13:41:04 -04006090 clp->cl_clientid = res.clientid;
6091 clp->cl_exchange_flags = (res.flags & ~EXCHGID4_FLAG_CONFIRMED_R);
6092 if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R))
6093 clp->cl_seqid = res.seqid;
6094
Chuck Leveracdeb692012-05-21 22:46:16 -04006095 kfree(clp->cl_serverowner);
6096 clp->cl_serverowner = res.server_owner;
6097 res.server_owner = NULL;
Chuck Leveracdeb692012-05-21 22:46:16 -04006098
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05006099 /* use the most recent implementation id */
Chuck Lever59155542012-05-21 22:44:41 -04006100 kfree(clp->cl_implid);
6101 clp->cl_implid = res.impl_id;
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05006102
Chuck Lever177313f2012-05-21 22:44:58 -04006103 if (clp->cl_serverscope != NULL &&
Chuck Lever79d4e1f2012-05-21 22:44:31 -04006104 !nfs41_same_server_scope(clp->cl_serverscope,
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04006105 res.server_scope)) {
6106 dprintk("%s: server_scope mismatch detected\n",
6107 __func__);
6108 set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state);
Chuck Lever79d4e1f2012-05-21 22:44:31 -04006109 kfree(clp->cl_serverscope);
6110 clp->cl_serverscope = NULL;
Weston Andros Adamson78fe0f42011-05-31 19:05:47 -04006111 }
6112
Chuck Lever177313f2012-05-21 22:44:58 -04006113 if (clp->cl_serverscope == NULL) {
Chuck Lever79d4e1f2012-05-21 22:44:31 -04006114 clp->cl_serverscope = res.server_scope;
Weston Andros Adamsonabe9a6d2012-02-16 11:17:05 -05006115 goto out;
6116 }
Trond Myklebust32b01312012-05-26 13:41:04 -04006117 } else
6118 kfree(res.impl_id);
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05006119
Chuck Leveracdeb692012-05-21 22:46:16 -04006120out_server_owner:
6121 kfree(res.server_owner);
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05006122out_server_scope:
Weston Andros Adamsonabe9a6d2012-02-16 11:17:05 -05006123 kfree(res.server_scope);
6124out:
Chuck Lever177313f2012-05-21 22:44:58 -04006125 if (clp->cl_implid != NULL)
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006126 dprintk("NFS reply exchange_id: Server Implementation ID: "
Weston Andros Adamson7d2ed9a2012-02-17 15:20:26 -05006127 "domain: %s, name: %s, date: %llu,%u\n",
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006128 clp->cl_implid->domain, clp->cl_implid->name,
Chuck Lever59155542012-05-21 22:44:41 -04006129 clp->cl_implid->date.seconds,
6130 clp->cl_implid->date.nseconds);
Chuck Lever6bbb4ae2012-07-11 16:30:59 -04006131 dprintk("NFS reply exchange_id: %d\n", status);
Benny Halevy99fe60d2009-04-01 09:22:29 -04006132 return status;
6133}
6134
Trond Myklebust66245532012-05-25 17:18:09 -04006135static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
6136 struct rpc_cred *cred)
6137{
6138 struct rpc_message msg = {
6139 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_CLIENTID],
6140 .rpc_argp = clp,
6141 .rpc_cred = cred,
6142 };
6143 int status;
6144
6145 status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04006146 trace_nfs4_destroy_clientid(clp, status);
Trond Myklebust66245532012-05-25 17:18:09 -04006147 if (status)
Trond Myklebust02c67522012-06-07 13:45:53 -04006148 dprintk("NFS: Got error %d from the server %s on "
Trond Myklebust66245532012-05-25 17:18:09 -04006149 "DESTROY_CLIENTID.", status, clp->cl_hostname);
6150 return status;
6151}
6152
6153static int nfs4_proc_destroy_clientid(struct nfs_client *clp,
6154 struct rpc_cred *cred)
6155{
6156 unsigned int loop;
6157 int ret;
6158
6159 for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
6160 ret = _nfs4_proc_destroy_clientid(clp, cred);
6161 switch (ret) {
6162 case -NFS4ERR_DELAY:
6163 case -NFS4ERR_CLIENTID_BUSY:
6164 ssleep(1);
6165 break;
6166 default:
6167 return ret;
6168 }
6169 }
6170 return 0;
6171}
6172
6173int nfs4_destroy_clientid(struct nfs_client *clp)
6174{
6175 struct rpc_cred *cred;
6176 int ret = 0;
6177
6178 if (clp->cl_mvops->minor_version < 1)
6179 goto out;
6180 if (clp->cl_exchange_flags == 0)
6181 goto out;
Chuck Lever05f4c352012-09-14 17:24:32 -04006182 if (clp->cl_preserve_clid)
6183 goto out;
Chuck Lever73d8bde2013-07-24 12:28:37 -04006184 cred = nfs4_get_clid_cred(clp);
Trond Myklebust66245532012-05-25 17:18:09 -04006185 ret = nfs4_proc_destroy_clientid(clp, cred);
6186 if (cred)
6187 put_rpccred(cred);
6188 switch (ret) {
6189 case 0:
6190 case -NFS4ERR_STALE_CLIENTID:
6191 clp->cl_exchange_flags = 0;
6192 }
6193out:
6194 return ret;
6195}
6196
Andy Adamson2050f0c2009-04-01 09:22:30 -04006197struct nfs4_get_lease_time_data {
6198 struct nfs4_get_lease_time_args *args;
6199 struct nfs4_get_lease_time_res *res;
6200 struct nfs_client *clp;
6201};
6202
6203static void nfs4_get_lease_time_prepare(struct rpc_task *task,
6204 void *calldata)
6205{
Andy Adamson2050f0c2009-04-01 09:22:30 -04006206 struct nfs4_get_lease_time_data *data =
6207 (struct nfs4_get_lease_time_data *)calldata;
6208
6209 dprintk("--> %s\n", __func__);
6210 /* just setup sequence, do not trigger session recovery
6211 since we're invoked within one */
Trond Myklebustd9afbd12012-10-22 20:28:44 -04006212 nfs41_setup_sequence(data->clp->cl_session,
6213 &data->args->la_seq_args,
6214 &data->res->lr_seq_res,
6215 task);
Andy Adamson2050f0c2009-04-01 09:22:30 -04006216 dprintk("<-- %s\n", __func__);
6217}
6218
6219/*
6220 * Called from nfs4_state_manager thread for session setup, so don't recover
6221 * from sequence operation or clientid errors.
6222 */
6223static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
6224{
6225 struct nfs4_get_lease_time_data *data =
6226 (struct nfs4_get_lease_time_data *)calldata;
6227
6228 dprintk("--> %s\n", __func__);
Trond Myklebust14516c32010-07-31 14:29:06 -04006229 if (!nfs41_sequence_done(task, &data->res->lr_seq_res))
6230 return;
Andy Adamson2050f0c2009-04-01 09:22:30 -04006231 switch (task->tk_status) {
6232 case -NFS4ERR_DELAY:
6233 case -NFS4ERR_GRACE:
6234 dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
6235 rpc_delay(task, NFS4_POLL_RETRY_MIN);
6236 task->tk_status = 0;
Andy Adamsona8a4ae32011-05-03 13:43:03 -04006237 /* fall through */
6238 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebustd00c5d42011-10-19 12:17:29 -07006239 rpc_restart_call_prepare(task);
Andy Adamson2050f0c2009-04-01 09:22:30 -04006240 return;
6241 }
Andy Adamson2050f0c2009-04-01 09:22:30 -04006242 dprintk("<-- %s\n", __func__);
6243}
6244
Trond Myklebust17280172012-03-11 13:11:00 -04006245static const struct rpc_call_ops nfs4_get_lease_time_ops = {
Andy Adamson2050f0c2009-04-01 09:22:30 -04006246 .rpc_call_prepare = nfs4_get_lease_time_prepare,
6247 .rpc_call_done = nfs4_get_lease_time_done,
6248};
6249
6250int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
6251{
6252 struct rpc_task *task;
6253 struct nfs4_get_lease_time_args args;
6254 struct nfs4_get_lease_time_res res = {
6255 .lr_fsinfo = fsinfo,
6256 };
6257 struct nfs4_get_lease_time_data data = {
6258 .args = &args,
6259 .res = &res,
6260 .clp = clp,
6261 };
6262 struct rpc_message msg = {
6263 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME],
6264 .rpc_argp = &args,
6265 .rpc_resp = &res,
6266 };
6267 struct rpc_task_setup task_setup = {
6268 .rpc_client = clp->cl_rpcclient,
6269 .rpc_message = &msg,
6270 .callback_ops = &nfs4_get_lease_time_ops,
Trond Myklebust1bd714f2011-04-24 14:29:33 -04006271 .callback_data = &data,
6272 .flags = RPC_TASK_TIMEOUT,
Andy Adamson2050f0c2009-04-01 09:22:30 -04006273 };
6274 int status;
6275
Chuck Levera9c92d62013-08-09 12:48:18 -04006276 nfs4_init_sequence(&args.la_seq_args, &res.lr_seq_res, 0);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006277 nfs4_set_sequence_privileged(&args.la_seq_args);
Andy Adamson2050f0c2009-04-01 09:22:30 -04006278 dprintk("--> %s\n", __func__);
6279 task = rpc_run_task(&task_setup);
6280
6281 if (IS_ERR(task))
6282 status = PTR_ERR(task);
6283 else {
6284 status = task->tk_status;
6285 rpc_put_task(task);
6286 }
6287 dprintk("<-- %s return %d\n", __func__, status);
6288
6289 return status;
6290}
6291
Andy Adamsonfc931582009-04-01 09:22:31 -04006292/*
6293 * Initialize the values to be used by the client in CREATE_SESSION
6294 * If nfs4_init_session set the fore channel request and response sizes,
6295 * use them.
6296 *
6297 * Set the back channel max_resp_sz_cached to zero to force the client to
6298 * always set csa_cachethis to FALSE because the current implementation
6299 * of the back channel DRC only supports caching the CB_SEQUENCE operation.
6300 */
6301static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
6302{
Andy Adamson18aad3d2013-06-26 12:21:49 -04006303 unsigned int max_rqst_sz, max_resp_sz;
Andy Adamsonfc931582009-04-01 09:22:31 -04006304
Andy Adamson18aad3d2013-06-26 12:21:49 -04006305 max_rqst_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxwrite_overhead;
6306 max_resp_sz = NFS_MAX_FILE_IO_SIZE + nfs41_maxread_overhead;
6307
Andy Adamsonfc931582009-04-01 09:22:31 -04006308 /* Fore channel attributes */
Andy Adamson18aad3d2013-06-26 12:21:49 -04006309 args->fc_attrs.max_rqst_sz = max_rqst_sz;
6310 args->fc_attrs.max_resp_sz = max_resp_sz;
Andy Adamsonfc931582009-04-01 09:22:31 -04006311 args->fc_attrs.max_ops = NFS4_MAX_OPS;
Trond Myklebustef159e92012-02-06 19:50:40 -05006312 args->fc_attrs.max_reqs = max_session_slots;
Andy Adamsonfc931582009-04-01 09:22:31 -04006313
6314 dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u "
Mike Sager8e0d46e2009-12-17 12:06:26 -05006315 "max_ops=%u max_reqs=%u\n",
Andy Adamsonfc931582009-04-01 09:22:31 -04006316 __func__,
6317 args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz,
Mike Sager8e0d46e2009-12-17 12:06:26 -05006318 args->fc_attrs.max_ops, args->fc_attrs.max_reqs);
Andy Adamsonfc931582009-04-01 09:22:31 -04006319
6320 /* Back channel attributes */
Andy Adamsonfc931582009-04-01 09:22:31 -04006321 args->bc_attrs.max_rqst_sz = PAGE_SIZE;
6322 args->bc_attrs.max_resp_sz = PAGE_SIZE;
6323 args->bc_attrs.max_resp_sz_cached = 0;
6324 args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS;
6325 args->bc_attrs.max_reqs = 1;
6326
6327 dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u "
6328 "max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
6329 __func__,
6330 args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz,
6331 args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops,
6332 args->bc_attrs.max_reqs);
6333}
6334
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006335static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
Andy Adamson8d353012009-04-01 09:22:32 -04006336{
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006337 struct nfs4_channel_attrs *sent = &args->fc_attrs;
6338 struct nfs4_channel_attrs *rcvd = &session->fc_attrs;
6339
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006340 if (rcvd->max_resp_sz > sent->max_resp_sz)
6341 return -EINVAL;
6342 /*
6343 * Our requested max_ops is the minimum we need; we're not
6344 * prepared to break up compounds into smaller pieces than that.
6345 * So, no point even trying to continue if the server won't
6346 * cooperate:
6347 */
6348 if (rcvd->max_ops < sent->max_ops)
6349 return -EINVAL;
6350 if (rcvd->max_reqs == 0)
6351 return -EINVAL;
Vitaliy Gusevb4b9a0c2012-02-15 19:38:25 +04006352 if (rcvd->max_reqs > NFS4_MAX_SLOT_TABLE)
6353 rcvd->max_reqs = NFS4_MAX_SLOT_TABLE;
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006354 return 0;
Andy Adamson8d353012009-04-01 09:22:32 -04006355}
6356
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006357static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
6358{
6359 struct nfs4_channel_attrs *sent = &args->bc_attrs;
6360 struct nfs4_channel_attrs *rcvd = &session->bc_attrs;
Andy Adamson8d353012009-04-01 09:22:32 -04006361
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006362 if (rcvd->max_rqst_sz > sent->max_rqst_sz)
6363 return -EINVAL;
6364 if (rcvd->max_resp_sz < sent->max_resp_sz)
6365 return -EINVAL;
6366 if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
6367 return -EINVAL;
6368 /* These would render the backchannel useless: */
Vitaliy Gusevb4b9a0c2012-02-15 19:38:25 +04006369 if (rcvd->max_ops != sent->max_ops)
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006370 return -EINVAL;
Vitaliy Gusevb4b9a0c2012-02-15 19:38:25 +04006371 if (rcvd->max_reqs != sent->max_reqs)
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006372 return -EINVAL;
6373 return 0;
6374}
Andy Adamson8d353012009-04-01 09:22:32 -04006375
Andy Adamson8d353012009-04-01 09:22:32 -04006376static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args,
6377 struct nfs4_session *session)
6378{
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006379 int ret;
Andy Adamson8d353012009-04-01 09:22:32 -04006380
J. Bruce Fields43c2e882010-10-02 15:19:01 -04006381 ret = nfs4_verify_fore_channel_attrs(args, session);
6382 if (ret)
6383 return ret;
6384 return nfs4_verify_back_channel_attrs(args, session);
Andy Adamson8d353012009-04-01 09:22:32 -04006385}
6386
Trond Myklebust848f5bd2012-05-25 17:51:23 -04006387static int _nfs4_proc_create_session(struct nfs_client *clp,
6388 struct rpc_cred *cred)
Andy Adamsonfc931582009-04-01 09:22:31 -04006389{
6390 struct nfs4_session *session = clp->cl_session;
6391 struct nfs41_create_session_args args = {
6392 .client = clp,
6393 .cb_program = NFS4_CALLBACK,
6394 };
6395 struct nfs41_create_session_res res = {
6396 .client = clp,
6397 };
6398 struct rpc_message msg = {
6399 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION],
6400 .rpc_argp = &args,
6401 .rpc_resp = &res,
Trond Myklebust848f5bd2012-05-25 17:51:23 -04006402 .rpc_cred = cred,
Andy Adamsonfc931582009-04-01 09:22:31 -04006403 };
6404 int status;
6405
6406 nfs4_init_channel_attrs(&args);
Andy Adamson0f914212009-04-01 09:23:16 -04006407 args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
Andy Adamsonfc931582009-04-01 09:22:31 -04006408
Trond Myklebust1bd714f2011-04-24 14:29:33 -04006409 status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04006410 trace_nfs4_create_session(clp, status);
Andy Adamsonfc931582009-04-01 09:22:31 -04006411
Trond Myklebust43095d32012-11-20 11:13:12 -05006412 if (!status) {
Andy Adamson8d353012009-04-01 09:22:32 -04006413 /* Verify the session's negotiated channel_attrs values */
6414 status = nfs4_verify_channel_attrs(&args, session);
Andy Adamsonfc931582009-04-01 09:22:31 -04006415 /* Increment the clientid slot sequence id */
6416 clp->cl_seqid++;
6417 }
6418
6419 return status;
6420}
6421
6422/*
6423 * Issues a CREATE_SESSION operation to the server.
6424 * It is the responsibility of the caller to verify the session is
6425 * expired before calling this routine.
6426 */
Trond Myklebust848f5bd2012-05-25 17:51:23 -04006427int nfs4_proc_create_session(struct nfs_client *clp, struct rpc_cred *cred)
Andy Adamsonfc931582009-04-01 09:22:31 -04006428{
6429 int status;
6430 unsigned *ptr;
Andy Adamsonfc931582009-04-01 09:22:31 -04006431 struct nfs4_session *session = clp->cl_session;
6432
6433 dprintk("--> %s clp=%p session=%p\n", __func__, clp, session);
6434
Trond Myklebust848f5bd2012-05-25 17:51:23 -04006435 status = _nfs4_proc_create_session(clp, cred);
Andy Adamsonfc931582009-04-01 09:22:31 -04006436 if (status)
6437 goto out;
6438
Andy Adamsonaacd5532011-11-09 13:58:21 -05006439 /* Init or reset the session slot tables */
6440 status = nfs4_setup_session_slot_tables(session);
6441 dprintk("slot table setup returned %d\n", status);
Andy Adamsonfc931582009-04-01 09:22:31 -04006442 if (status)
6443 goto out;
6444
6445 ptr = (unsigned *)&session->sess_id.data[0];
6446 dprintk("%s client>seqid %d sessionid %u:%u:%u:%u\n", __func__,
6447 clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]);
Andy Adamsonfc931582009-04-01 09:22:31 -04006448out:
6449 dprintk("<-- %s\n", __func__);
6450 return status;
6451}
6452
Andy Adamson0f3e66c2009-04-01 09:22:34 -04006453/*
6454 * Issue the over-the-wire RPC DESTROY_SESSION.
6455 * The caller must serialize access to this routine.
6456 */
Trond Myklebust848f5bd2012-05-25 17:51:23 -04006457int nfs4_proc_destroy_session(struct nfs4_session *session,
6458 struct rpc_cred *cred)
Andy Adamson0f3e66c2009-04-01 09:22:34 -04006459{
Trond Myklebust848f5bd2012-05-25 17:51:23 -04006460 struct rpc_message msg = {
6461 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION],
6462 .rpc_argp = session,
6463 .rpc_cred = cred,
6464 };
Andy Adamson0f3e66c2009-04-01 09:22:34 -04006465 int status = 0;
Andy Adamson0f3e66c2009-04-01 09:22:34 -04006466
6467 dprintk("--> nfs4_proc_destroy_session\n");
6468
6469 /* session is still being setup */
6470 if (session->clp->cl_cons_state != NFS_CS_READY)
6471 return status;
6472
Trond Myklebust1bd714f2011-04-24 14:29:33 -04006473 status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
Trond Myklebustc6d01c62013-08-09 11:51:26 -04006474 trace_nfs4_destroy_session(session->clp, status);
Andy Adamson0f3e66c2009-04-01 09:22:34 -04006475
6476 if (status)
Trond Myklebust08106ac2012-06-05 10:08:24 -04006477 dprintk("NFS: Got error %d from the server on DESTROY_SESSION. "
Andy Adamson0f3e66c2009-04-01 09:22:34 -04006478 "Session has been destroyed regardless...\n", status);
6479
6480 dprintk("<-- nfs4_proc_destroy_session\n");
6481 return status;
6482}
6483
Trond Myklebust7b38c362012-05-23 13:23:31 -04006484/*
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006485 * Renew the cl_session lease.
6486 */
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04006487struct nfs4_sequence_data {
6488 struct nfs_client *clp;
6489 struct nfs4_sequence_args args;
6490 struct nfs4_sequence_res res;
6491};
6492
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08006493static void nfs41_sequence_release(void *data)
6494{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04006495 struct nfs4_sequence_data *calldata = data;
6496 struct nfs_client *clp = calldata->clp;
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08006497
Alexandros Batsakis71358402010-02-05 03:45:05 -08006498 if (atomic_read(&clp->cl_count) > 1)
6499 nfs4_schedule_state_renewal(clp);
6500 nfs_put_client(clp);
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04006501 kfree(calldata);
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08006502}
6503
Trond Myklebustaa5190d2010-06-16 09:52:25 -04006504static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp)
6505{
6506 switch(task->tk_status) {
6507 case -NFS4ERR_DELAY:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04006508 rpc_delay(task, NFS4_POLL_RETRY_MAX);
6509 return -EAGAIN;
6510 default:
Trond Myklebust0400a6b2011-03-09 16:00:53 -05006511 nfs4_schedule_lease_recovery(clp);
Trond Myklebustaa5190d2010-06-16 09:52:25 -04006512 }
6513 return 0;
6514}
6515
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08006516static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006517{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04006518 struct nfs4_sequence_data *calldata = data;
6519 struct nfs_client *clp = calldata->clp;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006520
Trond Myklebust14516c32010-07-31 14:29:06 -04006521 if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
6522 return;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006523
Trond Myklebustc6d01c62013-08-09 11:51:26 -04006524 trace_nfs4_sequence(clp, task->tk_status);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006525 if (task->tk_status < 0) {
6526 dprintk("%s ERROR %d\n", __func__, task->tk_status);
Alexandros Batsakis71358402010-02-05 03:45:05 -08006527 if (atomic_read(&clp->cl_count) == 1)
6528 goto out;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006529
Trond Myklebustaa5190d2010-06-16 09:52:25 -04006530 if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) {
6531 rpc_restart_call_prepare(task);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006532 return;
6533 }
6534 }
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006535 dprintk("%s rpc_cred %p\n", __func__, task->tk_msg.rpc_cred);
Alexandros Batsakis71358402010-02-05 03:45:05 -08006536out:
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006537 dprintk("<-- %s\n", __func__);
6538}
6539
6540static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
6541{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04006542 struct nfs4_sequence_data *calldata = data;
6543 struct nfs_client *clp = calldata->clp;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006544 struct nfs4_sequence_args *args;
6545 struct nfs4_sequence_res *res;
6546
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006547 args = task->tk_msg.rpc_argp;
6548 res = task->tk_msg.rpc_resp;
6549
Trond Myklebustd9afbd12012-10-22 20:28:44 -04006550 nfs41_setup_sequence(clp->cl_session, args, res, task);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006551}
6552
6553static const struct rpc_call_ops nfs41_sequence_ops = {
6554 .rpc_call_done = nfs41_sequence_call_done,
6555 .rpc_call_prepare = nfs41_sequence_prepare,
Alexandros Batsakisdc96aef2010-02-05 03:45:04 -08006556 .rpc_release = nfs41_sequence_release,
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006557};
6558
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006559static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
6560 struct rpc_cred *cred,
6561 bool is_privileged)
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006562{
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04006563 struct nfs4_sequence_data *calldata;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006564 struct rpc_message msg = {
6565 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
6566 .rpc_cred = cred,
6567 };
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006568 struct rpc_task_setup task_setup_data = {
6569 .rpc_client = clp->cl_rpcclient,
6570 .rpc_message = &msg,
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006571 .callback_ops = &nfs41_sequence_ops,
Trond Myklebustbc7a05c2013-04-08 17:50:28 -04006572 .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006573 };
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006574
Alexandros Batsakis71358402010-02-05 03:45:05 -08006575 if (!atomic_inc_not_zero(&clp->cl_count))
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006576 return ERR_PTR(-EIO);
Benny Halevydfb4f3092010-09-24 09:17:01 -04006577 calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04006578 if (calldata == NULL) {
Alexandros Batsakis71358402010-02-05 03:45:05 -08006579 nfs_put_client(clp);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006580 return ERR_PTR(-ENOMEM);
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006581 }
Chuck Levera9c92d62013-08-09 12:48:18 -04006582 nfs4_init_sequence(&calldata->args, &calldata->res, 0);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006583 if (is_privileged)
6584 nfs4_set_sequence_privileged(&calldata->args);
Trond Myklebustd5f8d3f2010-06-16 09:52:25 -04006585 msg.rpc_argp = &calldata->args;
6586 msg.rpc_resp = &calldata->res;
6587 calldata->clp = clp;
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006588 task_setup_data.callback_data = calldata;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006589
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006590 return rpc_run_task(&task_setup_data);
6591}
6592
Trond Myklebust2f60ea62011-08-24 15:07:37 -04006593static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags)
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006594{
6595 struct rpc_task *task;
6596 int ret = 0;
6597
Trond Myklebust2f60ea62011-08-24 15:07:37 -04006598 if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
6599 return 0;
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006600 task = _nfs41_proc_sequence(clp, cred, false);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006601 if (IS_ERR(task))
6602 ret = PTR_ERR(task);
6603 else
Trond Myklebustbf294b42011-02-21 11:05:41 -08006604 rpc_put_task_async(task);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006605 dprintk("<-- %s status=%d\n", __func__, ret);
6606 return ret;
6607}
6608
6609static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
6610{
6611 struct rpc_task *task;
6612 int ret;
6613
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006614 task = _nfs41_proc_sequence(clp, cred, true);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006615 if (IS_ERR(task)) {
6616 ret = PTR_ERR(task);
6617 goto out;
6618 }
6619 ret = rpc_wait_for_completion_task(task);
Trond Myklebustb4410c22011-03-09 16:00:55 -05006620 if (!ret) {
6621 struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
6622
6623 if (task->tk_status == 0)
6624 nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006625 ret = task->tk_status;
Trond Myklebustb4410c22011-03-09 16:00:55 -05006626 }
Trond Myklebust71ac6da2010-06-16 09:52:26 -04006627 rpc_put_task(task);
6628out:
6629 dprintk("<-- %s status=%d\n", __func__, ret);
6630 return ret;
Andy Adamsonfc01cea2009-04-01 09:22:36 -04006631}
6632
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006633struct nfs4_reclaim_complete_data {
6634 struct nfs_client *clp;
6635 struct nfs41_reclaim_complete_args arg;
6636 struct nfs41_reclaim_complete_res res;
6637};
6638
6639static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
6640{
6641 struct nfs4_reclaim_complete_data *calldata = data;
6642
Trond Myklebustd9afbd12012-10-22 20:28:44 -04006643 nfs41_setup_sequence(calldata->clp->cl_session,
6644 &calldata->arg.seq_args,
6645 &calldata->res.seq_res,
6646 task);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006647}
6648
Trond Myklebustaa5190d2010-06-16 09:52:25 -04006649static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp)
6650{
6651 switch(task->tk_status) {
6652 case 0:
6653 case -NFS4ERR_COMPLETE_ALREADY:
6654 case -NFS4ERR_WRONG_CRED: /* What to do here? */
6655 break;
6656 case -NFS4ERR_DELAY:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04006657 rpc_delay(task, NFS4_POLL_RETRY_MAX);
Andy Adamsona8a4ae32011-05-03 13:43:03 -04006658 /* fall through */
6659 case -NFS4ERR_RETRY_UNCACHED_REP:
Trond Myklebustaa5190d2010-06-16 09:52:25 -04006660 return -EAGAIN;
6661 default:
Trond Myklebust0400a6b2011-03-09 16:00:53 -05006662 nfs4_schedule_lease_recovery(clp);
Trond Myklebustaa5190d2010-06-16 09:52:25 -04006663 }
6664 return 0;
6665}
6666
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006667static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
6668{
6669 struct nfs4_reclaim_complete_data *calldata = data;
6670 struct nfs_client *clp = calldata->clp;
6671 struct nfs4_sequence_res *res = &calldata->res.seq_res;
6672
6673 dprintk("--> %s\n", __func__);
Trond Myklebust14516c32010-07-31 14:29:06 -04006674 if (!nfs41_sequence_done(task, res))
6675 return;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006676
Trond Myklebustc6d01c62013-08-09 11:51:26 -04006677 trace_nfs4_reclaim_complete(clp, task->tk_status);
Trond Myklebustaa5190d2010-06-16 09:52:25 -04006678 if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) {
6679 rpc_restart_call_prepare(task);
6680 return;
6681 }
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006682 dprintk("<-- %s\n", __func__);
6683}
6684
6685static void nfs4_free_reclaim_complete_data(void *data)
6686{
6687 struct nfs4_reclaim_complete_data *calldata = data;
6688
6689 kfree(calldata);
6690}
6691
6692static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = {
6693 .rpc_call_prepare = nfs4_reclaim_complete_prepare,
6694 .rpc_call_done = nfs4_reclaim_complete_done,
6695 .rpc_release = nfs4_free_reclaim_complete_data,
6696};
6697
6698/*
6699 * Issue a global reclaim complete.
6700 */
Trond Myklebust965e9c22013-05-20 11:05:17 -04006701static int nfs41_proc_reclaim_complete(struct nfs_client *clp,
6702 struct rpc_cred *cred)
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006703{
6704 struct nfs4_reclaim_complete_data *calldata;
6705 struct rpc_task *task;
6706 struct rpc_message msg = {
6707 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE],
Trond Myklebust965e9c22013-05-20 11:05:17 -04006708 .rpc_cred = cred,
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006709 };
6710 struct rpc_task_setup task_setup_data = {
6711 .rpc_client = clp->cl_rpcclient,
6712 .rpc_message = &msg,
6713 .callback_ops = &nfs4_reclaim_complete_call_ops,
6714 .flags = RPC_TASK_ASYNC,
6715 };
6716 int status = -ENOMEM;
6717
6718 dprintk("--> %s\n", __func__);
Trond Myklebust8535b2b2010-05-13 12:51:01 -04006719 calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006720 if (calldata == NULL)
6721 goto out;
6722 calldata->clp = clp;
6723 calldata->arg.one_fs = 0;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006724
Chuck Levera9c92d62013-08-09 12:48:18 -04006725 nfs4_init_sequence(&calldata->arg.seq_args, &calldata->res.seq_res, 0);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04006726 nfs4_set_sequence_privileged(&calldata->arg.seq_args);
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006727 msg.rpc_argp = &calldata->arg;
6728 msg.rpc_resp = &calldata->res;
6729 task_setup_data.callback_data = calldata;
6730 task = rpc_run_task(&task_setup_data);
Dan Carpenteracf82b82010-04-22 11:28:39 +02006731 if (IS_ERR(task)) {
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006732 status = PTR_ERR(task);
Dan Carpenteracf82b82010-04-22 11:28:39 +02006733 goto out;
6734 }
Andy Adamsonc34c32e2011-03-09 13:13:46 -05006735 status = nfs4_wait_for_completion_rpc_task(task);
6736 if (status == 0)
6737 status = task->tk_status;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006738 rpc_put_task(task);
Dan Carpenteracf82b82010-04-22 11:28:39 +02006739 return 0;
Ricardo Labiagafce5c832009-12-05 16:08:41 -05006740out:
6741 dprintk("<-- %s status=%d\n", __func__, status);
6742 return status;
6743}
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006744
6745static void
6746nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
6747{
6748 struct nfs4_layoutget *lgp = calldata;
Fred Isamanc31663d2011-01-06 11:36:24 +00006749 struct nfs_server *server = NFS_SERVER(lgp->args.inode);
Trond Myklebust6ba7db32012-10-22 20:07:20 -04006750 struct nfs4_session *session = nfs4_get_session(server);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006751
6752 dprintk("--> %s\n", __func__);
Fred Isamanc31663d2011-01-06 11:36:24 +00006753 /* Note the is a race here, where a CB_LAYOUTRECALL can come in
6754 * right now covering the LAYOUTGET we are about to send.
6755 * However, that is not so catastrophic, and there seems
6756 * to be no way to prevent it completely.
6757 */
Trond Myklebust6ba7db32012-10-22 20:07:20 -04006758 if (nfs41_setup_sequence(session, &lgp->args.seq_args,
Trond Myklebust9d12b212012-01-17 22:04:25 -05006759 &lgp->res.seq_res, task))
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006760 return;
Fred Isamancf7d63f2011-01-06 11:36:25 +00006761 if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
6762 NFS_I(lgp->args.inode)->layout,
6763 lgp->args.ctx->state)) {
6764 rpc_exit(task, NFS4_OK);
Fred Isamancf7d63f2011-01-06 11:36:25 +00006765 }
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006766}
6767
6768static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
6769{
6770 struct nfs4_layoutget *lgp = calldata;
Trond Myklebustee314c22012-10-01 17:25:48 -07006771 struct inode *inode = lgp->args.inode;
6772 struct nfs_server *server = NFS_SERVER(inode);
6773 struct pnfs_layout_hdr *lo;
6774 struct nfs4_state *state = NULL;
Weston Andros Adamson30005122013-02-28 20:30:10 -05006775 unsigned long timeo, giveup;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006776
6777 dprintk("--> %s\n", __func__);
6778
Trond Myklebust6ba7db32012-10-22 20:07:20 -04006779 if (!nfs41_sequence_done(task, &lgp->res.seq_res))
Trond Myklebustee314c22012-10-01 17:25:48 -07006780 goto out;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006781
6782 switch (task->tk_status) {
6783 case 0:
Trond Myklebustee314c22012-10-01 17:25:48 -07006784 goto out;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006785 case -NFS4ERR_LAYOUTTRYLATER:
6786 case -NFS4ERR_RECALLCONFLICT:
Weston Andros Adamson30005122013-02-28 20:30:10 -05006787 timeo = rpc_get_timeout(task->tk_client);
6788 giveup = lgp->args.timestamp + timeo;
6789 if (time_after(giveup, jiffies))
6790 task->tk_status = -NFS4ERR_DELAY;
Trond Myklebustee314c22012-10-01 17:25:48 -07006791 break;
6792 case -NFS4ERR_EXPIRED:
6793 case -NFS4ERR_BAD_STATEID:
6794 spin_lock(&inode->i_lock);
6795 lo = NFS_I(inode)->layout;
6796 if (!lo || list_empty(&lo->plh_segs)) {
6797 spin_unlock(&inode->i_lock);
6798 /* If the open stateid was bad, then recover it. */
6799 state = lgp->args.ctx->state;
6800 } else {
6801 LIST_HEAD(head);
6802
6803 pnfs_mark_matching_lsegs_invalid(lo, &head, NULL);
6804 spin_unlock(&inode->i_lock);
6805 /* Mark the bad layout state as invalid, then
6806 * retry using the open stateid. */
6807 pnfs_free_lseg_list(&head);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006808 }
6809 }
Trond Myklebustee314c22012-10-01 17:25:48 -07006810 if (nfs4_async_handle_error(task, server, state) == -EAGAIN)
6811 rpc_restart_call_prepare(task);
6812out:
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006813 dprintk("<-- %s\n", __func__);
6814}
6815
Idan Kedar85541162012-08-02 11:47:10 +03006816static size_t max_response_pages(struct nfs_server *server)
6817{
6818 u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
6819 return nfs_page_array_len(0, max_resp_sz);
6820}
6821
6822static void nfs4_free_pages(struct page **pages, size_t size)
6823{
6824 int i;
6825
6826 if (!pages)
6827 return;
6828
6829 for (i = 0; i < size; i++) {
6830 if (!pages[i])
6831 break;
6832 __free_page(pages[i]);
6833 }
6834 kfree(pages);
6835}
6836
6837static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)
6838{
6839 struct page **pages;
6840 int i;
6841
6842 pages = kcalloc(size, sizeof(struct page *), gfp_flags);
6843 if (!pages) {
6844 dprintk("%s: can't alloc array of %zu pages\n", __func__, size);
6845 return NULL;
6846 }
6847
6848 for (i = 0; i < size; i++) {
6849 pages[i] = alloc_page(gfp_flags);
6850 if (!pages[i]) {
6851 dprintk("%s: failed to allocate page\n", __func__);
6852 nfs4_free_pages(pages, size);
6853 return NULL;
6854 }
6855 }
6856
6857 return pages;
6858}
6859
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006860static void nfs4_layoutget_release(void *calldata)
6861{
6862 struct nfs4_layoutget *lgp = calldata;
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05006863 struct inode *inode = lgp->args.inode;
6864 struct nfs_server *server = NFS_SERVER(inode);
Idan Kedar85541162012-08-02 11:47:10 +03006865 size_t max_pages = max_response_pages(server);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006866
6867 dprintk("--> %s\n", __func__);
Idan Kedar85541162012-08-02 11:47:10 +03006868 nfs4_free_pages(lgp->args.layout.pages, max_pages);
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05006869 pnfs_put_layout_hdr(NFS_I(inode)->layout);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006870 put_nfs_open_context(lgp->args.ctx);
6871 kfree(calldata);
6872 dprintk("<-- %s\n", __func__);
6873}
6874
6875static const struct rpc_call_ops nfs4_layoutget_call_ops = {
6876 .rpc_call_prepare = nfs4_layoutget_prepare,
6877 .rpc_call_done = nfs4_layoutget_done,
6878 .rpc_release = nfs4_layoutget_release,
6879};
6880
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04006881struct pnfs_layout_segment *
6882nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006883{
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05006884 struct inode *inode = lgp->args.inode;
6885 struct nfs_server *server = NFS_SERVER(inode);
Idan Kedar85541162012-08-02 11:47:10 +03006886 size_t max_pages = max_response_pages(server);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006887 struct rpc_task *task;
6888 struct rpc_message msg = {
6889 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
6890 .rpc_argp = &lgp->args,
6891 .rpc_resp = &lgp->res,
Trond Myklebust6ab59342013-05-20 10:49:34 -04006892 .rpc_cred = lgp->cred,
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006893 };
6894 struct rpc_task_setup task_setup_data = {
6895 .rpc_client = server->client,
6896 .rpc_message = &msg,
6897 .callback_ops = &nfs4_layoutget_call_ops,
6898 .callback_data = lgp,
6899 .flags = RPC_TASK_ASYNC,
6900 };
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04006901 struct pnfs_layout_segment *lseg = NULL;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006902 int status = 0;
6903
6904 dprintk("--> %s\n", __func__);
6905
Idan Kedar85541162012-08-02 11:47:10 +03006906 lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
6907 if (!lgp->args.layout.pages) {
6908 nfs4_layoutget_release(lgp);
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04006909 return ERR_PTR(-ENOMEM);
Idan Kedar85541162012-08-02 11:47:10 +03006910 }
6911 lgp->args.layout.pglen = max_pages * PAGE_SIZE;
Weston Andros Adamson30005122013-02-28 20:30:10 -05006912 lgp->args.timestamp = jiffies;
Idan Kedar85541162012-08-02 11:47:10 +03006913
Weston Andros Adamson35124a02011-03-24 16:48:21 -04006914 lgp->res.layoutp = &lgp->args.layout;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006915 lgp->res.seq_res.sr_slot = NULL;
Chuck Levera9c92d62013-08-09 12:48:18 -04006916 nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
Weston Andros Adamsona47970f2013-02-25 21:27:33 -05006917
6918 /* nfs4_layoutget_release calls pnfs_put_layout_hdr */
6919 pnfs_get_layout_hdr(NFS_I(inode)->layout);
6920
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006921 task = rpc_run_task(&task_setup_data);
6922 if (IS_ERR(task))
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04006923 return ERR_CAST(task);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006924 status = nfs4_wait_for_completion_rpc_task(task);
Fred Isamanc31663d2011-01-06 11:36:24 +00006925 if (status == 0)
6926 status = task->tk_status;
Trond Myklebust1037e6e2013-08-14 16:36:51 -04006927 trace_nfs4_layoutget(lgp->args.ctx,
6928 &lgp->args.range,
6929 &lgp->res.range,
6930 status);
Weston Andros Adamson085b7a42013-02-15 16:03:46 -05006931 /* if layoutp->len is 0, nfs4_layoutget_prepare called rpc_exit */
6932 if (status == 0 && lgp->res.layoutp->len)
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04006933 lseg = pnfs_layout_process(lgp);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006934 rpc_put_task(task);
6935 dprintk("<-- %s status=%d\n", __func__, status);
Trond Myklebusta0b0a6e2012-09-17 17:12:15 -04006936 if (status)
6937 return ERR_PTR(status);
6938 return lseg;
Andy Adamsonb1f69b72010-10-20 00:18:03 -04006939}
6940
Benny Halevycbe82602011-05-22 19:52:37 +03006941static void
6942nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
6943{
6944 struct nfs4_layoutreturn *lrp = calldata;
6945
6946 dprintk("--> %s\n", __func__);
Trond Myklebustd9afbd12012-10-22 20:28:44 -04006947 nfs41_setup_sequence(lrp->clp->cl_session,
6948 &lrp->args.seq_args,
6949 &lrp->res.seq_res,
6950 task);
Benny Halevycbe82602011-05-22 19:52:37 +03006951}
6952
6953static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
6954{
6955 struct nfs4_layoutreturn *lrp = calldata;
6956 struct nfs_server *server;
6957
6958 dprintk("--> %s\n", __func__);
6959
Trond Myklebust6ba7db32012-10-22 20:07:20 -04006960 if (!nfs41_sequence_done(task, &lrp->res.seq_res))
Benny Halevycbe82602011-05-22 19:52:37 +03006961 return;
6962
6963 server = NFS_SERVER(lrp->args.inode);
6964 if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
Trond Myklebustd00c5d42011-10-19 12:17:29 -07006965 rpc_restart_call_prepare(task);
Benny Halevycbe82602011-05-22 19:52:37 +03006966 return;
6967 }
Benny Halevycbe82602011-05-22 19:52:37 +03006968 dprintk("<-- %s\n", __func__);
6969}
6970
6971static void nfs4_layoutreturn_release(void *calldata)
6972{
6973 struct nfs4_layoutreturn *lrp = calldata;
Trond Myklebust849b2862012-09-24 14:18:39 -04006974 struct pnfs_layout_hdr *lo = lrp->args.layout;
Benny Halevycbe82602011-05-22 19:52:37 +03006975
6976 dprintk("--> %s\n", __func__);
Trond Myklebust849b2862012-09-24 14:18:39 -04006977 spin_lock(&lo->plh_inode->i_lock);
6978 if (lrp->res.lrs_present)
6979 pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
6980 lo->plh_block_lgets--;
6981 spin_unlock(&lo->plh_inode->i_lock);
Trond Myklebust70c3bd22012-09-18 20:51:13 -04006982 pnfs_put_layout_hdr(lrp->args.layout);
Benny Halevycbe82602011-05-22 19:52:37 +03006983 kfree(calldata);
6984 dprintk("<-- %s\n", __func__);
6985}
6986
6987static const struct rpc_call_ops nfs4_layoutreturn_call_ops = {
6988 .rpc_call_prepare = nfs4_layoutreturn_prepare,
6989 .rpc_call_done = nfs4_layoutreturn_done,
6990 .rpc_release = nfs4_layoutreturn_release,
6991};
6992
6993int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
6994{
6995 struct rpc_task *task;
6996 struct rpc_message msg = {
6997 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN],
6998 .rpc_argp = &lrp->args,
6999 .rpc_resp = &lrp->res,
Trond Myklebust95560002013-05-20 10:43:47 -04007000 .rpc_cred = lrp->cred,
Benny Halevycbe82602011-05-22 19:52:37 +03007001 };
7002 struct rpc_task_setup task_setup_data = {
Andy Adamson1771c572013-07-22 12:42:05 -04007003 .rpc_client = NFS_SERVER(lrp->args.inode)->client,
Benny Halevycbe82602011-05-22 19:52:37 +03007004 .rpc_message = &msg,
7005 .callback_ops = &nfs4_layoutreturn_call_ops,
7006 .callback_data = lrp,
7007 };
7008 int status;
7009
7010 dprintk("--> %s\n", __func__);
Chuck Levera9c92d62013-08-09 12:48:18 -04007011 nfs4_init_sequence(&lrp->args.seq_args, &lrp->res.seq_res, 1);
Benny Halevycbe82602011-05-22 19:52:37 +03007012 task = rpc_run_task(&task_setup_data);
7013 if (IS_ERR(task))
7014 return PTR_ERR(task);
7015 status = task->tk_status;
Trond Myklebust1037e6e2013-08-14 16:36:51 -04007016 trace_nfs4_layoutreturn(lrp->args.inode, status);
Benny Halevycbe82602011-05-22 19:52:37 +03007017 dprintk("<-- %s status=%d\n", __func__, status);
7018 rpc_put_task(task);
7019 return status;
7020}
7021
Andy Adamson7f11d8d2011-07-30 20:52:35 -04007022/*
7023 * Retrieve the list of Data Server devices from the MDS.
7024 */
7025static int _nfs4_getdevicelist(struct nfs_server *server,
7026 const struct nfs_fh *fh,
7027 struct pnfs_devicelist *devlist)
7028{
7029 struct nfs4_getdevicelist_args args = {
7030 .fh = fh,
7031 .layoutclass = server->pnfs_curr_ld->id,
7032 };
7033 struct nfs4_getdevicelist_res res = {
7034 .devlist = devlist,
7035 };
7036 struct rpc_message msg = {
7037 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICELIST],
7038 .rpc_argp = &args,
7039 .rpc_resp = &res,
7040 };
7041 int status;
7042
7043 dprintk("--> %s\n", __func__);
7044 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
7045 &res.seq_res, 0);
7046 dprintk("<-- %s status=%d\n", __func__, status);
7047 return status;
7048}
7049
7050int nfs4_proc_getdevicelist(struct nfs_server *server,
7051 const struct nfs_fh *fh,
7052 struct pnfs_devicelist *devlist)
7053{
7054 struct nfs4_exception exception = { };
7055 int err;
7056
7057 do {
7058 err = nfs4_handle_exception(server,
7059 _nfs4_getdevicelist(server, fh, devlist),
7060 &exception);
7061 } while (exception.retry);
7062
7063 dprintk("%s: err=%d, num_devs=%u\n", __func__,
7064 err, devlist->num_devs);
7065
7066 return err;
7067}
7068EXPORT_SYMBOL_GPL(nfs4_proc_getdevicelist);
7069
Andy Adamsonb1f69b72010-10-20 00:18:03 -04007070static int
Trond Myklebustcd5875f2013-05-20 11:42:54 -04007071_nfs4_proc_getdeviceinfo(struct nfs_server *server,
7072 struct pnfs_device *pdev,
7073 struct rpc_cred *cred)
Andy Adamsonb1f69b72010-10-20 00:18:03 -04007074{
7075 struct nfs4_getdeviceinfo_args args = {
7076 .pdev = pdev,
7077 };
7078 struct nfs4_getdeviceinfo_res res = {
7079 .pdev = pdev,
7080 };
7081 struct rpc_message msg = {
7082 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO],
7083 .rpc_argp = &args,
7084 .rpc_resp = &res,
Trond Myklebustcd5875f2013-05-20 11:42:54 -04007085 .rpc_cred = cred,
Andy Adamsonb1f69b72010-10-20 00:18:03 -04007086 };
7087 int status;
7088
7089 dprintk("--> %s\n", __func__);
Bryan Schumaker7c513052011-03-24 17:12:24 +00007090 status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
Andy Adamsonb1f69b72010-10-20 00:18:03 -04007091 dprintk("<-- %s status=%d\n", __func__, status);
7092
7093 return status;
7094}
7095
Trond Myklebustcd5875f2013-05-20 11:42:54 -04007096int nfs4_proc_getdeviceinfo(struct nfs_server *server,
7097 struct pnfs_device *pdev,
7098 struct rpc_cred *cred)
Andy Adamsonb1f69b72010-10-20 00:18:03 -04007099{
7100 struct nfs4_exception exception = { };
7101 int err;
7102
7103 do {
7104 err = nfs4_handle_exception(server,
Trond Myklebustcd5875f2013-05-20 11:42:54 -04007105 _nfs4_proc_getdeviceinfo(server, pdev, cred),
Andy Adamsonb1f69b72010-10-20 00:18:03 -04007106 &exception);
7107 } while (exception.retry);
7108 return err;
7109}
7110EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo);
7111
Andy Adamson863a3c62011-03-23 13:27:54 +00007112static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
7113{
7114 struct nfs4_layoutcommit_data *data = calldata;
7115 struct nfs_server *server = NFS_SERVER(data->args.inode);
Trond Myklebust6ba7db32012-10-22 20:07:20 -04007116 struct nfs4_session *session = nfs4_get_session(server);
Andy Adamson863a3c62011-03-23 13:27:54 +00007117
Trond Myklebustd9afbd12012-10-22 20:28:44 -04007118 nfs41_setup_sequence(session,
7119 &data->args.seq_args,
7120 &data->res.seq_res,
7121 task);
Andy Adamson863a3c62011-03-23 13:27:54 +00007122}
7123
7124static void
7125nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
7126{
7127 struct nfs4_layoutcommit_data *data = calldata;
7128 struct nfs_server *server = NFS_SERVER(data->args.inode);
7129
Trond Myklebust6ba7db32012-10-22 20:07:20 -04007130 if (!nfs41_sequence_done(task, &data->res.seq_res))
Andy Adamson863a3c62011-03-23 13:27:54 +00007131 return;
7132
7133 switch (task->tk_status) { /* Just ignore these failures */
Trond Myklebuste59d27e2012-03-27 18:22:19 -04007134 case -NFS4ERR_DELEG_REVOKED: /* layout was recalled */
7135 case -NFS4ERR_BADIOMODE: /* no IOMODE_RW layout for range */
7136 case -NFS4ERR_BADLAYOUT: /* no layout */
7137 case -NFS4ERR_GRACE: /* loca_recalim always false */
Andy Adamson863a3c62011-03-23 13:27:54 +00007138 task->tk_status = 0;
Trond Myklebuste59d27e2012-03-27 18:22:19 -04007139 break;
7140 case 0:
Andy Adamson863a3c62011-03-23 13:27:54 +00007141 nfs_post_op_update_inode_force_wcc(data->args.inode,
7142 data->res.fattr);
Trond Myklebuste59d27e2012-03-27 18:22:19 -04007143 break;
7144 default:
7145 if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
7146 rpc_restart_call_prepare(task);
7147 return;
7148 }
7149 }
Andy Adamson863a3c62011-03-23 13:27:54 +00007150}
7151
7152static void nfs4_layoutcommit_release(void *calldata)
7153{
7154 struct nfs4_layoutcommit_data *data = calldata;
7155
Andy Adamsondb29c082011-07-30 20:52:38 -04007156 pnfs_cleanup_layoutcommit(data);
Andy Adamson863a3c62011-03-23 13:27:54 +00007157 put_rpccred(data->cred);
7158 kfree(data);
7159}
7160
7161static const struct rpc_call_ops nfs4_layoutcommit_ops = {
7162 .rpc_call_prepare = nfs4_layoutcommit_prepare,
7163 .rpc_call_done = nfs4_layoutcommit_done,
7164 .rpc_release = nfs4_layoutcommit_release,
7165};
7166
7167int
Andy Adamsonef311532011-03-12 02:58:10 -05007168nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
Andy Adamson863a3c62011-03-23 13:27:54 +00007169{
7170 struct rpc_message msg = {
7171 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTCOMMIT],
7172 .rpc_argp = &data->args,
7173 .rpc_resp = &data->res,
7174 .rpc_cred = data->cred,
7175 };
7176 struct rpc_task_setup task_setup_data = {
7177 .task = &data->task,
7178 .rpc_client = NFS_CLIENT(data->args.inode),
7179 .rpc_message = &msg,
7180 .callback_ops = &nfs4_layoutcommit_ops,
7181 .callback_data = data,
7182 .flags = RPC_TASK_ASYNC,
7183 };
7184 struct rpc_task *task;
7185 int status = 0;
7186
7187 dprintk("NFS: %4d initiating layoutcommit call. sync %d "
7188 "lbw: %llu inode %lu\n",
7189 data->task.tk_pid, sync,
7190 data->args.lastbytewritten,
7191 data->args.inode->i_ino);
7192
Chuck Levera9c92d62013-08-09 12:48:18 -04007193 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
Andy Adamson863a3c62011-03-23 13:27:54 +00007194 task = rpc_run_task(&task_setup_data);
7195 if (IS_ERR(task))
7196 return PTR_ERR(task);
Andy Adamsonef311532011-03-12 02:58:10 -05007197 if (sync == false)
Andy Adamson863a3c62011-03-23 13:27:54 +00007198 goto out;
7199 status = nfs4_wait_for_completion_rpc_task(task);
7200 if (status != 0)
7201 goto out;
7202 status = task->tk_status;
Trond Myklebust1037e6e2013-08-14 16:36:51 -04007203 trace_nfs4_layoutcommit(data->args.inode, status);
Andy Adamson863a3c62011-03-23 13:27:54 +00007204out:
7205 dprintk("%s: status %d\n", __func__, status);
7206 rpc_put_task(task);
7207 return status;
7208}
Bryan Schumakerfca78d62011-06-02 14:59:07 -04007209
Andy Adamson97431202013-08-08 10:57:56 -04007210/**
7211 * Use the state managment nfs_client cl_rpcclient, which uses krb5i (if
7212 * possible) as per RFC3530bis and RFC5661 Security Considerations sections
7213 */
Bryan Schumakerfca78d62011-06-02 14:59:07 -04007214static int
7215_nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
7216 struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
7217{
7218 struct nfs41_secinfo_no_name_args args = {
7219 .style = SECINFO_STYLE_CURRENT_FH,
7220 };
7221 struct nfs4_secinfo_res res = {
7222 .flavors = flavors,
7223 };
7224 struct rpc_message msg = {
7225 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO_NO_NAME],
7226 .rpc_argp = &args,
7227 .rpc_resp = &res,
7228 };
Andy Adamson97431202013-08-08 10:57:56 -04007229 return nfs4_call_sync(server->nfs_client->cl_rpcclient, server, &msg,
7230 &args.seq_args, &res.seq_res, 0);
Bryan Schumakerfca78d62011-06-02 14:59:07 -04007231}
7232
7233static int
7234nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
7235 struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
7236{
7237 struct nfs4_exception exception = { };
7238 int err;
7239 do {
7240 err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
7241 switch (err) {
7242 case 0:
7243 case -NFS4ERR_WRONGSEC:
7244 case -NFS4ERR_NOTSUPP:
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04007245 goto out;
Bryan Schumakerfca78d62011-06-02 14:59:07 -04007246 default:
7247 err = nfs4_handle_exception(server, err, &exception);
7248 }
7249 } while (exception.retry);
Trond Myklebust05e9cfb2012-03-27 18:13:02 -04007250out:
Bryan Schumakerfca78d62011-06-02 14:59:07 -04007251 return err;
7252}
7253
7254static int
7255nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
7256 struct nfs_fsinfo *info)
7257{
7258 int err;
7259 struct page *page;
7260 rpc_authflavor_t flavor;
7261 struct nfs4_secinfo_flavors *flavors;
7262
7263 page = alloc_page(GFP_KERNEL);
7264 if (!page) {
7265 err = -ENOMEM;
7266 goto out;
7267 }
7268
7269 flavors = page_address(page);
7270 err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
7271
7272 /*
7273 * Fall back on "guess and check" method if
7274 * the server doesn't support SECINFO_NO_NAME
7275 */
7276 if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) {
7277 err = nfs4_find_root_sec(server, fhandle, info);
7278 goto out_freepage;
7279 }
7280 if (err)
7281 goto out_freepage;
7282
7283 flavor = nfs_find_best_sec(flavors);
7284 if (err == 0)
7285 err = nfs4_lookup_root_sec(server, fhandle, info, flavor);
7286
7287out_freepage:
7288 put_page(page);
7289 if (err == -EACCES)
7290 return -EPERM;
7291out:
7292 return err;
7293}
Bryan Schumaker1cab0652012-01-31 10:39:29 -05007294
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007295static int _nfs41_test_stateid(struct nfs_server *server,
7296 nfs4_stateid *stateid,
7297 struct rpc_cred *cred)
Bryan Schumaker7d974792011-06-02 14:59:08 -04007298{
7299 int status;
7300 struct nfs41_test_stateid_args args = {
Bryan Schumaker1cab0652012-01-31 10:39:29 -05007301 .stateid = stateid,
Bryan Schumaker7d974792011-06-02 14:59:08 -04007302 };
7303 struct nfs41_test_stateid_res res;
7304 struct rpc_message msg = {
7305 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID],
7306 .rpc_argp = &args,
7307 .rpc_resp = &res,
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007308 .rpc_cred = cred,
Bryan Schumaker7d974792011-06-02 14:59:08 -04007309 };
Bryan Schumaker1cab0652012-01-31 10:39:29 -05007310
Chuck Lever38527b12012-07-11 16:30:23 -04007311 dprintk("NFS call test_stateid %p\n", stateid);
Chuck Levera9c92d62013-08-09 12:48:18 -04007312 nfs4_init_sequence(&args.seq_args, &res.seq_res, 0);
Trond Myklebust8fe72ba2012-10-29 19:02:20 -04007313 nfs4_set_sequence_privileged(&args.seq_args);
7314 status = nfs4_call_sync_sequence(server->client, server, &msg,
7315 &args.seq_args, &res.seq_res);
Chuck Lever38527b12012-07-11 16:30:23 -04007316 if (status != NFS_OK) {
7317 dprintk("NFS reply test_stateid: failed, %d\n", status);
Chuck Lever377e5072012-07-11 16:29:45 -04007318 return status;
Chuck Lever38527b12012-07-11 16:30:23 -04007319 }
7320 dprintk("NFS reply test_stateid: succeeded, %d\n", -res.status);
Chuck Lever377e5072012-07-11 16:29:45 -04007321 return -res.status;
Bryan Schumaker7d974792011-06-02 14:59:08 -04007322}
7323
Chuck Lever38527b12012-07-11 16:30:23 -04007324/**
7325 * nfs41_test_stateid - perform a TEST_STATEID operation
7326 *
7327 * @server: server / transport on which to perform the operation
7328 * @stateid: state ID to test
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007329 * @cred: credential
Chuck Lever38527b12012-07-11 16:30:23 -04007330 *
7331 * Returns NFS_OK if the server recognizes that "stateid" is valid.
7332 * Otherwise a negative NFS4ERR value is returned if the operation
7333 * failed or the state ID is not currently valid.
7334 */
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007335static int nfs41_test_stateid(struct nfs_server *server,
7336 nfs4_stateid *stateid,
7337 struct rpc_cred *cred)
Bryan Schumaker7d974792011-06-02 14:59:08 -04007338{
7339 struct nfs4_exception exception = { };
7340 int err;
7341 do {
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007342 err = _nfs41_test_stateid(server, stateid, cred);
Chuck Lever377e5072012-07-11 16:29:45 -04007343 if (err != -NFS4ERR_DELAY)
7344 break;
7345 nfs4_handle_exception(server, err, &exception);
Bryan Schumaker7d974792011-06-02 14:59:08 -04007346 } while (exception.retry);
7347 return err;
7348}
Bryan Schumaker9aeda352011-06-02 14:59:09 -04007349
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04007350struct nfs_free_stateid_data {
7351 struct nfs_server *server;
7352 struct nfs41_free_stateid_args args;
Bryan Schumaker9aeda352011-06-02 14:59:09 -04007353 struct nfs41_free_stateid_res res;
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04007354};
7355
7356static void nfs41_free_stateid_prepare(struct rpc_task *task, void *calldata)
7357{
7358 struct nfs_free_stateid_data *data = calldata;
7359 nfs41_setup_sequence(nfs4_get_session(data->server),
7360 &data->args.seq_args,
7361 &data->res.seq_res,
7362 task);
7363}
7364
7365static void nfs41_free_stateid_done(struct rpc_task *task, void *calldata)
7366{
7367 struct nfs_free_stateid_data *data = calldata;
7368
7369 nfs41_sequence_done(task, &data->res.seq_res);
7370
7371 switch (task->tk_status) {
7372 case -NFS4ERR_DELAY:
7373 if (nfs4_async_handle_error(task, data->server, NULL) == -EAGAIN)
7374 rpc_restart_call_prepare(task);
7375 }
7376}
7377
7378static void nfs41_free_stateid_release(void *calldata)
7379{
7380 kfree(calldata);
7381}
7382
Trond Myklebust17f26b12013-08-21 15:48:42 -04007383static const struct rpc_call_ops nfs41_free_stateid_ops = {
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04007384 .rpc_call_prepare = nfs41_free_stateid_prepare,
7385 .rpc_call_done = nfs41_free_stateid_done,
7386 .rpc_release = nfs41_free_stateid_release,
7387};
7388
7389static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
7390 nfs4_stateid *stateid,
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007391 struct rpc_cred *cred,
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04007392 bool privileged)
7393{
Bryan Schumaker9aeda352011-06-02 14:59:09 -04007394 struct rpc_message msg = {
7395 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID],
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007396 .rpc_cred = cred,
Bryan Schumaker9aeda352011-06-02 14:59:09 -04007397 };
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04007398 struct rpc_task_setup task_setup = {
7399 .rpc_client = server->client,
7400 .rpc_message = &msg,
7401 .callback_ops = &nfs41_free_stateid_ops,
7402 .flags = RPC_TASK_ASYNC,
7403 };
7404 struct nfs_free_stateid_data *data;
Bryan Schumaker9aeda352011-06-02 14:59:09 -04007405
Chuck Lever38527b12012-07-11 16:30:23 -04007406 dprintk("NFS call free_stateid %p\n", stateid);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04007407 data = kmalloc(sizeof(*data), GFP_NOFS);
7408 if (!data)
7409 return ERR_PTR(-ENOMEM);
7410 data->server = server;
7411 nfs4_stateid_copy(&data->args.stateid, stateid);
7412
7413 task_setup.callback_data = data;
7414
7415 msg.rpc_argp = &data->args;
7416 msg.rpc_resp = &data->res;
Chuck Levera9c92d62013-08-09 12:48:18 -04007417 nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04007418 if (privileged)
7419 nfs4_set_sequence_privileged(&data->args.seq_args);
7420
7421 return rpc_run_task(&task_setup);
Bryan Schumaker9aeda352011-06-02 14:59:09 -04007422}
7423
Chuck Lever38527b12012-07-11 16:30:23 -04007424/**
7425 * nfs41_free_stateid - perform a FREE_STATEID operation
7426 *
7427 * @server: server / transport on which to perform the operation
7428 * @stateid: state ID to release
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007429 * @cred: credential
Chuck Lever38527b12012-07-11 16:30:23 -04007430 *
7431 * Returns NFS_OK if the server freed "stateid". Otherwise a
7432 * negative NFS4ERR value is returned.
7433 */
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007434static int nfs41_free_stateid(struct nfs_server *server,
7435 nfs4_stateid *stateid,
7436 struct rpc_cred *cred)
Bryan Schumaker9aeda352011-06-02 14:59:09 -04007437{
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04007438 struct rpc_task *task;
7439 int ret;
7440
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007441 task = _nfs41_free_stateid(server, stateid, cred, true);
Trond Myklebust7c1d5fa2013-05-03 14:40:01 -04007442 if (IS_ERR(task))
7443 return PTR_ERR(task);
7444 ret = rpc_wait_for_completion_task(task);
7445 if (!ret)
7446 ret = task->tk_status;
7447 rpc_put_task(task);
7448 return ret;
Bryan Schumaker9aeda352011-06-02 14:59:09 -04007449}
Trond Myklebust36281ca2012-03-04 18:13:56 -05007450
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04007451static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
7452{
7453 struct rpc_task *task;
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007454 struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04007455
Trond Myklebustab7cb0d2013-05-20 11:20:27 -04007456 task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false);
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04007457 nfs4_free_lock_state(server, lsp);
7458 if (IS_ERR(task))
7459 return PTR_ERR(task);
7460 rpc_put_task(task);
7461 return 0;
7462}
7463
Trond Myklebust36281ca2012-03-04 18:13:56 -05007464static bool nfs41_match_stateid(const nfs4_stateid *s1,
7465 const nfs4_stateid *s2)
7466{
Trond Myklebust2d2f24a2012-03-04 18:13:57 -05007467 if (memcmp(s1->other, s2->other, sizeof(s1->other)) != 0)
Trond Myklebust36281ca2012-03-04 18:13:56 -05007468 return false;
7469
Trond Myklebust2d2f24a2012-03-04 18:13:57 -05007470 if (s1->seqid == s2->seqid)
Trond Myklebust36281ca2012-03-04 18:13:56 -05007471 return true;
Trond Myklebust2d2f24a2012-03-04 18:13:57 -05007472 if (s1->seqid == 0 || s2->seqid == 0)
Trond Myklebust36281ca2012-03-04 18:13:56 -05007473 return true;
7474
7475 return false;
7476}
7477
Andy Adamson557134a2009-04-01 09:21:53 -04007478#endif /* CONFIG_NFS_V4_1 */
7479
Trond Myklebust36281ca2012-03-04 18:13:56 -05007480static bool nfs4_match_stateid(const nfs4_stateid *s1,
7481 const nfs4_stateid *s2)
7482{
Trond Myklebustf597c532012-03-04 18:13:56 -05007483 return nfs4_stateid_match(s1, s2);
Trond Myklebust36281ca2012-03-04 18:13:56 -05007484}
7485
7486
Trond Myklebust17280172012-03-11 13:11:00 -04007487static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
Trond Myklebust7eff03a2008-12-23 15:21:43 -05007488 .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
Trond Myklebustb79a4a12008-12-23 15:21:41 -05007489 .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007490 .recover_open = nfs4_open_reclaim,
7491 .recover_lock = nfs4_lock_reclaim,
Andy Adamson591d71c2009-04-01 09:22:47 -04007492 .establish_clid = nfs4_init_clientid,
Chuck Lever05f4c352012-09-14 17:24:32 -04007493 .detect_trunking = nfs40_discover_server_trunking,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007494};
7495
Andy Adamson591d71c2009-04-01 09:22:47 -04007496#if defined(CONFIG_NFS_V4_1)
Trond Myklebust17280172012-03-11 13:11:00 -04007497static const struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
Andy Adamson591d71c2009-04-01 09:22:47 -04007498 .owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
7499 .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
7500 .recover_open = nfs4_open_reclaim,
7501 .recover_lock = nfs4_lock_reclaim,
Andy Adamson4d643d12009-12-04 15:52:24 -05007502 .establish_clid = nfs41_init_clientid,
Ricardo Labiagafce5c832009-12-05 16:08:41 -05007503 .reclaim_complete = nfs41_proc_reclaim_complete,
Chuck Lever05f4c352012-09-14 17:24:32 -04007504 .detect_trunking = nfs41_discover_server_trunking,
Andy Adamson591d71c2009-04-01 09:22:47 -04007505};
7506#endif /* CONFIG_NFS_V4_1 */
7507
Trond Myklebust17280172012-03-11 13:11:00 -04007508static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
Trond Myklebust7eff03a2008-12-23 15:21:43 -05007509 .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
Trond Myklebustb79a4a12008-12-23 15:21:41 -05007510 .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007511 .recover_open = nfs4_open_expired,
7512 .recover_lock = nfs4_lock_expired,
Andy Adamson591d71c2009-04-01 09:22:47 -04007513 .establish_clid = nfs4_init_clientid,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007514};
7515
Andy Adamson591d71c2009-04-01 09:22:47 -04007516#if defined(CONFIG_NFS_V4_1)
Trond Myklebust17280172012-03-11 13:11:00 -04007517static const struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
Andy Adamson591d71c2009-04-01 09:22:47 -04007518 .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
7519 .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
Bryan Schumakerf062eb62011-06-02 14:59:10 -04007520 .recover_open = nfs41_open_expired,
7521 .recover_lock = nfs41_lock_expired,
Andy Adamson4d643d12009-12-04 15:52:24 -05007522 .establish_clid = nfs41_init_clientid,
Andy Adamson591d71c2009-04-01 09:22:47 -04007523};
7524#endif /* CONFIG_NFS_V4_1 */
7525
Trond Myklebust17280172012-03-11 13:11:00 -04007526static const struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
Benny Halevy29fba382009-04-01 09:22:44 -04007527 .sched_state_renewal = nfs4_proc_async_renew,
Andy Adamsona7b72102009-04-01 09:22:46 -04007528 .get_state_renewal_cred_locked = nfs4_get_renew_cred_locked,
Benny Halevy8e69514f2009-04-01 09:22:45 -04007529 .renew_lease = nfs4_proc_renew,
Benny Halevy29fba382009-04-01 09:22:44 -04007530};
7531
7532#if defined(CONFIG_NFS_V4_1)
Trond Myklebust17280172012-03-11 13:11:00 -04007533static const struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
Benny Halevy29fba382009-04-01 09:22:44 -04007534 .sched_state_renewal = nfs41_proc_async_sequence,
Andy Adamsona7b72102009-04-01 09:22:46 -04007535 .get_state_renewal_cred_locked = nfs4_get_machine_cred_locked,
Benny Halevy8e69514f2009-04-01 09:22:45 -04007536 .renew_lease = nfs4_proc_sequence,
Benny Halevy29fba382009-04-01 09:22:44 -04007537};
7538#endif
7539
Trond Myklebust97dc1352010-06-16 09:52:26 -04007540static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
7541 .minor_version = 0,
Trond Myklebust39c6daa2013-03-15 16:11:57 -04007542 .init_caps = NFS_CAP_READDIRPLUS
7543 | NFS_CAP_ATOMIC_OPEN
7544 | NFS_CAP_CHANGE_ATTR
7545 | NFS_CAP_POSIX_LOCK,
Trond Myklebust97dc1352010-06-16 09:52:26 -04007546 .call_sync = _nfs4_call_sync,
Trond Myklebust36281ca2012-03-04 18:13:56 -05007547 .match_stateid = nfs4_match_stateid,
Bryan Schumakerfca78d62011-06-02 14:59:07 -04007548 .find_root_sec = nfs4_find_root_sec,
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04007549 .free_lock_state = nfs4_release_lockowner,
Chuck Lever9915ea72013-08-09 12:48:27 -04007550 .call_sync_ops = &nfs40_call_sync_ops,
Trond Myklebustc48f4f32010-06-16 09:52:27 -04007551 .reboot_recovery_ops = &nfs40_reboot_recovery_ops,
7552 .nograce_recovery_ops = &nfs40_nograce_recovery_ops,
7553 .state_renewal_ops = &nfs40_state_renewal_ops,
Trond Myklebust97dc1352010-06-16 09:52:26 -04007554};
7555
7556#if defined(CONFIG_NFS_V4_1)
7557static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
7558 .minor_version = 1,
Trond Myklebust39c6daa2013-03-15 16:11:57 -04007559 .init_caps = NFS_CAP_READDIRPLUS
7560 | NFS_CAP_ATOMIC_OPEN
7561 | NFS_CAP_CHANGE_ATTR
Trond Myklebust3b664862013-03-17 15:31:15 -04007562 | NFS_CAP_POSIX_LOCK
Trond Myklebust49f9a0f2013-03-15 16:44:28 -04007563 | NFS_CAP_STATEID_NFSV41
7564 | NFS_CAP_ATOMIC_OPEN_V1,
Bryan Schumaker104287c2012-11-12 14:13:13 -05007565 .call_sync = nfs4_call_sync_sequence,
Trond Myklebust36281ca2012-03-04 18:13:56 -05007566 .match_stateid = nfs41_match_stateid,
Bryan Schumakerfca78d62011-06-02 14:59:07 -04007567 .find_root_sec = nfs41_find_root_sec,
Trond Myklebustc8b2d0b2013-05-03 16:22:55 -04007568 .free_lock_state = nfs41_free_lock_state,
Chuck Lever9915ea72013-08-09 12:48:27 -04007569 .call_sync_ops = &nfs41_call_sync_ops,
Trond Myklebustc48f4f32010-06-16 09:52:27 -04007570 .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
7571 .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
7572 .state_renewal_ops = &nfs41_state_renewal_ops,
Trond Myklebust97dc1352010-06-16 09:52:26 -04007573};
7574#endif
7575
Steve Dickson42c2c422013-05-22 12:50:38 -04007576#if defined(CONFIG_NFS_V4_2)
7577static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
7578 .minor_version = 2,
Bryan Schumaker70173102013-06-19 13:41:43 -04007579 .init_caps = NFS_CAP_READDIRPLUS
7580 | NFS_CAP_ATOMIC_OPEN
7581 | NFS_CAP_CHANGE_ATTR
7582 | NFS_CAP_POSIX_LOCK
7583 | NFS_CAP_STATEID_NFSV41
7584 | NFS_CAP_ATOMIC_OPEN_V1,
Steve Dickson42c2c422013-05-22 12:50:38 -04007585 .call_sync = nfs4_call_sync_sequence,
7586 .match_stateid = nfs41_match_stateid,
7587 .find_root_sec = nfs41_find_root_sec,
Bryan Schumaker70173102013-06-19 13:41:43 -04007588 .free_lock_state = nfs41_free_lock_state,
Chuck Lever9915ea72013-08-09 12:48:27 -04007589 .call_sync_ops = &nfs41_call_sync_ops,
Steve Dickson42c2c422013-05-22 12:50:38 -04007590 .reboot_recovery_ops = &nfs41_reboot_recovery_ops,
7591 .nograce_recovery_ops = &nfs41_nograce_recovery_ops,
7592 .state_renewal_ops = &nfs41_state_renewal_ops,
7593};
7594#endif
7595
Trond Myklebust97dc1352010-06-16 09:52:26 -04007596const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
7597 [0] = &nfs_v4_0_minor_ops,
7598#if defined(CONFIG_NFS_V4_1)
7599 [1] = &nfs_v4_1_minor_ops,
7600#endif
Steve Dickson42c2c422013-05-22 12:50:38 -04007601#if defined(CONFIG_NFS_V4_2)
7602 [2] = &nfs_v4_2_minor_ops,
7603#endif
Trond Myklebust97dc1352010-06-16 09:52:26 -04007604};
7605
Trond Myklebust17f26b12013-08-21 15:48:42 -04007606static const struct inode_operations nfs4_dir_inode_operations = {
Bryan Schumaker73a79702012-07-16 16:39:12 -04007607 .create = nfs_create,
7608 .lookup = nfs_lookup,
7609 .atomic_open = nfs_atomic_open,
7610 .link = nfs_link,
7611 .unlink = nfs_unlink,
7612 .symlink = nfs_symlink,
7613 .mkdir = nfs_mkdir,
7614 .rmdir = nfs_rmdir,
7615 .mknod = nfs_mknod,
7616 .rename = nfs_rename,
7617 .permission = nfs_permission,
7618 .getattr = nfs_getattr,
7619 .setattr = nfs_setattr,
7620 .getxattr = generic_getxattr,
7621 .setxattr = generic_setxattr,
7622 .listxattr = generic_listxattr,
7623 .removexattr = generic_removexattr,
7624};
7625
Arjan van de Ven92e1d5b2007-02-12 00:55:39 -08007626static const struct inode_operations nfs4_file_inode_operations = {
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007627 .permission = nfs_permission,
7628 .getattr = nfs_getattr,
7629 .setattr = nfs_setattr,
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00007630 .getxattr = generic_getxattr,
7631 .setxattr = generic_setxattr,
7632 .listxattr = generic_listxattr,
7633 .removexattr = generic_removexattr,
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007634};
7635
David Howells509de812006-08-22 20:06:11 -04007636const struct nfs_rpc_ops nfs_v4_clientops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07007637 .version = 4, /* protocol version */
7638 .dentry_ops = &nfs4_dentry_operations,
7639 .dir_inode_ops = &nfs4_dir_inode_operations,
J. Bruce Fields6b3b5492005-06-22 17:16:22 +00007640 .file_inode_ops = &nfs4_file_inode_operations,
Jeff Layton1788ea62011-11-04 13:31:21 -04007641 .file_ops = &nfs4_file_operations,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007642 .getroot = nfs4_proc_get_root,
Bryan Schumaker281cad42012-04-27 13:27:45 -04007643 .submount = nfs4_submount,
Bryan Schumakerff9099f22012-07-30 16:05:18 -04007644 .try_mount = nfs4_try_mount,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007645 .getattr = nfs4_proc_getattr,
7646 .setattr = nfs4_proc_setattr,
7647 .lookup = nfs4_proc_lookup,
7648 .access = nfs4_proc_access,
7649 .readlink = nfs4_proc_readlink,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007650 .create = nfs4_proc_create,
7651 .remove = nfs4_proc_remove,
7652 .unlink_setup = nfs4_proc_unlink_setup,
Bryan Schumaker34e137c2012-03-19 14:54:41 -04007653 .unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007654 .unlink_done = nfs4_proc_unlink_done,
7655 .rename = nfs4_proc_rename,
Jeff Laytond3d41522010-09-17 17:31:57 -04007656 .rename_setup = nfs4_proc_rename_setup,
Bryan Schumakerc6bfa1a2012-03-19 14:54:42 -04007657 .rename_rpc_prepare = nfs4_proc_rename_rpc_prepare,
Jeff Laytond3d41522010-09-17 17:31:57 -04007658 .rename_done = nfs4_proc_rename_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007659 .link = nfs4_proc_link,
7660 .symlink = nfs4_proc_symlink,
7661 .mkdir = nfs4_proc_mkdir,
7662 .rmdir = nfs4_proc_remove,
7663 .readdir = nfs4_proc_readdir,
7664 .mknod = nfs4_proc_mknod,
7665 .statfs = nfs4_proc_statfs,
7666 .fsinfo = nfs4_proc_fsinfo,
7667 .pathconf = nfs4_proc_pathconf,
David Howellse9326dc2006-08-22 20:06:10 -04007668 .set_capabilities = nfs4_server_capabilities,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007669 .decode_dirent = nfs4_decode_dirent,
7670 .read_setup = nfs4_proc_read_setup,
Bryan Schumaker1abb50882012-06-20 15:53:47 -04007671 .read_pageio_init = pnfs_pageio_init_read,
Bryan Schumakerea7c3302012-03-19 14:54:40 -04007672 .read_rpc_prepare = nfs4_proc_read_rpc_prepare,
Trond Myklebustec06c092006-03-20 13:44:27 -05007673 .read_done = nfs4_read_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007674 .write_setup = nfs4_proc_write_setup,
Bryan Schumaker57208fa2012-06-20 15:53:48 -04007675 .write_pageio_init = pnfs_pageio_init_write,
Bryan Schumakerc6cb80d2012-03-19 14:54:39 -04007676 .write_rpc_prepare = nfs4_proc_write_rpc_prepare,
Trond Myklebust788e7a82006-03-20 13:44:27 -05007677 .write_done = nfs4_write_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007678 .commit_setup = nfs4_proc_commit_setup,
Fred Isaman0b7c0152012-04-20 14:47:39 -04007679 .commit_rpc_prepare = nfs4_proc_commit_rpc_prepare,
Trond Myklebust788e7a82006-03-20 13:44:27 -05007680 .commit_done = nfs4_commit_done,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007681 .lock = nfs4_proc_lock,
J. Bruce Fieldse50a1c22005-06-22 17:16:23 +00007682 .clear_acl_cache = nfs4_zap_acl_attr,
Trond Myklebust7fe5c392009-03-19 15:35:50 -04007683 .close_context = nfs4_close_context,
Trond Myklebust2b484292010-09-17 10:56:51 -04007684 .open_context = nfs4_atomic_open,
Bryan Schumaker011e2a72012-06-20 15:53:43 -04007685 .have_delegation = nfs4_have_delegation,
Bryan Schumaker57ec14c2012-06-20 15:53:44 -04007686 .return_delegation = nfs4_inode_return_delegation,
Bryan Schumaker6663ee72012-06-20 15:53:46 -04007687 .alloc_client = nfs4_alloc_client,
Andy Adamson45a52a02011-03-01 01:34:08 +00007688 .init_client = nfs4_init_client,
Bryan Schumakercdb7ece2012-06-20 15:53:45 -04007689 .free_client = nfs4_free_client,
Bryan Schumaker1179acc2012-07-30 16:05:19 -04007690 .create_server = nfs4_create_server,
7691 .clone_server = nfs_clone_server,
Linus Torvalds1da177e2005-04-16 15:20:36 -07007692};
7693
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00007694static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
7695 .prefix = XATTR_NAME_NFSV4_ACL,
7696 .list = nfs4_xattr_list_nfs4_acl,
7697 .get = nfs4_xattr_get_nfs4_acl,
7698 .set = nfs4_xattr_set_nfs4_acl,
7699};
7700
7701const struct xattr_handler *nfs4_xattr_handlers[] = {
7702 &nfs4_xattr_nfs4_acl_handler,
David Quigleyc9bccef2013-05-22 12:50:45 -04007703#ifdef CONFIG_NFS_V4_SECURITY_LABEL
7704 &nfs4_xattr_nfs4_label_handler,
7705#endif
Aneesh Kumar K.V64c2ce82010-12-09 11:35:25 +00007706 NULL
7707};
7708
Linus Torvalds1da177e2005-04-16 15:20:36 -07007709/*
7710 * Local variables:
7711 * c-basic-offset: 8
7712 * End:
7713 */