Blame view

fs/nfs/nfs4proc.c 169 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  /*
   *  fs/nfs/nfs4proc.c
   *
   *  Client-side procedure declarations for NFSv4.
   *
   *  Copyright (c) 2002 The Regents of the University of Michigan.
   *  All rights reserved.
   *
   *  Kendrick Smith <kmsmith@umich.edu>
   *  Andy Adamson   <andros@umich.edu>
   *
   *  Redistribution and use in source and binary forms, with or without
   *  modification, are permitted provided that the following conditions
   *  are met:
   *
   *  1. Redistributions of source code must retain the above copyright
   *     notice, this list of conditions and the following disclaimer.
   *  2. Redistributions in binary form must reproduce the above copyright
   *     notice, this list of conditions and the following disclaimer in the
   *     documentation and/or other materials provided with the distribution.
   *  3. Neither the name of the University nor the names of its
   *     contributors may be used to endorse or promote products derived
   *     from this software without specific prior written permission.
   *
   *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
   *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
   *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
   *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
  #include <linux/delay.h>
  #include <linux/errno.h>
  #include <linux/string.h>
652f89f64   Trond Myklebust   NFSv4: Do not acc...
42
43
  #include <linux/ratelimit.h>
  #include <linux/printk.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
44
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  #include <linux/sunrpc/clnt.h>
8f70e95f9   Bryan Schumaker   NFS: Determine in...
46
  #include <linux/sunrpc/gss_api.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
  #include <linux/nfs.h>
  #include <linux/nfs4.h>
  #include <linux/nfs_fs.h>
  #include <linux/nfs_page.h>
9b7160c55   Bryan Schumaker   NFS: don't negoti...
51
  #include <linux/nfs_mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  #include <linux/namei.h>
02a913a73   Trond Myklebust   NFSv4: Eliminate ...
53
  #include <linux/mount.h>
99fe60d06   Benny Halevy   nfs41: exchange_i...
54
  #include <linux/module.h>
6926afd19   Trond Myklebust   NFSv4: Save the o...
55
  #include <linux/nfs_idmap.h>
5a0ffe544   Andy Adamson   nfs41: Release ba...
56
  #include <linux/sunrpc/bc_xprt.h>
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
57
  #include <linux/xattr.h>
c7a360b05   Andy Adamson   NFS construct con...
58
  #include <linux/utsname.h>
d310310cb   Jeff Layton   Freezer / sunrpc ...
59
  #include <linux/freezer.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60

4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
61
  #include "nfs4_fs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  #include "delegation.h"
101070ca2   Trond Myklebust   NFS: Ensure that ...
63
  #include "internal.h"
006ea73e5   Chuck Lever   NFS: add hooks to...
64
  #include "iostat.h"
fc931582c   Andy Adamson   nfs41: create_ses...
65
  #include "callback.h"
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
66
  #include "pnfs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  
  #define NFSDBG_FACILITY		NFSDBG_PROC
2066fe89b   Trond Myklebust   NFSv4: Poll more ...
69
  #define NFS4_POLL_RETRY_MIN	(HZ/10)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  #define NFS4_POLL_RETRY_MAX	(15*HZ)
a78cb57a1   Trond Myklebust   NFSv4: Don't loop...
71
  #define NFS4_MAX_LOOP_ON_RECOVER (10)
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
72
  struct nfs4_opendata;
864472e9b   Trond Myklebust   NFSv4: Make open ...
73
  static int _nfs4_proc_open(struct nfs4_opendata *data);
b257957e5   Alexandros Batsakis   nfs: make recover...
74
  static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
9e33bed55   Trond Myklebust   NFSv4: Add recove...
76
  static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *);
9936781d0   Trond Myklebust   NFSv4: Try to rec...
77
  static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr);
0ab64e0e1   Trond Myklebust   NFS: Reduce stack...
78
79
80
  static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
  			    struct nfs_fattr *fattr, struct iattr *sattr,
  			    struct nfs4_state *state);
f062eb6ce   Bryan Schumaker   NFS: test and fre...
81
82
83
84
  #ifdef CONFIG_NFS_V4_1
  static int nfs41_test_stateid(struct nfs_server *, struct nfs4_state *);
  static int nfs41_free_stateid(struct nfs_server *, struct nfs4_state *);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
  /* Prevent leaks of NFSv4 errors into userland */
46f72f57d   WANG Cong   fs/nfs/nfs4proc.c...
86
  static int nfs4_map_errors(int err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
  {
52567b03c   Trond Myklebust   NFSv4: Fix a bug ...
88
89
90
91
92
  	if (err >= -1000)
  		return err;
  	switch (err) {
  	case -NFS4ERR_RESOURCE:
  		return -EREMOTEIO;
7ebb93159   Bryan Schumaker   NFS: use secinfo ...
93
94
  	case -NFS4ERR_WRONGSEC:
  		return -EPERM;
3ddeb7c5c   Trond Myklebust   NFSv4: Propagate ...
95
96
97
  	case -NFS4ERR_BADOWNER:
  	case -NFS4ERR_BADNAME:
  		return -EINVAL;
52567b03c   Trond Myklebust   NFSv4: Fix a bug ...
98
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
  		dprintk("%s could not handle NFSv4 error %d
  ",
3110ff804   Harvey Harrison   nfs: replace rema...
101
  				__func__, -err);
52567b03c   Trond Myklebust   NFSv4: Fix a bug ...
102
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  	}
52567b03c   Trond Myklebust   NFSv4: Fix a bug ...
104
  	return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  }
  
  /*
   * This is our standard bitmap for GETATTR requests.
   */
  const u32 nfs4_fattr_bitmap[2] = {
  	FATTR4_WORD0_TYPE
  	| FATTR4_WORD0_CHANGE
  	| FATTR4_WORD0_SIZE
  	| FATTR4_WORD0_FSID
  	| FATTR4_WORD0_FILEID,
  	FATTR4_WORD1_MODE
  	| FATTR4_WORD1_NUMLINKS
  	| FATTR4_WORD1_OWNER
  	| FATTR4_WORD1_OWNER_GROUP
  	| FATTR4_WORD1_RAWDEV
  	| FATTR4_WORD1_SPACE_USED
  	| FATTR4_WORD1_TIME_ACCESS
  	| FATTR4_WORD1_TIME_METADATA
  	| FATTR4_WORD1_TIME_MODIFY
  };
  
  const u32 nfs4_statfs_bitmap[2] = {
  	FATTR4_WORD0_FILES_AVAIL
  	| FATTR4_WORD0_FILES_FREE
  	| FATTR4_WORD0_FILES_TOTAL,
  	FATTR4_WORD1_SPACE_AVAIL
  	| FATTR4_WORD1_SPACE_FREE
  	| FATTR4_WORD1_SPACE_TOTAL
  };
4ce79717c   Trond Myklebust   [PATCH] NFS: Head...
135
  const u32 nfs4_pathconf_bitmap[2] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
138
139
  	FATTR4_WORD0_MAXLINK
  	| FATTR4_WORD0_MAXNAME,
  	0
  };
dae100c2b   Fred Isaman   pnfs: ask for lay...
140
  const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
  			| FATTR4_WORD0_MAXREAD
  			| FATTR4_WORD0_MAXWRITE
  			| FATTR4_WORD0_LEASE_TIME,
55b6e7742   Ricardo Labiaga   Ask for time_delt...
144
  			FATTR4_WORD1_TIME_DELTA
dae100c2b   Fred Isaman   pnfs: ask for lay...
145
146
  			| FATTR4_WORD1_FS_LAYOUT_TYPES,
  			FATTR4_WORD2_LAYOUT_BLKSIZE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  };
830b8e33f   Manoj Naik   NFSv4: Define an ...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
  const u32 nfs4_fs_locations_bitmap[2] = {
  	FATTR4_WORD0_TYPE
  	| FATTR4_WORD0_CHANGE
  	| FATTR4_WORD0_SIZE
  	| FATTR4_WORD0_FSID
  	| FATTR4_WORD0_FILEID
  	| FATTR4_WORD0_FS_LOCATIONS,
  	FATTR4_WORD1_MODE
  	| FATTR4_WORD1_NUMLINKS
  	| FATTR4_WORD1_OWNER
  	| FATTR4_WORD1_OWNER_GROUP
  	| FATTR4_WORD1_RAWDEV
  	| FATTR4_WORD1_SPACE_USED
  	| FATTR4_WORD1_TIME_ACCESS
  	| FATTR4_WORD1_TIME_METADATA
  	| FATTR4_WORD1_TIME_MODIFY
  	| FATTR4_WORD1_MOUNTED_ON_FILEID
  };
bc4785cd4   Al Viro   [PATCH] nfs: veri...
166
  static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
  		struct nfs4_readdir_arg *readdir)
  {
0dbb4c679   Al Viro   [PATCH] xdr annot...
169
  	__be32 *start, *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
  
  	BUG_ON(readdir->count < 80);
  	if (cookie > 2) {
b7ef19560   Adrian Bunk   [PATCH] NFSv4: fs...
173
  		readdir->cookie = cookie;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
  		memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));
  		return;
  	}
  
  	readdir->cookie = 0;
  	memset(&readdir->verifier, 0, sizeof(readdir->verifier));
  	if (cookie == 2)
  		return;
  	
  	/*
  	 * NFSv4 servers do not return entries for '.' and '..'
  	 * Therefore, we fake these entries here.  We let '.'
  	 * have cookie 0 and '..' have cookie 1.  Note that
  	 * when talking to the server, we always send cookie 0
  	 * instead of 1 or 2.
  	 */
0dbb4c679   Al Viro   [PATCH] xdr annot...
190
  	start = p = kmap_atomic(*readdir->pages, KM_USER0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
193
194
195
196
197
198
199
200
201
  	
  	if (cookie == 0) {
  		*p++ = xdr_one;                                  /* next */
  		*p++ = xdr_zero;                   /* cookie, first word */
  		*p++ = xdr_one;                   /* cookie, second word */
  		*p++ = xdr_one;                             /* entry len */
  		memcpy(p, ".\0\0\0", 4);                        /* entry */
  		p++;
  		*p++ = xdr_one;                         /* bitmap length */
  		*p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
  		*p++ = htonl(8);              /* attribute buffer length */
4e769b934   Peter Staubach   64 bit ino suppor...
202
  		p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_inode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
208
209
210
211
212
213
  	}
  	
  	*p++ = xdr_one;                                  /* next */
  	*p++ = xdr_zero;                   /* cookie, first word */
  	*p++ = xdr_two;                   /* cookie, second word */
  	*p++ = xdr_two;                             /* entry len */
  	memcpy(p, "..\0\0", 4);                         /* entry */
  	p++;
  	*p++ = xdr_one;                         /* bitmap length */
  	*p++ = htonl(FATTR4_WORD0_FILEID);             /* bitmap */
  	*p++ = htonl(8);              /* attribute buffer length */
4e769b934   Peter Staubach   64 bit ino suppor...
214
  	p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
216
217
218
219
  
  	readdir->pgbase = (char *)p - (char *)start;
  	readdir->count -= readdir->pgbase;
  	kunmap_atomic(start, KM_USER0);
  }
65de872ed   Trond Myklebust   NFS: Remove the u...
220
221
222
223
224
  static int nfs4_wait_clnt_recover(struct nfs_client *clp)
  {
  	int res;
  
  	might_sleep();
e005e8041   Trond Myklebust   NFSv4: Rename the...
225
  	res = wait_on_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING,
72cb77f4a   Trond Myklebust   NFS: Throttle pag...
226
  			nfs_wait_bit_killable, TASK_KILLABLE);
65de872ed   Trond Myklebust   NFS: Remove the u...
227
228
229
230
231
232
233
234
235
236
237
238
239
  	return res;
  }
  
  static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
  {
  	int res = 0;
  
  	might_sleep();
  
  	if (*timeout <= 0)
  		*timeout = NFS4_POLL_RETRY_MIN;
  	if (*timeout > NFS4_POLL_RETRY_MAX)
  		*timeout = NFS4_POLL_RETRY_MAX;
d310310cb   Jeff Layton   Freezer / sunrpc ...
240
  	freezable_schedule_timeout_killable(*timeout);
65de872ed   Trond Myklebust   NFS: Remove the u...
241
242
243
244
245
246
247
248
249
  	if (fatal_signal_pending(current))
  		res = -ERESTARTSYS;
  	*timeout <<= 1;
  	return res;
  }
  
  /* This is the error handling routine for processes that are allowed
   * to sleep.
   */
b064eca2c   Trond Myklebust   NFSv4: Send unmap...
250
  static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
65de872ed   Trond Myklebust   NFS: Remove the u...
251
252
  {
  	struct nfs_client *clp = server->nfs_client;
9e33bed55   Trond Myklebust   NFSv4: Add recove...
253
  	struct nfs4_state *state = exception->state;
65de872ed   Trond Myklebust   NFS: Remove the u...
254
255
256
257
258
259
  	int ret = errorcode;
  
  	exception->retry = 0;
  	switch(errorcode) {
  		case 0:
  			return 0;
9e33bed55   Trond Myklebust   NFSv4: Add recove...
260
261
262
263
264
  		case -NFS4ERR_ADMIN_REVOKED:
  		case -NFS4ERR_BAD_STATEID:
  		case -NFS4ERR_OPENMODE:
  			if (state == NULL)
  				break;
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
265
266
  			nfs4_schedule_stateid_recovery(server, state);
  			goto wait_on_recovery;
0ced63d1a   Trond Myklebust   NFSv4: Handle exp...
267
268
269
  		case -NFS4ERR_EXPIRED:
  			if (state != NULL)
  				nfs4_schedule_stateid_recovery(server, state);
65de872ed   Trond Myklebust   NFS: Remove the u...
270
  		case -NFS4ERR_STALE_STATEID:
a2c0b9e29   Trond Myklebust   NFS: Ensure that ...
271
  		case -NFS4ERR_STALE_CLIENTID:
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
272
273
  			nfs4_schedule_lease_recovery(clp);
  			goto wait_on_recovery;
03391693a   Trond Myklebust   NFSv4.1: Don't ca...
274
  #if defined(CONFIG_NFS_V4_1)
4745e3154   Andy Adamson   nfs41: kick start...
275
276
277
278
279
280
281
282
283
284
  		case -NFS4ERR_BADSESSION:
  		case -NFS4ERR_BADSLOT:
  		case -NFS4ERR_BAD_HIGH_SLOT:
  		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
  		case -NFS4ERR_DEADSESSION:
  		case -NFS4ERR_SEQ_FALSE_RETRY:
  		case -NFS4ERR_SEQ_MISORDERED:
  			dprintk("%s ERROR: %d Reset session
  ", __func__,
  				errorcode);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
285
  			nfs4_schedule_session_recovery(clp->cl_session);
4745e3154   Andy Adamson   nfs41: kick start...
286
  			exception->retry = 1;
b9179237e   Andy Adamson   nfs41: fix switch...
287
  			break;
03391693a   Trond Myklebust   NFSv4.1: Don't ca...
288
  #endif /* defined(CONFIG_NFS_V4_1) */
65de872ed   Trond Myklebust   NFS: Remove the u...
289
  		case -NFS4ERR_FILE_OPEN:
44ed3556b   NeilBrown   NFS4ERR_FILE_OPEN...
290
291
292
293
294
295
296
  			if (exception->timeout > HZ) {
  				/* We have retried a decent amount, time to
  				 * fail
  				 */
  				ret = -EBUSY;
  				break;
  			}
65de872ed   Trond Myklebust   NFS: Remove the u...
297
298
  		case -NFS4ERR_GRACE:
  		case -NFS4ERR_DELAY:
2c6434888   Jeff Layton   nfs4: handle -EKE...
299
  		case -EKEYEXPIRED:
65de872ed   Trond Myklebust   NFS: Remove the u...
300
301
302
  			ret = nfs4_delay(server->client, &exception->timeout);
  			if (ret != 0)
  				break;
a8a4ae3a8   Andy Adamson   NFSv41: Resend on...
303
  		case -NFS4ERR_RETRY_UNCACHED_REP:
65de872ed   Trond Myklebust   NFS: Remove the u...
304
305
  		case -NFS4ERR_OLD_STATEID:
  			exception->retry = 1;
b064eca2c   Trond Myklebust   NFSv4: Send unmap...
306
307
308
309
310
311
312
313
314
315
316
317
318
319
  			break;
  		case -NFS4ERR_BADOWNER:
  			/* The following works around a Linux server bug! */
  		case -NFS4ERR_BADNAME:
  			if (server->caps & NFS_CAP_UIDGID_NOMAP) {
  				server->caps &= ~NFS_CAP_UIDGID_NOMAP;
  				exception->retry = 1;
  				printk(KERN_WARNING "NFS: v4 server %s "
  						"does not accept raw "
  						"uid/gids. "
  						"Reenabling the idmapper.
  ",
  						server->nfs_client->cl_hostname);
  			}
65de872ed   Trond Myklebust   NFS: Remove the u...
320
321
322
  	}
  	/* We failed to handle the error */
  	return nfs4_map_errors(ret);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
323
  wait_on_recovery:
a2c0b9e29   Trond Myklebust   NFS: Ensure that ...
324
325
326
327
  	ret = nfs4_wait_clnt_recover(clp);
  	if (ret == 0)
  		exception->retry = 1;
  	return ret;
65de872ed   Trond Myklebust   NFS: Remove the u...
328
  }
452e93523   Trond Myklebust   NFSv4: Clean up t...
329
  static void do_renew_lease(struct nfs_client *clp, unsigned long timestamp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
335
  	spin_lock(&clp->cl_lock);
  	if (time_before(clp->cl_last_renewal,timestamp))
  		clp->cl_last_renewal = timestamp;
  	spin_unlock(&clp->cl_lock);
  }
452e93523   Trond Myklebust   NFSv4: Clean up t...
336
337
338
339
  static void renew_lease(const struct nfs_server *server, unsigned long timestamp)
  {
  	do_renew_lease(server->nfs_client, timestamp);
  }
cccef3b96   Andy Adamson   nfs41: introduce ...
340
  #if defined(CONFIG_NFS_V4_1)
510b81756   Benny Halevy   nfs41: find slot
341
  /*
e2c4ab3ce   Andy Adamson   nfs41: free slot
342
343
344
345
346
347
348
349
350
351
352
   * nfs4_free_slot - free a slot and efficiently update slot table.
   *
   * freeing a slot is trivially done by clearing its respective bit
   * in the bitmap.
   * If the freed slotid equals highest_used_slotid we want to update it
   * so that the server would be able to size down the slot table if needed,
   * otherwise we know that the highest_used_slotid is still in use.
   * When updating highest_used_slotid there may be "holes" in the bitmap
   * so we need to scan down from highest_used_slotid to 0 looking for the now
   * highest slotid in use.
   * If none found, highest_used_slotid is set to -1.
35dc1d74a   Trond Myklebust   NFSv41: Fix up so...
353
354
   *
   * Must be called while holding tbl->slot_tbl_lock
e2c4ab3ce   Andy Adamson   nfs41: free slot
355
356
   */
  static void
aabd0b40b   Andy Adamson   NFSv4.1: change n...
357
  nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
e2c4ab3ce   Andy Adamson   nfs41: free slot
358
359
  {
  	int slotid = free_slotid;
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
360
  	BUG_ON(slotid < 0 || slotid >= NFS4_MAX_SLOT_TABLE);
e2c4ab3ce   Andy Adamson   nfs41: free slot
361
362
363
364
365
366
  	/* clear used bit in bitmap */
  	__clear_bit(slotid, tbl->used_slots);
  
  	/* update highest_used_slotid when it is freed */
  	if (slotid == tbl->highest_used_slotid) {
  		slotid = find_last_bit(tbl->used_slots, tbl->max_slots);
bcb56164c   Trond Myklebust   NFSv41: More clea...
367
  		if (slotid < tbl->max_slots)
e2c4ab3ce   Andy Adamson   nfs41: free slot
368
369
370
371
  			tbl->highest_used_slotid = slotid;
  		else
  			tbl->highest_used_slotid = -1;
  	}
e2c4ab3ce   Andy Adamson   nfs41: free slot
372
373
374
375
  	dprintk("%s: free_slotid %u highest_used_slotid %d
  ", __func__,
  		free_slotid, tbl->highest_used_slotid);
  }
3bfb0fc59   Alexandros Batsakis   nfs: minor cleanu...
376
  /*
42acd0218   Andy Adamson   NFS add session b...
377
   * Signal state manager thread if session fore channel is drained
3bfb0fc59   Alexandros Batsakis   nfs: minor cleanu...
378
   */
42acd0218   Andy Adamson   NFS add session b...
379
  static void nfs4_check_drain_fc_complete(struct nfs4_session *ses)
3bfb0fc59   Alexandros Batsakis   nfs: minor cleanu...
380
  {
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
381
  	struct rpc_task *task;
a2118c33a   Trond Myklebust   NFSv41: Don't sto...
382
  	if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
383
384
385
  		task = rpc_wake_up_next(&ses->fc_slot_table.slot_tbl_waitq);
  		if (task)
  			rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
3bfb0fc59   Alexandros Batsakis   nfs: minor cleanu...
386
387
388
389
390
  		return;
  	}
  
  	if (ses->fc_slot_table.highest_used_slotid != -1)
  		return;
42acd0218   Andy Adamson   NFS add session b...
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
  	dprintk("%s COMPLETE: Session Fore Channel Drained
  ", __func__);
  	complete(&ses->fc_slot_table.complete);
  }
  
  /*
   * Signal state manager thread if session back channel is drained
   */
  void nfs4_check_drain_bc_complete(struct nfs4_session *ses)
  {
  	if (!test_bit(NFS4_SESSION_DRAINING, &ses->session_state) ||
  	    ses->bc_slot_table.highest_used_slotid != -1)
  		return;
  	dprintk("%s COMPLETE: Session Back Channel Drained
  ", __func__);
  	complete(&ses->bc_slot_table.complete);
3bfb0fc59   Alexandros Batsakis   nfs: minor cleanu...
407
  }
d185a334c   Trond Myklebust   NFSv4.1: Simplify...
408
  static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
13615871c   Andy Adamson   nfs41: nfs41_sequ...
409
410
  {
  	struct nfs4_slot_table *tbl;
d185a334c   Trond Myklebust   NFSv4.1: Simplify...
411
  	tbl = &res->sr_session->fc_slot_table;
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
412
  	if (!res->sr_slot) {
13615871c   Andy Adamson   nfs41: nfs41_sequ...
413
414
  		/* just wake up the next guy waiting since
  		 * we may have not consumed a slot after all */
691daf3b0   Andy Adamson   nfs41: drain sess...
415
416
  		dprintk("%s: No slot
  ", __func__);
35dc1d74a   Trond Myklebust   NFSv41: Fix up so...
417
  		return;
13615871c   Andy Adamson   nfs41: nfs41_sequ...
418
  	}
ea028ac92   Andy Adamson   nfs41: nfs41: fix...
419

35dc1d74a   Trond Myklebust   NFSv41: Fix up so...
420
  	spin_lock(&tbl->slot_tbl_lock);
aabd0b40b   Andy Adamson   NFSv4.1: change n...
421
  	nfs4_free_slot(tbl, res->sr_slot - tbl->slots);
42acd0218   Andy Adamson   NFS add session b...
422
  	nfs4_check_drain_fc_complete(res->sr_session);
35dc1d74a   Trond Myklebust   NFSv41: Fix up so...
423
  	spin_unlock(&tbl->slot_tbl_lock);
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
424
  	res->sr_slot = NULL;
13615871c   Andy Adamson   nfs41: nfs41_sequ...
425
  }
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
426
  static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
b0df806c0   Andy Adamson   nfs41: nfs41_sequ...
427
428
  {
  	unsigned long timestamp;
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
429
  	struct nfs_client *clp;
b0df806c0   Andy Adamson   nfs41: nfs41_sequ...
430
431
432
433
434
435
436
437
438
  
  	/*
  	 * sr_status remains 1 if an RPC level error occurred. The server
  	 * may or may not have processed the sequence operation..
  	 * Proceed as if the server received and processed the sequence
  	 * operation.
  	 */
  	if (res->sr_status == 1)
  		res->sr_status = NFS_OK;
468f86134   Bryan Schumaker   NFSv4.1: Don't up...
439
440
  	/* don't increment the sequence number if the task wasn't sent */
  	if (!RPC_WAS_SENT(task))
b0df806c0   Andy Adamson   nfs41: nfs41_sequ...
441
  		goto out;
691daf3b0   Andy Adamson   nfs41: drain sess...
442
  	/* Check the SEQUENCE operation status */
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
443
444
  	switch (res->sr_status) {
  	case 0:
b0df806c0   Andy Adamson   nfs41: nfs41_sequ...
445
  		/* Update the slot's sequence and clientid lease timer */
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
446
  		++res->sr_slot->seq_nr;
b0df806c0   Andy Adamson   nfs41: nfs41_sequ...
447
  		timestamp = res->sr_renewal_time;
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
448
  		clp = res->sr_session->clp;
452e93523   Trond Myklebust   NFSv4: Clean up t...
449
  		do_renew_lease(clp, timestamp);
0629e370d   Alexandros Batsakis   nfs41: check SEQU...
450
  		/* Check sequence flags */
b4410c2f7   Trond Myklebust   NFSv4.1: Fix the ...
451
452
  		if (res->sr_status_flags != 0)
  			nfs4_schedule_lease_recovery(clp);
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
453
454
455
456
457
458
  		break;
  	case -NFS4ERR_DELAY:
  		/* The server detected a resend of the RPC call and
  		 * returned NFS4ERR_DELAY as per Section 2.10.6.2
  		 * of RFC5661.
  		 */
12364a4f0   Geert Uytterhoeven   nfs4: The differe...
459
460
  		dprintk("%s: slot=%td seq=%d: Operation in progress
  ",
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
461
462
463
  			__func__,
  			res->sr_slot - res->sr_session->fc_slot_table.slots,
  			res->sr_slot->seq_nr);
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
464
465
466
  		goto out_retry;
  	default:
  		/* Just update the slot sequence no. */
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
467
  		++res->sr_slot->seq_nr;
b0df806c0   Andy Adamson   nfs41: nfs41_sequ...
468
469
470
471
472
  	}
  out:
  	/* The session may be reset by one of the error handlers. */
  	dprintk("%s: Error %d free the slot 
  ", __func__, res->sr_status);
d185a334c   Trond Myklebust   NFSv4.1: Simplify...
473
  	nfs41_sequence_free_slot(res);
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
474
475
  	return 1;
  out_retry:
d05dd4e98   Trond Myklebust   NFS: Fix the NFS ...
476
  	if (!rpc_restart_call(task))
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
477
478
479
  		goto out;
  	rpc_delay(task, NFS4_POLL_RETRY_MAX);
  	return 0;
b0df806c0   Andy Adamson   nfs41: nfs41_sequ...
480
  }
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
481
482
  static int nfs4_sequence_done(struct rpc_task *task,
  			       struct nfs4_sequence_res *res)
df8964554   Trond Myklebust   NFSv41: Further c...
483
  {
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
484
485
486
  	if (res->sr_session == NULL)
  		return 1;
  	return nfs41_sequence_done(task, res);
df8964554   Trond Myklebust   NFSv41: Further c...
487
  }
e2c4ab3ce   Andy Adamson   nfs41: free slot
488
  /*
510b81756   Benny Halevy   nfs41: find slot
489
490
491
492
493
494
   * nfs4_find_slot - efficiently look for a free slot
   *
   * nfs4_find_slot looks for an unset bit in the used_slots bitmap.
   * If found, we mark the slot as used, update the highest_used_slotid,
   * and respectively set up the sequence operation args.
   * The slot number is returned if found, or NFS4_MAX_SLOT_TABLE otherwise.
fbcd4abcb   Andy Adamson   nfs41: setup_sequ...
495
496
   *
   * Note: must be called with under the slot_tbl_lock.
510b81756   Benny Halevy   nfs41: find slot
497
498
   */
  static u8
40ead580a   Alexandros Batsakis   nfs: remove rpc_t...
499
  nfs4_find_slot(struct nfs4_slot_table *tbl)
510b81756   Benny Halevy   nfs41: find slot
500
501
502
503
  {
  	int slotid;
  	u8 ret_id = NFS4_MAX_SLOT_TABLE;
  	BUILD_BUG_ON((u8)NFS4_MAX_SLOT_TABLE != (int)NFS4_MAX_SLOT_TABLE);
510b81756   Benny Halevy   nfs41: find slot
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
  	dprintk("--> %s used_slots=%04lx highest_used=%d max_slots=%d
  ",
  		__func__, tbl->used_slots[0], tbl->highest_used_slotid,
  		tbl->max_slots);
  	slotid = find_first_zero_bit(tbl->used_slots, tbl->max_slots);
  	if (slotid >= tbl->max_slots)
  		goto out;
  	__set_bit(slotid, tbl->used_slots);
  	if (slotid > tbl->highest_used_slotid)
  		tbl->highest_used_slotid = slotid;
  	ret_id = slotid;
  out:
  	dprintk("<-- %s used_slots=%04lx highest_used=%d slotid=%d 
  ",
  		__func__, tbl->used_slots[0], tbl->highest_used_slotid, ret_id);
510b81756   Benny Halevy   nfs41: find slot
519
520
  	return ret_id;
  }
dc70d7b31   Andy Adamson   NFSv4.1: filelayo...
521
  int nfs41_setup_sequence(struct nfs4_session *session,
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
522
523
524
525
526
  				struct nfs4_sequence_args *args,
  				struct nfs4_sequence_res *res,
  				int cache_reply,
  				struct rpc_task *task)
  {
fbcd4abcb   Andy Adamson   nfs41: setup_sequ...
527
528
529
530
531
532
  	struct nfs4_slot *slot;
  	struct nfs4_slot_table *tbl;
  	u8 slotid;
  
  	dprintk("--> %s
  ", __func__);
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
533
  	/* slot already allocated? */
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
534
  	if (res->sr_slot != NULL)
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
535
  		return 0;
fbcd4abcb   Andy Adamson   nfs41: setup_sequ...
536
537
538
  	tbl = &session->fc_slot_table;
  
  	spin_lock(&tbl->slot_tbl_lock);
a2118c33a   Trond Myklebust   NFSv41: Don't sto...
539
  	if (test_bit(NFS4_SESSION_DRAINING, &session->session_state) &&
5601a00d6   Alexandros Batsakis   nfs: run state ma...
540
  	    !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
0b1c8fc43   Andy Adamson   NFSv4.1: cleanup ...
541
  		/* The state manager will wait until the slot table is empty */
05f0d2364   Andy Adamson   nfs41: remove nfs...
542
  		rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
b069d94af   Andy Adamson   nfs41: schedule a...
543
  		spin_unlock(&tbl->slot_tbl_lock);
0b1c8fc43   Andy Adamson   NFSv4.1: cleanup ...
544
545
  		dprintk("%s session is draining
  ", __func__);
05f0d2364   Andy Adamson   nfs41: remove nfs...
546
  		return -EAGAIN;
b069d94af   Andy Adamson   nfs41: schedule a...
547
  	}
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
548
549
550
551
552
553
554
555
  	if (!rpc_queue_empty(&tbl->slot_tbl_waitq) &&
  	    !rpc_task_has_priority(task, RPC_PRIORITY_PRIVILEGED)) {
  		rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
  		spin_unlock(&tbl->slot_tbl_lock);
  		dprintk("%s enforce FIFO order
  ", __func__);
  		return -EAGAIN;
  	}
40ead580a   Alexandros Batsakis   nfs: remove rpc_t...
556
  	slotid = nfs4_find_slot(tbl);
fbcd4abcb   Andy Adamson   nfs41: setup_sequ...
557
558
559
560
561
562
563
564
  	if (slotid == NFS4_MAX_SLOT_TABLE) {
  		rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
  		spin_unlock(&tbl->slot_tbl_lock);
  		dprintk("<-- %s: no free slots
  ", __func__);
  		return -EAGAIN;
  	}
  	spin_unlock(&tbl->slot_tbl_lock);
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
565
  	rpc_task_set_priority(task, RPC_PRIORITY_NORMAL);
fbcd4abcb   Andy Adamson   nfs41: setup_sequ...
566
  	slot = tbl->slots + slotid;
99fe60d06   Benny Halevy   nfs41: exchange_i...
567
  	args->sa_session = session;
fbcd4abcb   Andy Adamson   nfs41: setup_sequ...
568
569
570
571
572
  	args->sa_slotid = slotid;
  	args->sa_cache_this = cache_reply;
  
  	dprintk("<-- %s slotid=%d seqid=%d
  ", __func__, slotid, slot->seq_nr);
99fe60d06   Benny Halevy   nfs41: exchange_i...
573
  	res->sr_session = session;
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
574
  	res->sr_slot = slot;
fbcd4abcb   Andy Adamson   nfs41: setup_sequ...
575
  	res->sr_renewal_time = jiffies;
2a6e26cdb   Trond Myklebust   NFSv4.1: Clean up...
576
  	res->sr_status_flags = 0;
fbcd4abcb   Andy Adamson   nfs41: setup_sequ...
577
578
579
580
581
  	/*
  	 * sr_status is only set in decode_sequence, and so will remain
  	 * set to 1 if an rpc level failure occurs.
  	 */
  	res->sr_status = 1;
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
582
583
  	return 0;
  }
dc70d7b31   Andy Adamson   NFSv4.1: filelayo...
584
  EXPORT_SYMBOL_GPL(nfs41_setup_sequence);
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
585

035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
586
  int nfs4_setup_sequence(const struct nfs_server *server,
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
587
588
589
590
591
  			struct nfs4_sequence_args *args,
  			struct nfs4_sequence_res *res,
  			int cache_reply,
  			struct rpc_task *task)
  {
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
592
  	struct nfs4_session *session = nfs4_get_session(server);
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
593
  	int ret = 0;
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
594
595
596
597
598
  	if (session == NULL) {
  		args->sa_session = NULL;
  		res->sr_session = NULL;
  		goto out;
  	}
12364a4f0   Geert Uytterhoeven   nfs4: The differe...
599
600
  	dprintk("--> %s clp %p session %p sr_slot %td
  ",
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
601
602
  		__func__, session->clp, session, res->sr_slot ?
  			res->sr_slot - session->fc_slot_table.slots : -1);
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
603

035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
604
  	ret = nfs41_setup_sequence(session, args, res, cache_reply,
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
605
  				   task);
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
606
607
608
609
610
611
612
  out:
  	dprintk("<-- %s status=%d
  ", __func__, ret);
  	return ret;
  }
  
  struct nfs41_call_sync_data {
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
613
  	const struct nfs_server *seq_server;
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
614
615
616
617
618
619
620
621
  	struct nfs4_sequence_args *seq_args;
  	struct nfs4_sequence_res *seq_res;
  	int cache_reply;
  };
  
  static void nfs41_call_sync_prepare(struct rpc_task *task, void *calldata)
  {
  	struct nfs41_call_sync_data *data = calldata;
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
622
623
624
625
  	dprintk("--> %s data->seq_server %p
  ", __func__, data->seq_server);
  
  	if (nfs4_setup_sequence(data->seq_server, data->seq_args,
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
626
627
628
629
  				data->seq_res, data->cache_reply, task))
  		return;
  	rpc_call_start(task);
  }
b257957e5   Alexandros Batsakis   nfs: make recover...
630
631
632
633
634
  static void nfs41_call_priv_sync_prepare(struct rpc_task *task, void *calldata)
  {
  	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
  	nfs41_call_sync_prepare(task, calldata);
  }
69ab40c4c   Andy Adamson   nfs41: nfs41_call...
635
636
637
  static void nfs41_call_sync_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs41_call_sync_data *data = calldata;
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
638
  	nfs41_sequence_done(task, data->seq_res);
69ab40c4c   Andy Adamson   nfs41: nfs41_call...
639
  }
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
640
641
  struct rpc_call_ops nfs41_call_sync_ops = {
  	.rpc_call_prepare = nfs41_call_sync_prepare,
69ab40c4c   Andy Adamson   nfs41: nfs41_call...
642
  	.rpc_call_done = nfs41_call_sync_done,
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
643
  };
b257957e5   Alexandros Batsakis   nfs: make recover...
644
645
646
647
  struct rpc_call_ops nfs41_call_priv_sync_ops = {
  	.rpc_call_prepare = nfs41_call_priv_sync_prepare,
  	.rpc_call_done = nfs41_call_sync_done,
  };
7c5130588   Bryan Schumaker   NFS: lookup suppo...
648
649
  static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
  				   struct nfs_server *server,
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
650
651
652
  				   struct rpc_message *msg,
  				   struct nfs4_sequence_args *args,
  				   struct nfs4_sequence_res *res,
b257957e5   Alexandros Batsakis   nfs: make recover...
653
654
  				   int cache_reply,
  				   int privileged)
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
655
656
657
658
  {
  	int ret;
  	struct rpc_task *task;
  	struct nfs41_call_sync_data data = {
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
659
  		.seq_server = server,
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
660
661
662
663
664
  		.seq_args = args,
  		.seq_res = res,
  		.cache_reply = cache_reply,
  	};
  	struct rpc_task_setup task_setup = {
7c5130588   Bryan Schumaker   NFS: lookup suppo...
665
  		.rpc_client = clnt,
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
666
667
668
669
  		.rpc_message = msg,
  		.callback_ops = &nfs41_call_sync_ops,
  		.callback_data = &data
  	};
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
670
  	res->sr_slot = NULL;
b257957e5   Alexandros Batsakis   nfs: make recover...
671
672
  	if (privileged)
  		task_setup.callback_ops = &nfs41_call_priv_sync_ops;
ce5039c1b   Andy Adamson   nfs41: nfs4_setup...
673
674
675
676
677
678
679
680
681
  	task = rpc_run_task(&task_setup);
  	if (IS_ERR(task))
  		ret = PTR_ERR(task);
  	else {
  		ret = task->tk_status;
  		rpc_put_task(task);
  	}
  	return ret;
  }
7c5130588   Bryan Schumaker   NFS: lookup suppo...
682
683
  int _nfs4_call_sync_session(struct rpc_clnt *clnt,
  			    struct nfs_server *server,
cccef3b96   Andy Adamson   nfs41: introduce ...
684
685
686
687
688
  			    struct rpc_message *msg,
  			    struct nfs4_sequence_args *args,
  			    struct nfs4_sequence_res *res,
  			    int cache_reply)
  {
7c5130588   Bryan Schumaker   NFS: lookup suppo...
689
  	return nfs4_call_sync_sequence(clnt, server, msg, args, res, cache_reply, 0);
cccef3b96   Andy Adamson   nfs41: introduce ...
690
  }
df8964554   Trond Myklebust   NFSv41: Further c...
691
  #else
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
692
693
  static int nfs4_sequence_done(struct rpc_task *task,
  			       struct nfs4_sequence_res *res)
df8964554   Trond Myklebust   NFSv41: Further c...
694
  {
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
695
  	return 1;
df8964554   Trond Myklebust   NFSv41: Further c...
696
  }
cccef3b96   Andy Adamson   nfs41: introduce ...
697
  #endif /* CONFIG_NFS_V4_1 */
7c5130588   Bryan Schumaker   NFS: lookup suppo...
698
699
  int _nfs4_call_sync(struct rpc_clnt *clnt,
  		    struct nfs_server *server,
cccef3b96   Andy Adamson   nfs41: introduce ...
700
701
702
703
704
  		    struct rpc_message *msg,
  		    struct nfs4_sequence_args *args,
  		    struct nfs4_sequence_res *res,
  		    int cache_reply)
  {
f3752975c   Benny Halevy   nfs41: nfs41: pas...
705
  	args->sa_session = res->sr_session = NULL;
7c5130588   Bryan Schumaker   NFS: lookup suppo...
706
  	return rpc_call_sync(clnt, msg, 0);
cccef3b96   Andy Adamson   nfs41: introduce ...
707
  }
e73b83f27   Bryan Schumaker   NFS: convert call...
708
  static inline
7c5130588   Bryan Schumaker   NFS: lookup suppo...
709
710
  int nfs4_call_sync(struct rpc_clnt *clnt,
  		   struct nfs_server *server,
e73b83f27   Bryan Schumaker   NFS: convert call...
711
712
713
714
715
  		   struct rpc_message *msg,
  		   struct nfs4_sequence_args *args,
  		   struct nfs4_sequence_res *res,
  		   int cache_reply)
  {
7c5130588   Bryan Schumaker   NFS: lookup suppo...
716
717
  	return server->nfs_client->cl_mvops->call_sync(clnt, server, msg,
  						args, res, cache_reply);
e73b83f27   Bryan Schumaker   NFS: convert call...
718
  }
cccef3b96   Andy Adamson   nfs41: introduce ...
719

38478b24e   Trond Myklebust   NFS: More page ca...
720
  static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
721
  {
38478b24e   Trond Myklebust   NFS: More page ca...
722
  	struct nfs_inode *nfsi = NFS_I(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723

38478b24e   Trond Myklebust   NFS: More page ca...
724
  	spin_lock(&dir->i_lock);
40d247040   Trond Myklebust   NFS: Fix a connec...
725
  	nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_DATA;
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
726
  	if (!cinfo->atomic || cinfo->before != dir->i_version)
bfc69a456   Trond Myklebust   NFS: define a fun...
727
  		nfs_force_lookup_revalidate(dir);
a9a4a87a5   Trond Myklebust   NFS: Use the inod...
728
  	dir->i_version = cinfo->after;
38478b24e   Trond Myklebust   NFS: More page ca...
729
  	spin_unlock(&dir->i_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  }
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
731
  struct nfs4_opendata {
c6d00e639   Trond Myklebust   NFSv4: Convert st...
732
  	struct kref kref;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
733
734
  	struct nfs_openargs o_arg;
  	struct nfs_openres o_res;
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
735
736
  	struct nfs_open_confirmargs c_arg;
  	struct nfs_open_confirmres c_res;
6926afd19   Trond Myklebust   NFSv4: Save the o...
737
738
  	struct nfs4_string owner_name;
  	struct nfs4_string group_name;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
739
740
  	struct nfs_fattr f_attr;
  	struct nfs_fattr dir_attr;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
741
  	struct dentry *dir;
82a2c1b77   Al Viro   nfs4_opendata doe...
742
  	struct dentry *dentry;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
743
  	struct nfs4_state_owner *owner;
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
744
  	struct nfs4_state *state;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
745
  	struct iattr attrs;
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
746
  	unsigned long timestamp;
3e309914a   Trond Myklebust   NFSv4: Clean up _...
747
  	unsigned int rpc_done : 1;
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
748
749
  	int rpc_status;
  	int cancelled;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
750
  };
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
751
752
753
754
755
  
  static void nfs4_init_opendata_res(struct nfs4_opendata *p)
  {
  	p->o_res.f_attr = &p->f_attr;
  	p->o_res.dir_attr = &p->dir_attr;
c1d519312   Trond Myklebust   NFSv4: Only incre...
756
757
  	p->o_res.seqid = p->o_arg.seqid;
  	p->c_res.seqid = p->c_arg.seqid;
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
758
759
760
  	p->o_res.server = p->o_arg.server;
  	nfs_fattr_init(&p->f_attr);
  	nfs_fattr_init(&p->dir_attr);
6926afd19   Trond Myklebust   NFSv4: Save the o...
761
  	nfs_fattr_init_names(&p->f_attr, &p->owner_name, &p->group_name);
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
762
  }
82a2c1b77   Al Viro   nfs4_opendata doe...
763
  static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
dc0b027df   Trond Myklebust   NFSv4: Convert th...
764
  		struct nfs4_state_owner *sp, fmode_t fmode, int flags,
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
765
766
  		const struct iattr *attrs,
  		gfp_t gfp_mask)
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
767
  {
82a2c1b77   Al Viro   nfs4_opendata doe...
768
  	struct dentry *parent = dget_parent(dentry);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
769
770
771
  	struct inode *dir = parent->d_inode;
  	struct nfs_server *server = NFS_SERVER(dir);
  	struct nfs4_opendata *p;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
772
  	p = kzalloc(sizeof(*p), gfp_mask);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
773
774
  	if (p == NULL)
  		goto err;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
775
  	p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
776
777
  	if (p->o_arg.seqid == NULL)
  		goto err_free;
82a2c1b77   Al Viro   nfs4_opendata doe...
778
779
  	nfs_sb_active(dentry->d_sb);
  	p->dentry = dget(dentry);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
780
781
782
783
  	p->dir = parent;
  	p->owner = sp;
  	atomic_inc(&sp->so_count);
  	p->o_arg.fh = NFS_FH(dir);
dc0b027df   Trond Myklebust   NFSv4: Convert th...
784
785
  	p->o_arg.open_flags = flags;
  	p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
7539bbab8   David Howells   NFS: Rename nfs_s...
786
  	p->o_arg.clientid = server->nfs_client->cl_clientid;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
787
  	p->o_arg.id = sp->so_owner_id.id;
82a2c1b77   Al Viro   nfs4_opendata doe...
788
  	p->o_arg.name = &dentry->d_name;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
789
790
  	p->o_arg.server = server;
  	p->o_arg.bitmask = server->attr_bitmask;
6926afd19   Trond Myklebust   NFSv4: Save the o...
791
  	p->o_arg.dir_bitmask = server->cache_consistency_bitmask;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
792
  	p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;
d77d76ffb   Trond Myklebust   NFSv41: Clean up ...
793
794
  	if (flags & O_CREAT) {
  		u32 *s;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
795
796
  		p->o_arg.u.attrs = &p->attrs;
  		memcpy(&p->attrs, attrs, sizeof(p->attrs));
d77d76ffb   Trond Myklebust   NFSv41: Clean up ...
797
798
799
  		s = (u32 *) p->o_arg.u.verifier.data;
  		s[0] = jiffies;
  		s[1] = current->pid;
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
800
  	}
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
801
802
803
  	p->c_arg.fh = &p->o_res.fh;
  	p->c_arg.stateid = &p->o_res.stateid;
  	p->c_arg.seqid = p->o_arg.seqid;
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
804
  	nfs4_init_opendata_res(p);
c6d00e639   Trond Myklebust   NFSv4: Convert st...
805
  	kref_init(&p->kref);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
806
807
808
809
810
811
812
  	return p;
  err_free:
  	kfree(p);
  err:
  	dput(parent);
  	return NULL;
  }
c6d00e639   Trond Myklebust   NFSv4: Convert st...
813
  static void nfs4_opendata_free(struct kref *kref)
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
814
  {
c6d00e639   Trond Myklebust   NFSv4: Convert st...
815
816
  	struct nfs4_opendata *p = container_of(kref,
  			struct nfs4_opendata, kref);
82a2c1b77   Al Viro   nfs4_opendata doe...
817
  	struct super_block *sb = p->dentry->d_sb;
c6d00e639   Trond Myklebust   NFSv4: Convert st...
818
819
  
  	nfs_free_seqid(p->o_arg.seqid);
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
820
821
  	if (p->state != NULL)
  		nfs4_put_open_state(p->state);
c6d00e639   Trond Myklebust   NFSv4: Convert st...
822
823
  	nfs4_put_state_owner(p->owner);
  	dput(p->dir);
82a2c1b77   Al Viro   nfs4_opendata doe...
824
825
  	dput(p->dentry);
  	nfs_sb_deactive(sb);
6926afd19   Trond Myklebust   NFSv4: Save the o...
826
  	nfs_fattr_free_names(&p->f_attr);
c6d00e639   Trond Myklebust   NFSv4: Convert st...
827
828
829
830
831
832
833
  	kfree(p);
  }
  
  static void nfs4_opendata_put(struct nfs4_opendata *p)
  {
  	if (p != NULL)
  		kref_put(&p->kref, nfs4_opendata_free);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
834
  }
06f814a3a   Trond Myklebust   NFSv4: Make locku...
835
836
  static int nfs4_wait_for_completion_rpc_task(struct rpc_task *task)
  {
06f814a3a   Trond Myklebust   NFSv4: Make locku...
837
  	int ret;
06f814a3a   Trond Myklebust   NFSv4: Make locku...
838
  	ret = rpc_wait_for_completion_task(task);
06f814a3a   Trond Myklebust   NFSv4: Make locku...
839
840
  	return ret;
  }
dc0b027df   Trond Myklebust   NFSv4: Convert th...
841
  static int can_open_cached(struct nfs4_state *state, fmode_t mode, int open_mode)
6ee412689   Trond Myklebust   NFSv4: Don't call...
842
843
  {
  	int ret = 0;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
844
845
846
847
  
  	if (open_mode & O_EXCL)
  		goto out;
  	switch (mode & (FMODE_READ|FMODE_WRITE)) {
6ee412689   Trond Myklebust   NFSv4: Don't call...
848
  		case FMODE_READ:
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
849
850
  			ret |= test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0
  				&& state->n_rdonly != 0;
6ee412689   Trond Myklebust   NFSv4: Don't call...
851
852
  			break;
  		case FMODE_WRITE:
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
853
854
  			ret |= test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0
  				&& state->n_wronly != 0;
6ee412689   Trond Myklebust   NFSv4: Don't call...
855
856
  			break;
  		case FMODE_READ|FMODE_WRITE:
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
857
858
  			ret |= test_bit(NFS_O_RDWR_STATE, &state->flags) != 0
  				&& state->n_rdwr != 0;
6ee412689   Trond Myklebust   NFSv4: Don't call...
859
  	}
dc0b027df   Trond Myklebust   NFSv4: Convert th...
860
  out:
6ee412689   Trond Myklebust   NFSv4: Don't call...
861
862
  	return ret;
  }
dc0b027df   Trond Myklebust   NFSv4: Convert th...
863
  static int can_open_delegated(struct nfs_delegation *delegation, fmode_t fmode)
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
864
  {
652f89f64   Trond Myklebust   NFSv4: Do not acc...
865
866
  	if (delegation == NULL)
  		return 0;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
867
  	if ((delegation->type & fmode) != fmode)
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
868
  		return 0;
15c831bf1   Trond Myklebust   NFS: Use atomic b...
869
  	if (test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags))
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
870
  		return 0;
b7391f44f   Trond Myklebust   NFSv4: Return unr...
871
  	nfs_mark_delegation_referenced(delegation);
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
872
873
  	return 1;
  }
dc0b027df   Trond Myklebust   NFSv4: Convert th...
874
  static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
875
  {
dc0b027df   Trond Myklebust   NFSv4: Convert th...
876
  	switch (fmode) {
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
877
878
879
880
881
882
883
884
885
  		case FMODE_WRITE:
  			state->n_wronly++;
  			break;
  		case FMODE_READ:
  			state->n_rdonly++;
  			break;
  		case FMODE_READ|FMODE_WRITE:
  			state->n_rdwr++;
  	}
dc0b027df   Trond Myklebust   NFSv4: Convert th...
886
  	nfs4_state_set_mode_locked(state, state->state | fmode);
003707c72   Trond Myklebust   NFSv4: Always use...
887
  }
dc0b027df   Trond Myklebust   NFSv4: Convert th...
888
  static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
003707c72   Trond Myklebust   NFSv4: Always use...
889
890
891
892
  {
  	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
  		memcpy(state->stateid.data, stateid->data, sizeof(state->stateid.data));
  	memcpy(state->open_stateid.data, stateid->data, sizeof(state->open_stateid.data));
dc0b027df   Trond Myklebust   NFSv4: Convert th...
893
  	switch (fmode) {
003707c72   Trond Myklebust   NFSv4: Always use...
894
895
896
897
898
899
900
901
902
  		case FMODE_READ:
  			set_bit(NFS_O_RDONLY_STATE, &state->flags);
  			break;
  		case FMODE_WRITE:
  			set_bit(NFS_O_WRONLY_STATE, &state->flags);
  			break;
  		case FMODE_READ|FMODE_WRITE:
  			set_bit(NFS_O_RDWR_STATE, &state->flags);
  	}
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
903
  }
dc0b027df   Trond Myklebust   NFSv4: Convert th...
904
  static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
003707c72   Trond Myklebust   NFSv4: Always use...
905
  {
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
906
  	write_seqlock(&state->seqlock);
dc0b027df   Trond Myklebust   NFSv4: Convert th...
907
  	nfs_set_open_stateid_locked(state, stateid, fmode);
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
908
  	write_sequnlock(&state->seqlock);
003707c72   Trond Myklebust   NFSv4: Always use...
909
  }
dc0b027df   Trond Myklebust   NFSv4: Convert th...
910
  static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  {
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
912
913
914
915
916
  	/*
  	 * Protect the call to nfs4_state_set_mode_locked and
  	 * serialise the stateid update
  	 */
  	write_seqlock(&state->seqlock);
003707c72   Trond Myklebust   NFSv4: Always use...
917
918
919
920
921
  	if (deleg_stateid != NULL) {
  		memcpy(state->stateid.data, deleg_stateid->data, sizeof(state->stateid.data));
  		set_bit(NFS_DELEGATED_STATE, &state->flags);
  	}
  	if (open_stateid != NULL)
dc0b027df   Trond Myklebust   NFSv4: Convert th...
922
  		nfs_set_open_stateid_locked(state, open_stateid, fmode);
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
923
924
  	write_sequnlock(&state->seqlock);
  	spin_lock(&state->owner->so_lock);
dc0b027df   Trond Myklebust   NFSv4: Convert th...
925
  	update_open_stateflags(state, fmode);
ec0734282   Trond Myklebust   NFSv4: Fix up loc...
926
  	spin_unlock(&state->owner->so_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
  }
dc0b027df   Trond Myklebust   NFSv4: Convert th...
928
  static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *delegation, fmode_t fmode)
343104308   Trond Myklebust   NFSv4: Fix up ano...
929
930
931
932
  {
  	struct nfs_inode *nfsi = NFS_I(state->inode);
  	struct nfs_delegation *deleg_cur;
  	int ret = 0;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
933
  	fmode &= (FMODE_READ|FMODE_WRITE);
343104308   Trond Myklebust   NFSv4: Fix up ano...
934
935
936
937
938
939
940
941
  
  	rcu_read_lock();
  	deleg_cur = rcu_dereference(nfsi->delegation);
  	if (deleg_cur == NULL)
  		goto no_delegation;
  
  	spin_lock(&deleg_cur->lock);
  	if (nfsi->delegation != deleg_cur ||
dc0b027df   Trond Myklebust   NFSv4: Convert th...
942
  	    (deleg_cur->type & fmode) != fmode)
343104308   Trond Myklebust   NFSv4: Fix up ano...
943
944
945
946
947
948
  		goto no_delegation_unlock;
  
  	if (delegation == NULL)
  		delegation = &deleg_cur->stateid;
  	else if (memcmp(deleg_cur->stateid.data, delegation->data, NFS4_STATEID_SIZE) != 0)
  		goto no_delegation_unlock;
b7391f44f   Trond Myklebust   NFSv4: Return unr...
949
  	nfs_mark_delegation_referenced(deleg_cur);
dc0b027df   Trond Myklebust   NFSv4: Convert th...
950
  	__update_open_stateid(state, open_stateid, &deleg_cur->stateid, fmode);
343104308   Trond Myklebust   NFSv4: Fix up ano...
951
952
953
954
955
956
957
  	ret = 1;
  no_delegation_unlock:
  	spin_unlock(&deleg_cur->lock);
  no_delegation:
  	rcu_read_unlock();
  
  	if (!ret && open_stateid != NULL) {
dc0b027df   Trond Myklebust   NFSv4: Convert th...
958
  		__update_open_stateid(state, open_stateid, NULL, fmode);
343104308   Trond Myklebust   NFSv4: Fix up ano...
959
960
961
962
963
  		ret = 1;
  	}
  
  	return ret;
  }
dc0b027df   Trond Myklebust   NFSv4: Convert th...
964
  static void nfs4_return_incompatible_delegation(struct inode *inode, fmode_t fmode)
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
965
966
967
968
969
  {
  	struct nfs_delegation *delegation;
  
  	rcu_read_lock();
  	delegation = rcu_dereference(NFS_I(inode)->delegation);
dc0b027df   Trond Myklebust   NFSv4: Convert th...
970
  	if (delegation == NULL || (delegation->type & fmode) == fmode) {
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
971
972
973
974
975
976
  		rcu_read_unlock();
  		return;
  	}
  	rcu_read_unlock();
  	nfs_inode_return_delegation(inode);
  }
6ee412689   Trond Myklebust   NFSv4: Don't call...
977
  static struct nfs4_state *nfs4_try_open_cached(struct nfs4_opendata *opendata)
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
978
979
980
981
  {
  	struct nfs4_state *state = opendata->state;
  	struct nfs_inode *nfsi = NFS_I(state->inode);
  	struct nfs_delegation *delegation;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
982
983
  	int open_mode = opendata->o_arg.open_flags & O_EXCL;
  	fmode_t fmode = opendata->o_arg.fmode;
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
984
985
  	nfs4_stateid stateid;
  	int ret = -EAGAIN;
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
986
  	for (;;) {
dc0b027df   Trond Myklebust   NFSv4: Convert th...
987
  		if (can_open_cached(state, fmode, open_mode)) {
6ee412689   Trond Myklebust   NFSv4: Don't call...
988
  			spin_lock(&state->owner->so_lock);
dc0b027df   Trond Myklebust   NFSv4: Convert th...
989
990
  			if (can_open_cached(state, fmode, open_mode)) {
  				update_open_stateflags(state, fmode);
6ee412689   Trond Myklebust   NFSv4: Don't call...
991
  				spin_unlock(&state->owner->so_lock);
6ee412689   Trond Myklebust   NFSv4: Don't call...
992
993
994
995
  				goto out_return_state;
  			}
  			spin_unlock(&state->owner->so_lock);
  		}
343104308   Trond Myklebust   NFSv4: Fix up ano...
996
997
  		rcu_read_lock();
  		delegation = rcu_dereference(nfsi->delegation);
652f89f64   Trond Myklebust   NFSv4: Do not acc...
998
  		if (!can_open_delegated(delegation, fmode)) {
343104308   Trond Myklebust   NFSv4: Fix up ano...
999
  			rcu_read_unlock();
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1000
  			break;
343104308   Trond Myklebust   NFSv4: Fix up ano...
1001
  		}
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1002
1003
1004
  		/* Save the delegation */
  		memcpy(stateid.data, delegation->stateid.data, sizeof(stateid.data));
  		rcu_read_unlock();
af22f94ae   Trond Myklebust   NFSv4: Simplify _...
1005
  		ret = nfs_may_open(state->inode, state->owner->so_cred, open_mode);
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1006
1007
1008
  		if (ret != 0)
  			goto out;
  		ret = -EAGAIN;
343104308   Trond Myklebust   NFSv4: Fix up ano...
1009
1010
  
  		/* Try to update the stateid using the delegation */
dc0b027df   Trond Myklebust   NFSv4: Convert th...
1011
  		if (update_open_stateid(state, NULL, &stateid, fmode))
343104308   Trond Myklebust   NFSv4: Fix up ano...
1012
  			goto out_return_state;
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1013
  	}
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1014
1015
1016
1017
1018
1019
  out:
  	return ERR_PTR(ret);
  out_return_state:
  	atomic_inc(&state->count);
  	return state;
  }
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1020
1021
1022
1023
  static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
  {
  	struct inode *inode;
  	struct nfs4_state *state = NULL;
003707c72   Trond Myklebust   NFSv4: Always use...
1024
  	struct nfs_delegation *delegation;
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1025
  	int ret;
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1026

aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1027
  	if (!data->rpc_done) {
6ee412689   Trond Myklebust   NFSv4: Don't call...
1028
  		state = nfs4_try_open_cached(data);
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1029
1030
  		goto out;
  	}
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1031
  	ret = -EAGAIN;
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1032
  	if (!(data->f_attr.valid & NFS_ATTR_FATTR))
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1033
  		goto err;
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1034
  	inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr);
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1035
  	ret = PTR_ERR(inode);
03f28e3a2   Trond Myklebust   NFS: Make nfs_fhg...
1036
  	if (IS_ERR(inode))
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1037
1038
  		goto err;
  	ret = -ENOMEM;
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1039
1040
  	state = nfs4_get_open_state(inode, data->owner);
  	if (state == NULL)
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1041
  		goto err_put_inode;
549d6ed5e   Trond Myklebust   NFSv4: set the de...
1042
  	if (data->o_res.delegation_type != 0) {
549d6ed5e   Trond Myklebust   NFSv4: set the de...
1043
  		int delegation_flags = 0;
003707c72   Trond Myklebust   NFSv4: Always use...
1044
1045
1046
1047
1048
  		rcu_read_lock();
  		delegation = rcu_dereference(NFS_I(inode)->delegation);
  		if (delegation)
  			delegation_flags = delegation->flags;
  		rcu_read_unlock();
652f89f64   Trond Myklebust   NFSv4: Do not acc...
1049
1050
1051
1052
1053
1054
1055
  		if (data->o_arg.claim == NFS4_OPEN_CLAIM_DELEGATE_CUR) {
  			pr_err_ratelimited("NFS: Broken NFSv4 server %s is "
  					"returning a delegation for "
  					"OPEN(CLAIM_DELEGATE_CUR)
  ",
  					NFS_CLIENT(inode)->cl_server);
  		} else if ((delegation_flags & 1UL<<NFS_DELEGATION_NEED_RECLAIM) == 0)
549d6ed5e   Trond Myklebust   NFSv4: set the de...
1056
1057
1058
1059
1060
1061
1062
1063
  			nfs_inode_set_delegation(state->inode,
  					data->owner->so_cred,
  					&data->o_res);
  		else
  			nfs_inode_reclaim_delegation(state->inode,
  					data->owner->so_cred,
  					&data->o_res);
  	}
343104308   Trond Myklebust   NFSv4: Fix up ano...
1064
1065
  
  	update_open_stateid(state, &data->o_res.stateid, NULL,
dc0b027df   Trond Myklebust   NFSv4: Convert th...
1066
  			data->o_arg.fmode);
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1067
  	iput(inode);
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1068
  out:
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1069
  	return state;
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1070
1071
1072
1073
  err_put_inode:
  	iput(inode);
  err:
  	return ERR_PTR(ret);
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1074
  }
864472e9b   Trond Myklebust   NFSv4: Make open ...
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
  static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state)
  {
  	struct nfs_inode *nfsi = NFS_I(state->inode);
  	struct nfs_open_context *ctx;
  
  	spin_lock(&state->inode->i_lock);
  	list_for_each_entry(ctx, &nfsi->open_files, list) {
  		if (ctx->state != state)
  			continue;
  		get_nfs_open_context(ctx);
  		spin_unlock(&state->inode->i_lock);
  		return ctx;
  	}
  	spin_unlock(&state->inode->i_lock);
  	return ERR_PTR(-ENOENT);
  }
6f220ed5a   Trond Myklebust   NFSv4: Fix open s...
1091
1092
1093
  static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state)
  {
  	struct nfs4_opendata *opendata;
3d4ff43d8   Al Viro   nfs_open_context ...
1094
  	opendata = nfs4_opendata_alloc(ctx->dentry, state->owner, 0, 0, NULL, GFP_NOFS);
6f220ed5a   Trond Myklebust   NFSv4: Fix open s...
1095
1096
1097
1098
1099
1100
  	if (opendata == NULL)
  		return ERR_PTR(-ENOMEM);
  	opendata->state = state;
  	atomic_inc(&state->count);
  	return opendata;
  }
dc0b027df   Trond Myklebust   NFSv4: Convert th...
1101
  static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, fmode_t fmode, struct nfs4_state **res)
864472e9b   Trond Myklebust   NFSv4: Make open ...
1102
  {
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1103
  	struct nfs4_state *newstate;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1104
  	int ret;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
1105
1106
  	opendata->o_arg.open_flags = 0;
  	opendata->o_arg.fmode = fmode;
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1107
1108
1109
  	memset(&opendata->o_res, 0, sizeof(opendata->o_res));
  	memset(&opendata->c_res, 0, sizeof(opendata->c_res));
  	nfs4_init_opendata_res(opendata);
b257957e5   Alexandros Batsakis   nfs: make recover...
1110
  	ret = _nfs4_recover_proc_open(opendata);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1111
1112
  	if (ret != 0)
  		return ret; 
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1113
  	newstate = nfs4_opendata_to_nfs4_state(opendata);
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1114
1115
  	if (IS_ERR(newstate))
  		return PTR_ERR(newstate);
643168c2d   Al Viro   nfs4_closedata do...
1116
  	nfs4_close_state(newstate, fmode);
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1117
  	*res = newstate;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1118
1119
1120
1121
1122
  	return 0;
  }
  
  static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state)
  {
864472e9b   Trond Myklebust   NFSv4: Make open ...
1123
  	struct nfs4_state *newstate;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1124
1125
1126
  	int ret;
  
  	/* memory barrier prior to reading state->n_* */
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1127
  	clear_bit(NFS_DELEGATED_STATE, &state->flags);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1128
1129
  	smp_rmb();
  	if (state->n_rdwr != 0) {
b0ed9dbc2   Trond Myklebust   NFSv4: Fix open r...
1130
  		clear_bit(NFS_O_RDWR_STATE, &state->flags);
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1131
  		ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1132
1133
  		if (ret != 0)
  			return ret;
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1134
1135
  		if (newstate != state)
  			return -ESTALE;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1136
1137
  	}
  	if (state->n_wronly != 0) {
b0ed9dbc2   Trond Myklebust   NFSv4: Fix open r...
1138
  		clear_bit(NFS_O_WRONLY_STATE, &state->flags);
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1139
  		ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1140
1141
  		if (ret != 0)
  			return ret;
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1142
1143
  		if (newstate != state)
  			return -ESTALE;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1144
1145
  	}
  	if (state->n_rdonly != 0) {
b0ed9dbc2   Trond Myklebust   NFSv4: Fix open r...
1146
  		clear_bit(NFS_O_RDONLY_STATE, &state->flags);
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1147
  		ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1148
1149
  		if (ret != 0)
  			return ret;
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1150
1151
  		if (newstate != state)
  			return -ESTALE;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1152
  	}
1ac7e2fd3   Trond Myklebust   NFSv4: Clean up t...
1153
1154
1155
1156
1157
1158
  	/*
  	 * We may have performed cached opens for all three recoveries.
  	 * Check if we need to update the current stateid.
  	 */
  	if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 &&
  	    memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) {
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
1159
  		write_seqlock(&state->seqlock);
1ac7e2fd3   Trond Myklebust   NFSv4: Clean up t...
1160
1161
  		if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
  			memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data));
8bda4e4c9   Trond Myklebust   NFSv4: Fix up sta...
1162
  		write_sequnlock(&state->seqlock);
1ac7e2fd3   Trond Myklebust   NFSv4: Clean up t...
1163
  	}
864472e9b   Trond Myklebust   NFSv4: Make open ...
1164
1165
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
1168
  /*
   * OPEN_RECLAIM:
   * 	reclaim state on the server after a reboot.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1169
   */
539cd03a5   Trond Myklebust   NFSv4: Cleanup: p...
1170
  static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1171
  {
1ac7e2fd3   Trond Myklebust   NFSv4: Clean up t...
1172
  	struct nfs_delegation *delegation;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1173
  	struct nfs4_opendata *opendata;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
1174
  	fmode_t delegation_type = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1175
  	int status;
6f220ed5a   Trond Myklebust   NFSv4: Fix open s...
1176
1177
1178
  	opendata = nfs4_open_recoverdata_alloc(ctx, state);
  	if (IS_ERR(opendata))
  		return PTR_ERR(opendata);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1179
1180
  	opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS;
  	opendata->o_arg.fh = NFS_FH(state->inode);
1ac7e2fd3   Trond Myklebust   NFSv4: Clean up t...
1181
1182
  	rcu_read_lock();
  	delegation = rcu_dereference(NFS_I(state->inode)->delegation);
15c831bf1   Trond Myklebust   NFS: Use atomic b...
1183
  	if (delegation != NULL && test_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags) != 0)
65bbf6bdb   Trond Myklebust   NFSv4: Fix a typo...
1184
  		delegation_type = delegation->type;
1ac7e2fd3   Trond Myklebust   NFSv4: Clean up t...
1185
  	rcu_read_unlock();
864472e9b   Trond Myklebust   NFSv4: Make open ...
1186
1187
  	opendata->o_arg.u.delegation_type = delegation_type;
  	status = nfs4_open_recover(opendata, state);
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1188
  	nfs4_opendata_put(opendata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1189
1190
  	return status;
  }
539cd03a5   Trond Myklebust   NFSv4: Cleanup: p...
1191
  static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1192
1193
1194
1195
1196
  {
  	struct nfs_server *server = NFS_SERVER(state->inode);
  	struct nfs4_exception exception = { };
  	int err;
  	do {
539cd03a5   Trond Myklebust   NFSv4: Cleanup: p...
1197
  		err = _nfs4_do_open_reclaim(ctx, state);
168667c43   Trond Myklebust   NFSv4: The state ...
1198
  		if (err != -NFS4ERR_DELAY)
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
1199
1200
  			break;
  		nfs4_handle_exception(server, err, &exception);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1201
1202
1203
  	} while (exception.retry);
  	return err;
  }
864472e9b   Trond Myklebust   NFSv4: Make open ...
1204
1205
1206
1207
1208
1209
1210
1211
  static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
  {
  	struct nfs_open_context *ctx;
  	int ret;
  
  	ctx = nfs4_state_find_open_context(state);
  	if (IS_ERR(ctx))
  		return PTR_ERR(ctx);
539cd03a5   Trond Myklebust   NFSv4: Cleanup: p...
1212
  	ret = nfs4_do_open_reclaim(ctx, state);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1213
1214
1215
  	put_nfs_open_context(ctx);
  	return ret;
  }
13437e12f   Trond Myklebust   NFSv4: Support re...
1216
  static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1217
  {
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
1218
  	struct nfs4_opendata *opendata;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1219
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1220

6f220ed5a   Trond Myklebust   NFSv4: Fix open s...
1221
1222
1223
  	opendata = nfs4_open_recoverdata_alloc(ctx, state);
  	if (IS_ERR(opendata))
  		return PTR_ERR(opendata);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
1224
  	opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR;
13437e12f   Trond Myklebust   NFSv4: Support re...
1225
  	memcpy(opendata->o_arg.u.delegation.data, stateid->data,
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
1226
  			sizeof(opendata->o_arg.u.delegation.data));
864472e9b   Trond Myklebust   NFSv4: Make open ...
1227
  	ret = nfs4_open_recover(opendata, state);
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1228
  	nfs4_opendata_put(opendata);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1229
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1230
  }
13437e12f   Trond Myklebust   NFSv4: Support re...
1231
  int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
1233
  {
  	struct nfs4_exception exception = { };
539cd03a5   Trond Myklebust   NFSv4: Cleanup: p...
1234
  	struct nfs_server *server = NFS_SERVER(state->inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
1236
  	int err;
  	do {
13437e12f   Trond Myklebust   NFSv4: Support re...
1237
  		err = _nfs4_open_delegation_recall(ctx, state, stateid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1238
1239
  		switch (err) {
  			case 0:
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1240
1241
1242
  			case -ENOENT:
  			case -ESTALE:
  				goto out;
bcfa49f6f   Ricardo Labiaga   nfs41: Handle ses...
1243
1244
1245
1246
1247
  			case -NFS4ERR_BADSESSION:
  			case -NFS4ERR_BADSLOT:
  			case -NFS4ERR_BAD_HIGH_SLOT:
  			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
  			case -NFS4ERR_DEADSESSION:
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1248
  				nfs4_schedule_session_recovery(server->nfs_client->cl_session);
bcfa49f6f   Ricardo Labiaga   nfs41: Handle ses...
1249
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1250
1251
1252
1253
  			case -NFS4ERR_STALE_CLIENTID:
  			case -NFS4ERR_STALE_STATEID:
  			case -NFS4ERR_EXPIRED:
  				/* Don't recall a delegation if it was lost */
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1254
  				nfs4_schedule_lease_recovery(server->nfs_client);
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1255
1256
1257
1258
1259
1260
1261
1262
  				goto out;
  			case -ERESTARTSYS:
  				/*
  				 * The show must go on: exit, but mark the
  				 * stateid as needing recovery.
  				 */
  			case -NFS4ERR_ADMIN_REVOKED:
  			case -NFS4ERR_BAD_STATEID:
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1263
  				nfs4_schedule_stateid_recovery(server, state);
168667c43   Trond Myklebust   NFSv4: The state ...
1264
1265
1266
1267
1268
1269
1270
  			case -EKEYEXPIRED:
  				/*
  				 * User RPCSEC_GSS context has expired.
  				 * We cannot recover this stateid now, so
  				 * skip it and allow recovery thread to
  				 * proceed.
  				 */
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1271
1272
1273
  			case -ENOMEM:
  				err = 0;
  				goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1274
1275
1276
  		}
  		err = nfs4_handle_exception(server, err, &exception);
  	} while (exception.retry);
965b5d679   Trond Myklebust   NFSv4: Handle mor...
1277
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
1279
  	return err;
  }
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1280
1281
1282
1283
1284
  static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_opendata *data = calldata;
  
  	data->rpc_status = task->tk_status;
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1285
  	if (data->rpc_status == 0) {
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1286
1287
  		memcpy(data->o_res.stateid.data, data->c_res.stateid.data,
  				sizeof(data->o_res.stateid.data));
bb22629ee   Trond Myklebust   NFSv4: nfs4_open_...
1288
  		nfs_confirm_seqid(&data->owner->so_seqid, 0);
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1289
  		renew_lease(data->o_res.server, data->timestamp);
3e309914a   Trond Myklebust   NFSv4: Clean up _...
1290
  		data->rpc_done = 1;
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1291
  	}
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
  }
  
  static void nfs4_open_confirm_release(void *calldata)
  {
  	struct nfs4_opendata *data = calldata;
  	struct nfs4_state *state = NULL;
  
  	/* If this request hasn't been cancelled, do nothing */
  	if (data->cancelled == 0)
  		goto out_free;
  	/* In case of error, no cleanup! */
3e309914a   Trond Myklebust   NFSv4: Clean up _...
1303
  	if (!data->rpc_done)
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1304
  		goto out_free;
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1305
  	state = nfs4_opendata_to_nfs4_state(data);
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1306
  	if (!IS_ERR(state))
643168c2d   Al Viro   nfs4_closedata do...
1307
  		nfs4_close_state(state, data->o_arg.fmode);
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1308
  out_free:
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1309
  	nfs4_opendata_put(data);
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1310
1311
1312
  }
  
  static const struct rpc_call_ops nfs4_open_confirm_ops = {
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
  	.rpc_call_done = nfs4_open_confirm_done,
  	.rpc_release = nfs4_open_confirm_release,
  };
  
  /*
   * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata
   */
  static int _nfs4_proc_open_confirm(struct nfs4_opendata *data)
  {
  	struct nfs_server *server = NFS_SERVER(data->dir->d_inode);
  	struct rpc_task *task;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1324
1325
1326
1327
1328
1329
  	struct  rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM],
  		.rpc_argp = &data->c_arg,
  		.rpc_resp = &data->c_res,
  		.rpc_cred = data->owner->so_cred,
  	};
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1330
1331
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = server->client,
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1332
  		.rpc_message = &msg,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1333
1334
  		.callback_ops = &nfs4_open_confirm_ops,
  		.callback_data = data,
101070ca2   Trond Myklebust   NFS: Ensure that ...
1335
  		.workqueue = nfsiod_workqueue,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1336
1337
  		.flags = RPC_TASK_ASYNC,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1338
  	int status;
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1339
  	kref_get(&data->kref);
3e309914a   Trond Myklebust   NFSv4: Clean up _...
1340
1341
  	data->rpc_done = 0;
  	data->rpc_status = 0;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1342
  	data->timestamp = jiffies;
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1343
  	task = rpc_run_task(&task_setup_data);
7a1218a27   Trond Myklebust   SUNRPC: Ensure rp...
1344
  	if (IS_ERR(task))
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1345
  		return PTR_ERR(task);
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1346
1347
1348
1349
1350
1351
  	status = nfs4_wait_for_completion_rpc_task(task);
  	if (status != 0) {
  		data->cancelled = 1;
  		smp_wmb();
  	} else
  		status = data->rpc_status;
e6b3c4db6   Trond Myklebust   Fix a second pote...
1352
  	rpc_put_task(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
1354
  	return status;
  }
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1355
  static void nfs4_open_prepare(struct rpc_task *task, void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1356
  {
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1357
1358
  	struct nfs4_opendata *data = calldata;
  	struct nfs4_state_owner *sp = data->owner;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1359

24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1360
1361
  	if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0)
  		return;
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1362
1363
1364
1365
1366
1367
  	/*
  	 * Check if we still need to send an OPEN call, or if we can use
  	 * a delegation instead.
  	 */
  	if (data->state != NULL) {
  		struct nfs_delegation *delegation;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
1368
  		if (can_open_cached(data->state, data->o_arg.fmode, data->o_arg.open_flags))
6ee412689   Trond Myklebust   NFSv4: Don't call...
1369
  			goto out_no_action;
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1370
1371
  		rcu_read_lock();
  		delegation = rcu_dereference(NFS_I(data->state->inode)->delegation);
652f89f64   Trond Myklebust   NFSv4: Do not acc...
1372
1373
1374
  		if (data->o_arg.claim != NFS4_OPEN_CLAIM_DELEGATE_CUR &&
  		    can_open_delegated(delegation, data->o_arg.fmode))
  			goto unlock_no_action;
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1375
1376
  		rcu_read_unlock();
  	}
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1377
  	/* Update sequence id. */
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
1378
  	data->o_arg.id = sp->so_owner_id.id;
1f0e890db   Trond Myklebust   NFSv4: Clean up s...
1379
  	data->o_arg.clientid = sp->so_server->nfs_client->cl_clientid;
6f220ed5a   Trond Myklebust   NFSv4: Fix open s...
1380
  	if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) {
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1381
  		task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR];
6f220ed5a   Trond Myklebust   NFSv4: Fix open s...
1382
1383
  		nfs_copy_fh(&data->o_res.fh, data->o_arg.fh);
  	}
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1384
  	data->timestamp = jiffies;
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
1385
  	if (nfs4_setup_sequence(data->o_arg.server,
d898528cd   Andy Adamson   nfs41: open seque...
1386
1387
1388
  				&data->o_arg.seq_args,
  				&data->o_res.seq_res, 1, task))
  		return;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1389
  	rpc_call_start(task);
6ee412689   Trond Myklebust   NFSv4: Don't call...
1390
  	return;
652f89f64   Trond Myklebust   NFSv4: Do not acc...
1391
1392
  unlock_no_action:
  	rcu_read_unlock();
6ee412689   Trond Myklebust   NFSv4: Don't call...
1393
1394
  out_no_action:
  	task->tk_action = NULL;
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1395
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1396

b257957e5   Alexandros Batsakis   nfs: make recover...
1397
1398
1399
1400
1401
  static void nfs4_recover_open_prepare(struct rpc_task *task, void *calldata)
  {
  	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
  	nfs4_open_prepare(task, calldata);
  }
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1402
1403
1404
  static void nfs4_open_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_opendata *data = calldata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1405

24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1406
  	data->rpc_status = task->tk_status;
d898528cd   Andy Adamson   nfs41: open seque...
1407

14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
1408
1409
  	if (!nfs4_sequence_done(task, &data->o_res.seq_res))
  		return;
d898528cd   Andy Adamson   nfs41: open seque...
1410

24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1411
1412
  	if (task->tk_status == 0) {
  		switch (data->o_res.f_attr->mode & S_IFMT) {
6f926b5ba   Trond Myklebust   [NFS]: Check that...
1413
1414
1415
  			case S_IFREG:
  				break;
  			case S_IFLNK:
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1416
  				data->rpc_status = -ELOOP;
6f926b5ba   Trond Myklebust   [NFS]: Check that...
1417
1418
  				break;
  			case S_IFDIR:
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1419
  				data->rpc_status = -EISDIR;
6f926b5ba   Trond Myklebust   [NFS]: Check that...
1420
1421
  				break;
  			default:
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1422
  				data->rpc_status = -ENOTDIR;
6f926b5ba   Trond Myklebust   [NFS]: Check that...
1423
  		}
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1424
  		renew_lease(data->o_res.server, data->timestamp);
0f9f95e0a   Trond Myklebust   NFSv4: Clean up c...
1425
1426
  		if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM))
  			nfs_confirm_seqid(&data->owner->so_seqid, 0);
6f926b5ba   Trond Myklebust   [NFS]: Check that...
1427
  	}
3e309914a   Trond Myklebust   NFSv4: Clean up _...
1428
  	data->rpc_done = 1;
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1429
  }
6f926b5ba   Trond Myklebust   [NFS]: Check that...
1430

24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1431
1432
1433
1434
1435
1436
1437
1438
1439
  static void nfs4_open_release(void *calldata)
  {
  	struct nfs4_opendata *data = calldata;
  	struct nfs4_state *state = NULL;
  
  	/* If this request hasn't been cancelled, do nothing */
  	if (data->cancelled == 0)
  		goto out_free;
  	/* In case of error, no cleanup! */
3e309914a   Trond Myklebust   NFSv4: Clean up _...
1440
  	if (data->rpc_status != 0 || !data->rpc_done)
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1441
1442
1443
1444
  		goto out_free;
  	/* In case we need an open_confirm, no cleanup! */
  	if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)
  		goto out_free;
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1445
  	state = nfs4_opendata_to_nfs4_state(data);
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1446
  	if (!IS_ERR(state))
643168c2d   Al Viro   nfs4_closedata do...
1447
  		nfs4_close_state(state, data->o_arg.fmode);
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1448
  out_free:
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1449
  	nfs4_opendata_put(data);
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1450
1451
1452
1453
1454
1455
1456
  }
  
  static const struct rpc_call_ops nfs4_open_ops = {
  	.rpc_call_prepare = nfs4_open_prepare,
  	.rpc_call_done = nfs4_open_done,
  	.rpc_release = nfs4_open_release,
  };
b257957e5   Alexandros Batsakis   nfs: make recover...
1457
1458
1459
1460
1461
1462
1463
  static const struct rpc_call_ops nfs4_recover_open_ops = {
  	.rpc_call_prepare = nfs4_recover_open_prepare,
  	.rpc_call_done = nfs4_open_done,
  	.rpc_release = nfs4_open_release,
  };
  
  static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover)
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1464
1465
1466
1467
1468
1469
  {
  	struct inode *dir = data->dir->d_inode;
  	struct nfs_server *server = NFS_SERVER(dir);
  	struct nfs_openargs *o_arg = &data->o_arg;
  	struct nfs_openres *o_res = &data->o_res;
  	struct rpc_task *task;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1470
1471
1472
1473
1474
1475
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN],
  		.rpc_argp = o_arg,
  		.rpc_resp = o_res,
  		.rpc_cred = data->owner->so_cred,
  	};
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1476
1477
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = server->client,
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1478
  		.rpc_message = &msg,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1479
1480
  		.callback_ops = &nfs4_open_ops,
  		.callback_data = data,
101070ca2   Trond Myklebust   NFS: Ensure that ...
1481
  		.workqueue = nfsiod_workqueue,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1482
1483
  		.flags = RPC_TASK_ASYNC,
  	};
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1484
  	int status;
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1485
  	kref_get(&data->kref);
3e309914a   Trond Myklebust   NFSv4: Clean up _...
1486
1487
  	data->rpc_done = 0;
  	data->rpc_status = 0;
2ced46c27   Trond Myklebust   NFSv4: Fix up a b...
1488
  	data->cancelled = 0;
b257957e5   Alexandros Batsakis   nfs: make recover...
1489
1490
  	if (isrecover)
  		task_setup_data.callback_ops = &nfs4_recover_open_ops;
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1491
  	task = rpc_run_task(&task_setup_data);
b257957e5   Alexandros Batsakis   nfs: make recover...
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
          if (IS_ERR(task))
                  return PTR_ERR(task);
          status = nfs4_wait_for_completion_rpc_task(task);
          if (status != 0) {
                  data->cancelled = 1;
                  smp_wmb();
          } else
                  status = data->rpc_status;
          rpc_put_task(task);
  
  	return status;
  }
  
  static int _nfs4_recover_proc_open(struct nfs4_opendata *data)
  {
  	struct inode *dir = data->dir->d_inode;
  	struct nfs_openres *o_res = &data->o_res;
          int status;
  
  	status = nfs4_run_open_task(data, 1);
  	if (status != 0 || !data->rpc_done)
  		return status;
6926afd19   Trond Myklebust   NFSv4: Save the o...
1514
  	nfs_fattr_map_and_free_names(NFS_SERVER(dir), &data->f_attr);
b257957e5   Alexandros Batsakis   nfs: make recover...
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
  	nfs_refresh_inode(dir, o_res->dir_attr);
  
  	if (o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
  		status = _nfs4_proc_open_confirm(data);
  		if (status != 0)
  			return status;
  	}
  
  	return status;
  }
  
  /*
   * Note: On error, nfs4_proc_open will free the struct nfs4_opendata
   */
  static int _nfs4_proc_open(struct nfs4_opendata *data)
  {
  	struct inode *dir = data->dir->d_inode;
  	struct nfs_server *server = NFS_SERVER(dir);
  	struct nfs_openargs *o_arg = &data->o_arg;
  	struct nfs_openres *o_res = &data->o_res;
  	int status;
  
  	status = nfs4_run_open_task(data, 0);
08ef7bd3b   Trond Myklebust   NFSv4: Translate ...
1538
1539
1540
1541
1542
1543
  	if (!data->rpc_done)
  		return status;
  	if (status != 0) {
  		if (status == -NFS4ERR_BADNAME &&
  				!(o_arg->open_flags & O_CREAT))
  			return -ENOENT;
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1544
  		return status;
08ef7bd3b   Trond Myklebust   NFSv4: Translate ...
1545
  	}
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1546

6926afd19   Trond Myklebust   NFSv4: Save the o...
1547
  	nfs_fattr_map_and_free_names(server, &data->f_attr);
56ae19f38   Trond Myklebust   NFSv4: Add direct...
1548
1549
1550
1551
1552
  	if (o_arg->open_flags & O_CREAT) {
  		update_changeattr(dir, &o_res->cinfo);
  		nfs_post_op_update_inode(dir, o_res->dir_attr);
  	} else
  		nfs_refresh_inode(dir, o_res->dir_attr);
0df5dd4aa   Trond Myklebust   NFSv4: fix delega...
1553
1554
  	if ((o_res->rflags & NFS4_OPEN_RESULT_LOCKTYPE_POSIX) == 0)
  		server->caps &= ~NFS_CAP_POSIX_LOCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1555
  	if(o_res->rflags & NFS4_OPEN_RESULT_CONFIRM) {
cdd4e68b5   Trond Myklebust   NFSv4: Make open_...
1556
  		status = _nfs4_proc_open_confirm(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1557
  		if (status != 0)
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1558
  			return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1559
1560
  	}
  	if (!(o_res->f_attr->valid & NFS_ATTR_FATTR))
9936781d0   Trond Myklebust   NFSv4: Try to rec...
1561
  		_nfs4_proc_getattr(server, &o_res->fh, o_res->f_attr);
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1562
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1563
  }
d83217c13   Andy Adamson   NFSv4.1: data ser...
1564
  static int nfs4_client_recover_expired_lease(struct nfs_client *clp)
58d9714a4   Trond Myklebust   NFSv4: Send RENEW...
1565
  {
a78cb57a1   Trond Myklebust   NFSv4: Don't loop...
1566
  	unsigned int loop;
6b30954eb   Trond Myklebust   NFSv4: Retry leas...
1567
  	int ret;
58d9714a4   Trond Myklebust   NFSv4: Send RENEW...
1568

a78cb57a1   Trond Myklebust   NFSv4: Don't loop...
1569
  	for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
65de872ed   Trond Myklebust   NFS: Remove the u...
1570
  		ret = nfs4_wait_clnt_recover(clp);
6b30954eb   Trond Myklebust   NFSv4: Retry leas...
1571
  		if (ret != 0)
a78cb57a1   Trond Myklebust   NFSv4: Don't loop...
1572
  			break;
e598d843c   Trond Myklebust   NFSv4: Remove red...
1573
1574
  		if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) &&
  		    !test_bit(NFS4CLNT_CHECK_LEASE,&clp->cl_state))
6b30954eb   Trond Myklebust   NFSv4: Retry leas...
1575
  			break;
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
1576
  		nfs4_schedule_state_manager(clp);
a78cb57a1   Trond Myklebust   NFSv4: Don't loop...
1577
  		ret = -EIO;
6b30954eb   Trond Myklebust   NFSv4: Retry leas...
1578
  	}
a78cb57a1   Trond Myklebust   NFSv4: Don't loop...
1579
  	return ret;
58d9714a4   Trond Myklebust   NFSv4: Send RENEW...
1580
  }
d83217c13   Andy Adamson   NFSv4.1: data ser...
1581
1582
1583
1584
  static int nfs4_recover_expired_lease(struct nfs_server *server)
  {
  	return nfs4_client_recover_expired_lease(server->nfs_client);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1585
1586
1587
1588
1589
  /*
   * OPEN_EXPIRED:
   * 	reclaim state on the server after a network partition.
   * 	Assumes caller holds the appropriate lock
   */
539cd03a5   Trond Myklebust   NFSv4: Cleanup: p...
1590
  static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1591
  {
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
1592
  	struct nfs4_opendata *opendata;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1593
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1594

6f220ed5a   Trond Myklebust   NFSv4: Fix open s...
1595
1596
1597
  	opendata = nfs4_open_recoverdata_alloc(ctx, state);
  	if (IS_ERR(opendata))
  		return PTR_ERR(opendata);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1598
  	ret = nfs4_open_recover(opendata, state);
35d05778e   Trond Myklebust   NFSv4: Remove bog...
1599
  	if (ret == -ESTALE)
3d4ff43d8   Al Viro   nfs_open_context ...
1600
  		d_drop(ctx->dentry);
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1601
  	nfs4_opendata_put(opendata);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1602
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1603
  }
a9ed2e258   Trond Myklebust   NFSv4: Handle NFS...
1604
  static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
1605
  {
539cd03a5   Trond Myklebust   NFSv4: Cleanup: p...
1606
  	struct nfs_server *server = NFS_SERVER(state->inode);
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
1607
1608
1609
1610
  	struct nfs4_exception exception = { };
  	int err;
  
  	do {
539cd03a5   Trond Myklebust   NFSv4: Cleanup: p...
1611
  		err = _nfs4_open_expired(ctx, state);
a9ed2e258   Trond Myklebust   NFSv4: Handle NFS...
1612
1613
1614
1615
1616
1617
1618
1619
  		switch (err) {
  		default:
  			goto out;
  		case -NFS4ERR_GRACE:
  		case -NFS4ERR_DELAY:
  			nfs4_handle_exception(server, err, &exception);
  			err = 0;
  		}
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
1620
  	} while (exception.retry);
a9ed2e258   Trond Myklebust   NFSv4: Handle NFS...
1621
  out:
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
1622
1623
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1624
1625
  static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1626
  	struct nfs_open_context *ctx;
864472e9b   Trond Myklebust   NFSv4: Make open ...
1627
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1628

864472e9b   Trond Myklebust   NFSv4: Make open ...
1629
1630
1631
  	ctx = nfs4_state_find_open_context(state);
  	if (IS_ERR(ctx))
  		return PTR_ERR(ctx);
539cd03a5   Trond Myklebust   NFSv4: Cleanup: p...
1632
  	ret = nfs4_do_open_expired(ctx, state);
864472e9b   Trond Myklebust   NFSv4: Make open ...
1633
1634
  	put_nfs_open_context(ctx);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1635
  }
f062eb6ce   Bryan Schumaker   NFS: test and fre...
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
  #if defined(CONFIG_NFS_V4_1)
  static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
  {
  	int status;
  	struct nfs_server *server = NFS_SERVER(state->inode);
  
  	status = nfs41_test_stateid(server, state);
  	if (status == NFS_OK)
  		return 0;
  	nfs41_free_stateid(server, state);
  	return nfs4_open_expired(sp, state);
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1649
  /*
aa53ed541   Jeff Layton   NFS4: on a O_EXCL...
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
   * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-*
   * fields corresponding to attributes that were used to store the verifier.
   * Make sure we clobber those fields in the later setattr call
   */
  static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr)
  {
  	if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) &&
  	    !(sattr->ia_valid & ATTR_ATIME_SET))
  		sattr->ia_valid |= ATTR_ATIME;
  
  	if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) &&
  	    !(sattr->ia_valid & ATTR_MTIME_SET))
  		sattr->ia_valid |= ATTR_MTIME;
  }
  
  /*
24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1666
   * Returns a referenced nfs4_state
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1667
   */
82a2c1b77   Al Viro   nfs4_opendata doe...
1668
  static int _nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1669
1670
1671
1672
  {
  	struct nfs4_state_owner  *sp;
  	struct nfs4_state     *state = NULL;
  	struct nfs_server       *server = NFS_SERVER(dir);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
1673
  	struct nfs4_opendata *opendata;
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1674
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1675
1676
  
  	/* Protect against reboot recovery conflicts */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1677
1678
1679
1680
1681
1682
  	status = -ENOMEM;
  	if (!(sp = nfs4_get_state_owner(server, cred))) {
  		dprintk("nfs4_do_open: nfs4_get_state_owner failed!
  ");
  		goto out_err;
  	}
58d9714a4   Trond Myklebust   NFSv4: Send RENEW...
1683
1684
  	status = nfs4_recover_expired_lease(server);
  	if (status != 0)
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
1685
  		goto err_put_state_owner;
82a2c1b77   Al Viro   nfs4_opendata doe...
1686
1687
  	if (dentry->d_inode != NULL)
  		nfs4_return_incompatible_delegation(dentry->d_inode, fmode);
58d9714a4   Trond Myklebust   NFSv4: Send RENEW...
1688
  	status = -ENOMEM;
82a2c1b77   Al Viro   nfs4_opendata doe...
1689
  	opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr, GFP_KERNEL);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
1690
  	if (opendata == NULL)
95d35cb4c   Trond Myklebust   NFSv4: Remove nfs...
1691
  		goto err_put_state_owner;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1692

82a2c1b77   Al Viro   nfs4_opendata doe...
1693
1694
  	if (dentry->d_inode != NULL)
  		opendata->state = nfs4_get_open_state(dentry->d_inode, sp);
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1695

24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1696
  	status = _nfs4_proc_open(opendata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1697
  	if (status != 0)
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1698
  		goto err_opendata_put;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1699

24ac23ab8   Trond Myklebust   NFSv4: Convert op...
1700
  	state = nfs4_opendata_to_nfs4_state(opendata);
1b370bc28   Trond Myklebust   NFSv4: Allow nfs4...
1701
1702
  	status = PTR_ERR(state);
  	if (IS_ERR(state))
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1703
  		goto err_opendata_put;
0df5dd4aa   Trond Myklebust   NFSv4: fix delega...
1704
  	if (server->caps & NFS_CAP_POSIX_LOCK)
8e469ebd6   Trond Myklebust   NFSv4: Don't allo...
1705
  		set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
0ab64e0e1   Trond Myklebust   NFS: Reduce stack...
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
  
  	if (opendata->o_arg.open_flags & O_EXCL) {
  		nfs4_exclusive_attrset(opendata, sattr);
  
  		nfs_fattr_init(opendata->o_res.f_attr);
  		status = nfs4_do_setattr(state->inode, cred,
  				opendata->o_res.f_attr, sattr,
  				state);
  		if (status == 0)
  			nfs_setattr_update_inode(state->inode, sattr);
  		nfs_post_op_update_inode(state->inode, opendata->o_res.f_attr);
  	}
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1718
  	nfs4_opendata_put(opendata);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1719
  	nfs4_put_state_owner(sp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1720
1721
  	*res = state;
  	return 0;
c6d00e639   Trond Myklebust   NFSv4: Convert st...
1722
1723
  err_opendata_put:
  	nfs4_opendata_put(opendata);
e56e0b78e   Trond Myklebust   NFSv4: Allocate O...
1724
1725
  err_put_state_owner:
  	nfs4_put_state_owner(sp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1726
  out_err:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1727
1728
1729
  	*res = NULL;
  	return status;
  }
82a2c1b77   Al Viro   nfs4_opendata doe...
1730
  static struct nfs4_state *nfs4_do_open(struct inode *dir, struct dentry *dentry, fmode_t fmode, int flags, struct iattr *sattr, struct rpc_cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1731
1732
1733
1734
1735
1736
  {
  	struct nfs4_exception exception = { };
  	struct nfs4_state *res;
  	int status;
  
  	do {
82a2c1b77   Al Viro   nfs4_opendata doe...
1737
  		status = _nfs4_do_open(dir, dentry, fmode, flags, sattr, cred, &res);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1738
1739
1740
1741
1742
1743
1744
1745
  		if (status == 0)
  			break;
  		/* NOTE: BAD_SEQID means the server and client disagree about the
  		 * book-keeping w.r.t. state-changing operations
  		 * (OPEN/CLOSE/LOCK/LOCKU...)
  		 * It is actually a sign of a bug on the client or on the server.
  		 *
  		 * If we receive a BAD_SEQID error in the particular case of
cee54fc94   Trond Myklebust   NFSv4: Add functi...
1746
  		 * doing an OPEN, we assume that nfs_increment_open_seqid() will
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1747
1748
1749
1750
1751
  		 * have unhashed the old state_owner for us, and that we can
  		 * therefore safely retry using a new one. We should still warn
  		 * the user though...
  		 */
  		if (status == -NFS4ERR_BAD_SEQID) {
6f43ddccb   Trond Myklebust   NFSv4: Improve th...
1752
1753
1754
1755
  			printk(KERN_WARNING "NFS: v4 server %s "
  					" returned a bad sequence-id error!
  ",
  					NFS_SERVER(dir)->nfs_client->cl_hostname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1756
1757
1758
  			exception.retry = 1;
  			continue;
  		}
550f57470   Trond Myklebust   NFSv4: Ensure tha...
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
  		/*
  		 * BAD_STATEID on OPEN means that the server cancelled our
  		 * state before it received the OPEN_CONFIRM.
  		 * Recover by retrying the request as per the discussion
  		 * on Page 181 of RFC3530.
  		 */
  		if (status == -NFS4ERR_BAD_STATEID) {
  			exception.retry = 1;
  			continue;
  		}
aac00a8d0   Trond Myklebust   NFSv4: Check for ...
1769
1770
1771
1772
1773
  		if (status == -EAGAIN) {
  			/* We must have found a delegation */
  			exception.retry = 1;
  			continue;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1774
1775
1776
1777
1778
  		res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir),
  					status, &exception));
  	} while (exception.retry);
  	return res;
  }
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
1779
1780
1781
  static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
  			    struct nfs_fattr *fattr, struct iattr *sattr,
  			    struct nfs4_state *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1782
  {
3e4f6290c   Trond Myklebust   NFSv4: Send the d...
1783
  	struct nfs_server *server = NFS_SERVER(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1784
          struct nfs_setattrargs  arg = {
3e4f6290c   Trond Myklebust   NFSv4: Send the d...
1785
                  .fh             = NFS_FH(inode),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1786
1787
1788
1789
1790
1791
1792
1793
1794
                  .iap            = sattr,
  		.server		= server,
  		.bitmask = server->attr_bitmask,
          };
          struct nfs_setattrres  res = {
  		.fattr		= fattr,
  		.server		= server,
          };
          struct rpc_message msg = {
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
1795
1796
1797
1798
  		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_SETATTR],
  		.rpc_argp	= &arg,
  		.rpc_resp	= &res,
  		.rpc_cred	= cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1799
          };
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1800
  	unsigned long timestamp = jiffies;
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
1801
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1802

0e574af1b   Trond Myklebust   NFS: Cleanup init...
1803
  	nfs_fattr_init(fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1804

3e4f6290c   Trond Myklebust   NFSv4: Send the d...
1805
1806
1807
  	if (nfs4_copy_delegation_stateid(&arg.stateid, inode)) {
  		/* Use that stateid */
  	} else if (state != NULL) {
77041ed9b   Trond Myklebust   NFSv4: Ensure the...
1808
  		nfs4_copy_stateid(&arg.stateid, state, current->files, current->tgid);
08e9eac42   Trond Myklebust   [PATCH] NFSv4: Fi...
1809
  	} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1810
  		memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
7c5130588   Bryan Schumaker   NFS: lookup suppo...
1811
  	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1812
1813
  	if (status == 0 && state != NULL)
  		renew_lease(server, timestamp);
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
1814
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1815
  }
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
1816
1817
1818
  static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
  			   struct nfs_fattr *fattr, struct iattr *sattr,
  			   struct nfs4_state *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1819
  {
3e4f6290c   Trond Myklebust   NFSv4: Send the d...
1820
  	struct nfs_server *server = NFS_SERVER(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1821
1822
1823
1824
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(server,
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
1825
  				_nfs4_do_setattr(inode, cred, fattr, sattr, state),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  struct nfs4_closedata {
  	struct inode *inode;
  	struct nfs4_state *state;
  	struct nfs_closeargs arg;
  	struct nfs_closeres res;
516a6af64   Trond Myklebust   NFS: Add optional...
1836
  	struct nfs_fattr fattr;
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1837
  	unsigned long timestamp;
f7e8917a6   Fred Isaman   pnfs: layout roc ...
1838
1839
  	bool roc;
  	u32 roc_barrier;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1840
  };
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1841
  static void nfs4_free_closedata(void *data)
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1842
  {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1843
1844
  	struct nfs4_closedata *calldata = data;
  	struct nfs4_state_owner *sp = calldata->state->owner;
643168c2d   Al Viro   nfs4_closedata do...
1845
  	struct super_block *sb = calldata->state->inode->i_sb;
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1846

f7e8917a6   Fred Isaman   pnfs: layout roc ...
1847
1848
  	if (calldata->roc)
  		pnfs_roc_release(calldata->state->inode);
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1849
1850
  	nfs4_put_open_state(calldata->state);
  	nfs_free_seqid(calldata->arg.seqid);
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1851
  	nfs4_put_state_owner(sp);
643168c2d   Al Viro   nfs4_closedata do...
1852
  	nfs_sb_deactive(sb);
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1853
1854
  	kfree(calldata);
  }
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
  static void nfs4_close_clear_stateid_flags(struct nfs4_state *state,
  		fmode_t fmode)
  {
  	spin_lock(&state->owner->so_lock);
  	if (!(fmode & FMODE_READ))
  		clear_bit(NFS_O_RDONLY_STATE, &state->flags);
  	if (!(fmode & FMODE_WRITE))
  		clear_bit(NFS_O_WRONLY_STATE, &state->flags);
  	clear_bit(NFS_O_RDWR_STATE, &state->flags);
  	spin_unlock(&state->owner->so_lock);
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1866
  static void nfs4_close_done(struct rpc_task *task, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1867
  {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1868
  	struct nfs4_closedata *calldata = data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1869
  	struct nfs4_state *state = calldata->state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1870
  	struct nfs_server *server = NFS_SERVER(calldata->inode);
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
1871
1872
  	if (!nfs4_sequence_done(task, &calldata->res.seq_res))
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1873
1874
1875
          /* hmm. we are done with the inode, and in the process of freeing
  	 * the state_owner. we keep this around to process errors
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1876
1877
  	switch (task->tk_status) {
  		case 0:
f7e8917a6   Fred Isaman   pnfs: layout roc ...
1878
1879
1880
  			if (calldata->roc)
  				pnfs_roc_set_barrier(state->inode,
  						     calldata->roc_barrier);
45328c354   Trond Myklebust   NFS: Fix NFSv4 op...
1881
  			nfs_set_open_stateid(state, &calldata->res.stateid, 0);
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1882
  			renew_lease(server, calldata->timestamp);
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1883
1884
  			nfs4_close_clear_stateid_flags(state,
  					calldata->arg.fmode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1885
1886
  			break;
  		case -NFS4ERR_STALE_STATEID:
9e33bed55   Trond Myklebust   NFSv4: Add recove...
1887
1888
  		case -NFS4ERR_OLD_STATEID:
  		case -NFS4ERR_BAD_STATEID:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1889
  		case -NFS4ERR_EXPIRED:
dc0b027df   Trond Myklebust   NFSv4: Convert th...
1890
  			if (calldata->arg.fmode == 0)
9e33bed55   Trond Myklebust   NFSv4: Add recove...
1891
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1892
  		default:
72211dbe7   Trond Myklebust   NFSv4: Release th...
1893
1894
  			if (nfs4_async_handle_error(task, server, state) == -EAGAIN)
  				rpc_restart_call_prepare(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1895
  	}
72211dbe7   Trond Myklebust   NFSv4: Release th...
1896
  	nfs_release_seqid(calldata->arg.seqid);
516a6af64   Trond Myklebust   NFS: Add optional...
1897
  	nfs_refresh_inode(calldata->inode, calldata->res.fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1898
  }
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
1899
  static void nfs4_close_prepare(struct rpc_task *task, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1900
  {
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
1901
  	struct nfs4_closedata *calldata = data;
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1902
  	struct nfs4_state *state = calldata->state;
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1903
  	int call_close = 0;
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1904

963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1905
  	if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1906
  		return;
003707c72   Trond Myklebust   NFSv4: Always use...
1907

88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1908
1909
  	task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE];
  	calldata->arg.fmode = FMODE_READ|FMODE_WRITE;
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
1910
  	spin_lock(&state->owner->so_lock);
003707c72   Trond Myklebust   NFSv4: Always use...
1911
  	/* Calculate the change in open mode */
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
1912
  	if (state->n_rdwr == 0) {
003707c72   Trond Myklebust   NFSv4: Always use...
1913
  		if (state->n_rdonly == 0) {
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1914
1915
1916
  			call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
  			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
  			calldata->arg.fmode &= ~FMODE_READ;
003707c72   Trond Myklebust   NFSv4: Always use...
1917
1918
  		}
  		if (state->n_wronly == 0) {
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1919
1920
1921
  			call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
  			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
  			calldata->arg.fmode &= ~FMODE_WRITE;
003707c72   Trond Myklebust   NFSv4: Always use...
1922
  		}
e76169238   Trond Myklebust   NFSv4: Make nfs4_...
1923
  	}
4cecb76ff   Trond Myklebust   NFSv4: Fix a race...
1924
  	spin_unlock(&state->owner->so_lock);
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1925
1926
  
  	if (!call_close) {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1927
1928
  		/* Note: exit _without_ calling nfs4_close_done */
  		task->tk_action = NULL;
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1929
1930
  		return;
  	}
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1931

f7e8917a6   Fred Isaman   pnfs: layout roc ...
1932
  	if (calldata->arg.fmode == 0) {
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1933
  		task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
f7e8917a6   Fred Isaman   pnfs: layout roc ...
1934
1935
1936
1937
1938
1939
1940
  		if (calldata->roc &&
  		    pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) {
  			rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq,
  				     task, NULL);
  			return;
  		}
  	}
88069f77e   Trond Myklebust   NFSv41: Fix a pot...
1941

516a6af64   Trond Myklebust   NFS: Add optional...
1942
  	nfs_fattr_init(calldata->res.fattr);
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
1943
  	calldata->timestamp = jiffies;
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
1944
  	if (nfs4_setup_sequence(NFS_SERVER(calldata->inode),
19ddab06e   Andy Adamson   nfs41: close sequ...
1945
1946
1947
  				&calldata->arg.seq_args, &calldata->res.seq_res,
  				1, task))
  		return;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1948
  	rpc_call_start(task);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1949
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1950
  static const struct rpc_call_ops nfs4_close_ops = {
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
1951
  	.rpc_call_prepare = nfs4_close_prepare,
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
1952
1953
1954
  	.rpc_call_done = nfs4_close_done,
  	.rpc_release = nfs4_free_closedata,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
  /* 
   * It is possible for data to be read/written from a mem-mapped file 
   * after the sys_close call (which hits the vfs layer as a flush).
   * This means that we can't safely call nfsv4 close on a file until 
   * the inode is cleared. This in turn means that we are not good
   * NFSv4 citizens - we do not indicate to the server to update the file's 
   * share state even when we are done with one of the three share 
   * stateid's in the inode.
   *
   * NOTE: Caller must be holding the sp->so_owner semaphore!
   */
643168c2d   Al Viro   nfs4_closedata do...
1966
  int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait, bool roc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1967
  {
4a35bd41a   Trond Myklebust   NFSv4: Ensure tha...
1968
  	struct nfs_server *server = NFS_SERVER(state->inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1969
  	struct nfs4_closedata *calldata;
b39e625b6   Trond Myklebust   NFSv4: Clean up n...
1970
1971
  	struct nfs4_state_owner *sp = state->owner;
  	struct rpc_task *task;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1972
1973
1974
1975
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE],
  		.rpc_cred = state->owner->so_cred,
  	};
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1976
1977
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = server->client,
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
1978
  		.rpc_message = &msg,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1979
  		.callback_ops = &nfs4_close_ops,
101070ca2   Trond Myklebust   NFS: Ensure that ...
1980
  		.workqueue = nfsiod_workqueue,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
1981
1982
  		.flags = RPC_TASK_ASYNC,
  	};
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1983
  	int status = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1984

8535b2be5   Trond Myklebust   NFSv4: Don't use ...
1985
  	calldata = kzalloc(sizeof(*calldata), gfp_mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1986
  	if (calldata == NULL)
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1987
  		goto out;
4a35bd41a   Trond Myklebust   NFSv4: Ensure tha...
1988
  	calldata->inode = state->inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1989
  	calldata->state = state;
4a35bd41a   Trond Myklebust   NFSv4: Ensure tha...
1990
  	calldata->arg.fh = NFS_FH(state->inode);
003707c72   Trond Myklebust   NFSv4: Always use...
1991
  	calldata->arg.stateid = &state->open_stateid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1992
  	/* Serialization for the sequence id */
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
1993
  	calldata->arg.seqid = nfs_alloc_seqid(&state->owner->so_seqid, gfp_mask);
9512135df   Trond Myklebust   NFSv4: Fix a pote...
1994
1995
  	if (calldata->arg.seqid == NULL)
  		goto out_free_calldata;
dc0b027df   Trond Myklebust   NFSv4: Convert th...
1996
  	calldata->arg.fmode = 0;
a65318bf3   Trond Myklebust   NFSv4: Simplify s...
1997
  	calldata->arg.bitmask = server->cache_consistency_bitmask;
516a6af64   Trond Myklebust   NFS: Add optional...
1998
  	calldata->res.fattr = &calldata->fattr;
c1d519312   Trond Myklebust   NFSv4: Only incre...
1999
  	calldata->res.seqid = calldata->arg.seqid;
516a6af64   Trond Myklebust   NFS: Add optional...
2000
  	calldata->res.server = server;
f7e8917a6   Fred Isaman   pnfs: layout roc ...
2001
  	calldata->roc = roc;
643168c2d   Al Viro   nfs4_closedata do...
2002
  	nfs_sb_active(calldata->inode->i_sb);
9512135df   Trond Myklebust   NFSv4: Fix a pote...
2003

1174dd1f8   Trond Myklebust   NFSv4: Convert a ...
2004
2005
  	msg.rpc_argp = &calldata->arg;
  	msg.rpc_resp = &calldata->res;
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
2006
2007
  	task_setup_data.callback_data = calldata;
  	task = rpc_run_task(&task_setup_data);
b39e625b6   Trond Myklebust   NFSv4: Clean up n...
2008
2009
  	if (IS_ERR(task))
  		return PTR_ERR(task);
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
2010
2011
2012
  	status = 0;
  	if (wait)
  		status = rpc_wait_for_completion_task(task);
b39e625b6   Trond Myklebust   NFSv4: Clean up n...
2013
  	rpc_put_task(task);
a49c3c773   Trond Myklebust   NFSv4: Ensure tha...
2014
  	return status;
9512135df   Trond Myklebust   NFSv4: Fix a pote...
2015
2016
2017
  out_free_calldata:
  	kfree(calldata);
  out:
f7e8917a6   Fred Isaman   pnfs: layout roc ...
2018
2019
  	if (roc)
  		pnfs_roc_release(state->inode);
b39e625b6   Trond Myklebust   NFSv4: Clean up n...
2020
2021
  	nfs4_put_open_state(state);
  	nfs4_put_state_owner(sp);
9512135df   Trond Myklebust   NFSv4: Fix a pote...
2022
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2023
  }
2b484297e   Trond Myklebust   NFS: Add an 'open...
2024
  static struct inode *
cd9a1c0e5   Trond Myklebust   NFSv4: Clean up n...
2025
  nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx, int open_flags, struct iattr *attr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2026
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2027
  	struct nfs4_state *state;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2028

565277f63   Trond Myklebust   NFS: Fix a race i...
2029
  	/* Protect against concurrent sillydeletes */
3d4ff43d8   Al Viro   nfs_open_context ...
2030
  	state = nfs4_do_open(dir, ctx->dentry, ctx->mode, open_flags, attr, ctx->cred);
f46e0bd34   Trond Myklebust   NFSv4: Further mi...
2031
2032
  	if (IS_ERR(state))
  		return ERR_CAST(state);
cd9a1c0e5   Trond Myklebust   NFSv4: Clean up n...
2033
  	ctx->state = state;
f46e0bd34   Trond Myklebust   NFSv4: Further mi...
2034
  	return igrab(state->inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2035
  }
1185a552e   Trond Myklebust   NFSv4: Ensure nfs...
2036
  static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
7fe5c398f   Trond Myklebust   NFS: Optimise NFS...
2037
2038
2039
2040
  {
  	if (ctx->state == NULL)
  		return;
  	if (is_sync)
643168c2d   Al Viro   nfs4_closedata do...
2041
  		nfs4_close_sync(ctx->state, ctx->mode);
7fe5c398f   Trond Myklebust   NFS: Optimise NFS...
2042
  	else
643168c2d   Al Viro   nfs4_closedata do...
2043
  		nfs4_close_state(ctx->state, ctx->mode);
7fe5c398f   Trond Myklebust   NFS: Optimise NFS...
2044
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2045
2046
2047
  
  static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
  {
43652ad55   Benny Halevy   nfs41: use nfs4_s...
2048
2049
2050
  	struct nfs4_server_caps_arg args = {
  		.fhandle = fhandle,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2051
2052
2053
  	struct nfs4_server_caps_res res = {};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS],
43652ad55   Benny Halevy   nfs41: use nfs4_s...
2054
  		.rpc_argp = &args,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2055
2056
2057
  		.rpc_resp = &res,
  	};
  	int status;
7c5130588   Bryan Schumaker   NFS: lookup suppo...
2058
  	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2059
2060
  	if (status == 0) {
  		memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask));
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
2061
2062
2063
2064
2065
  		server->caps &= ~(NFS_CAP_ACLS|NFS_CAP_HARDLINKS|
  				NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
  				NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|
  				NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME|
  				NFS_CAP_CTIME|NFS_CAP_MTIME);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2066
2067
2068
2069
2070
2071
  		if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
  			server->caps |= NFS_CAP_ACLS;
  		if (res.has_links != 0)
  			server->caps |= NFS_CAP_HARDLINKS;
  		if (res.has_symlinks != 0)
  			server->caps |= NFS_CAP_SYMLINKS;
62ab460cf   Trond Myklebust   NFSv4: Add 'serve...
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
  		if (res.attr_bitmask[0] & FATTR4_WORD0_FILEID)
  			server->caps |= NFS_CAP_FILEID;
  		if (res.attr_bitmask[1] & FATTR4_WORD1_MODE)
  			server->caps |= NFS_CAP_MODE;
  		if (res.attr_bitmask[1] & FATTR4_WORD1_NUMLINKS)
  			server->caps |= NFS_CAP_NLINK;
  		if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER)
  			server->caps |= NFS_CAP_OWNER;
  		if (res.attr_bitmask[1] & FATTR4_WORD1_OWNER_GROUP)
  			server->caps |= NFS_CAP_OWNER_GROUP;
  		if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_ACCESS)
  			server->caps |= NFS_CAP_ATIME;
  		if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_METADATA)
  			server->caps |= NFS_CAP_CTIME;
  		if (res.attr_bitmask[1] & FATTR4_WORD1_TIME_MODIFY)
  			server->caps |= NFS_CAP_MTIME;
a65318bf3   Trond Myklebust   NFSv4: Simplify s...
2088
2089
2090
  		memcpy(server->cache_consistency_bitmask, res.attr_bitmask, sizeof(server->cache_consistency_bitmask));
  		server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE;
  		server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2091
2092
  		server->acl_bitmask = res.acl_bitmask;
  	}
cccef3b96   Andy Adamson   nfs41: introduce ...
2093

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2094
2095
  	return status;
  }
55a975937   Trond Myklebust   NFS: Ensure the c...
2096
  int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(server,
  				_nfs4_server_capabilities(server, fhandle),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
  		struct nfs_fsinfo *info)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2111
2112
2113
2114
2115
  	struct nfs4_lookup_root_arg args = {
  		.bitmask = nfs4_fattr_bitmap,
  	};
  	struct nfs4_lookup_res res = {
  		.server = server,
0e574af1b   Trond Myklebust   NFS: Cleanup init...
2116
  		.fattr = info->fattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2117
2118
2119
2120
2121
2122
2123
  		.fh = fhandle,
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
008f55d0e   Benny Halevy   nfs41: recover le...
2124

0e574af1b   Trond Myklebust   NFS: Cleanup init...
2125
  	nfs_fattr_init(info->fattr);
7c5130588   Bryan Schumaker   NFS: lookup suppo...
2126
  	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2127
2128
2129
2130
2131
2132
2133
2134
  }
  
  static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
  		struct nfs_fsinfo *info)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
fb8a5ba81   Bryan Schumaker   NFSv4: Handle NFS...
2135
2136
2137
2138
2139
2140
2141
2142
  		err = _nfs4_lookup_root(server, fhandle, info);
  		switch (err) {
  		case 0:
  		case -NFS4ERR_WRONGSEC:
  			break;
  		default:
  			err = nfs4_handle_exception(server, err, &exception);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
2144
2145
  	} while (exception.retry);
  	return err;
  }
8f70e95f9   Bryan Schumaker   NFS: Determine in...
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
  static int nfs4_lookup_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
  				struct nfs_fsinfo *info, rpc_authflavor_t flavor)
  {
  	struct rpc_auth *auth;
  	int ret;
  
  	auth = rpcauth_create(flavor, server->client);
  	if (!auth) {
  		ret = -EIO;
  		goto out;
  	}
  	ret = nfs4_lookup_root(server, fhandle, info);
8f70e95f9   Bryan Schumaker   NFS: Determine in...
2158
2159
2160
  out:
  	return ret;
  }
801a16dc7   Bryan Schumaker   NFS: Attempt moun...
2161
  static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
54ceac451   David Howells   NFS: Share NFS su...
2162
  			      struct nfs_fsinfo *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2163
  {
8f70e95f9   Bryan Schumaker   NFS: Determine in...
2164
  	int i, len, status = 0;
0fabee243   Bryan Schumaker   NFS: flav_array h...
2165
  	rpc_authflavor_t flav_array[NFS_MAX_SECFLAVORS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2166

801a16dc7   Bryan Schumaker   NFS: Attempt moun...
2167
2168
2169
  	len = gss_mech_list_pseudoflavors(&flav_array[0]);
  	flav_array[len] = RPC_AUTH_NULL;
  	len += 1;
8f70e95f9   Bryan Schumaker   NFS: Determine in...
2170
2171
2172
  
  	for (i = 0; i < len; i++) {
  		status = nfs4_lookup_root_sec(server, fhandle, info, flav_array[i]);
fb8a5ba81   Bryan Schumaker   NFSv4: Handle NFS...
2173
  		if (status == -NFS4ERR_WRONGSEC || status == -EACCES)
d1a8016a2   Bryan Schumaker   NFS: Fix infinite...
2174
2175
  			continue;
  		break;
8f70e95f9   Bryan Schumaker   NFS: Determine in...
2176
  	}
fb8a5ba81   Bryan Schumaker   NFSv4: Handle NFS...
2177
2178
2179
2180
2181
2182
2183
2184
2185
  	/*
  	 * -EACCESS could mean that the user doesn't have correct permissions
  	 * to access the mount.  It could also mean that we tried to mount
  	 * with a gss auth flavor, but rpc.gssd isn't running.  Either way,
  	 * existing mount programs don't handle -EACCES very well so it should
  	 * be mapped to -EPERM instead.
  	 */
  	if (status == -EACCES)
  		status = -EPERM;
801a16dc7   Bryan Schumaker   NFS: Attempt moun...
2186
2187
2188
2189
2190
2191
2192
2193
2194
  	return status;
  }
  
  /*
   * get the file handle for the "/" directory on the server
   */
  static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
  			      struct nfs_fsinfo *info)
  {
fca78d6d2   Bryan Schumaker   NFS: Add SECINFO_...
2195
  	int minor_version = server->nfs_client->cl_minorversion;
801a16dc7   Bryan Schumaker   NFS: Attempt moun...
2196
  	int status = nfs4_lookup_root(server, fhandle, info);
fb8a5ba81   Bryan Schumaker   NFSv4: Handle NFS...
2197
2198
2199
2200
2201
  	if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR))
  		/*
  		 * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM
  		 * by nfs4_map_errors() as this function exits.
  		 */
fca78d6d2   Bryan Schumaker   NFS: Add SECINFO_...
2202
  		status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2203
2204
2205
2206
  	if (status == 0)
  		status = nfs4_server_capabilities(server, fhandle);
  	if (status == 0)
  		status = nfs4_do_fsinfo(server, fhandle, info);
c12e87f46   Trond Myklebust   [PATCH] NFSv4: fi...
2207
  	return nfs4_map_errors(status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2208
  }
533eb4611   Andy Adamson   NFSv4.1: allow nf...
2209
  static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
2210
2211
2212
2213
2214
  /*
   * Get locations and (maybe) other attributes of a referral.
   * Note that we'll actually follow the referral later when
   * we detect fsid mismatch in inode revalidation
   */
533eb4611   Andy Adamson   NFSv4.1: allow nf...
2215
2216
  static int nfs4_get_referral(struct inode *dir, const struct qstr *name,
  			     struct nfs_fattr *fattr, struct nfs_fh *fhandle)
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
2217
2218
2219
2220
  {
  	int status = -ENOMEM;
  	struct page *page = NULL;
  	struct nfs4_fs_locations *locations = NULL;
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
2221
2222
2223
2224
2225
2226
2227
  
  	page = alloc_page(GFP_KERNEL);
  	if (page == NULL)
  		goto out;
  	locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
  	if (locations == NULL)
  		goto out;
c228fd3ae   Trond Myklebust   NFSv4: Cleanups f...
2228
  	status = nfs4_proc_fs_locations(dir, name, locations, page);
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
2229
2230
2231
2232
  	if (status != 0)
  		goto out;
  	/* Make sure server returned a different fsid for the referral */
  	if (nfs_fsid_equal(&NFS_SERVER(dir)->fsid, &locations->fattr.fsid)) {
533eb4611   Andy Adamson   NFSv4.1: allow nf...
2233
2234
2235
  		dprintk("%s: server did not return a different fsid for"
  			" a referral at %s
  ", __func__, name->name);
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
2236
2237
2238
  		status = -EIO;
  		goto out;
  	}
533eb4611   Andy Adamson   NFSv4.1: allow nf...
2239
2240
  	/* Fixup attributes for the nfs_lookup() call to nfs_fhget() */
  	nfs_fixup_referral_attributes(&locations->fattr);
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
2241

533eb4611   Andy Adamson   NFSv4.1: allow nf...
2242
  	/* replace the lookup nfs_fattr with the locations nfs_fattr */
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
2243
  	memcpy(fattr, &locations->fattr, sizeof(struct nfs_fattr));
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
2244
2245
2246
2247
  	memset(fhandle, 0, sizeof(struct nfs_fh));
  out:
  	if (page)
  		__free_page(page);
5d7ca35a1   Davidlohr Bueso   nfs: Remove redun...
2248
  	kfree(locations);
6b97fd3da   Manoj Naik   NFSv4: Follow a r...
2249
2250
  	return status;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
  static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
  {
  	struct nfs4_getattr_arg args = {
  		.fh = fhandle,
  		.bitmask = server->attr_bitmask,
  	};
  	struct nfs4_getattr_res res = {
  		.fattr = fattr,
  		.server = server,
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  	
0e574af1b   Trond Myklebust   NFS: Cleanup init...
2267
  	nfs_fattr_init(fattr);
7c5130588   Bryan Schumaker   NFS: lookup suppo...
2268
  	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
  }
  
  static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(server,
  				_nfs4_proc_getattr(server, fhandle, fattr),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  /* 
   * The file is not closed if it is opened due to the a request to change
   * the size of the file. The open call will not be needed once the
   * VFS layer lookup-intents are implemented.
   *
   * Close is called when the inode is destroyed.
   * If we haven't opened the file for O_WRONLY, we
   * need to in the size_change case to obtain a stateid.
   *
   * Got race?
   * Because OPEN is always done by name in nfsv4, it is
   * possible that we opened a different file by the same
   * name.  We can recognize this race condition, but we
   * can't do anything about it besides returning an error.
   *
   * This will be fixed with VFS changes (lookup-intent).
   */
  static int
  nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
  		  struct iattr *sattr)
  {
08e9eac42   Trond Myklebust   [PATCH] NFSv4: Fi...
2304
  	struct inode *inode = dentry->d_inode;
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
2305
  	struct rpc_cred *cred = NULL;
d530838bf   Trond Myklebust   NFSv4: Fix proble...
2306
  	struct nfs4_state *state = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2307
  	int status;
8a1636c45   Benny Halevy   pnfs: layoutret_o...
2308
2309
  	if (pnfs_ld_layoutret_on_setattr(inode))
  		pnfs_return_layout(inode);
0e574af1b   Trond Myklebust   NFS: Cleanup init...
2310
  	nfs_fattr_init(fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2311
  	
d530838bf   Trond Myklebust   NFSv4: Fix proble...
2312
  	/* Search for an existing open(O_WRITE) file */
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
2313
2314
2315
2316
  	if (sattr->ia_valid & ATTR_FILE) {
  		struct nfs_open_context *ctx;
  
  		ctx = nfs_file_open_context(sattr->ia_file);
504e51895   Neil Brown   Make nfs_file_cre...
2317
2318
2319
2320
  		if (ctx) {
  			cred = ctx->cred;
  			state = ctx->state;
  		}
659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
2321
  	}
08e9eac42   Trond Myklebust   [PATCH] NFSv4: Fi...
2322

659bfcd6d   Trond Myklebust   NFS: Fix the ftru...
2323
  	status = nfs4_do_setattr(inode, cred, fattr, sattr, state);
65e4308d2   Trond Myklebust   [PATCH] NFS: Ensu...
2324
2325
  	if (status == 0)
  		nfs_setattr_update_inode(inode, sattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2326
2327
  	return status;
  }
0c2e53f11   Trond Myklebust   NFS: Remove the u...
2328
2329
2330
  static int _nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir,
  		const struct qstr *name, struct nfs_fh *fhandle,
  		struct nfs_fattr *fattr)
2b3de4411   David Howells   NFS: Add a lookup...
2331
  {
0c2e53f11   Trond Myklebust   NFS: Remove the u...
2332
  	struct nfs_server *server = NFS_SERVER(dir);
2b3de4411   David Howells   NFS: Add a lookup...
2333
2334
2335
  	int		       status;
  	struct nfs4_lookup_arg args = {
  		.bitmask = server->attr_bitmask,
0c2e53f11   Trond Myklebust   NFS: Remove the u...
2336
  		.dir_fh = NFS_FH(dir),
2b3de4411   David Howells   NFS: Add a lookup...
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
  		.name = name,
  	};
  	struct nfs4_lookup_res res = {
  		.server = server,
  		.fattr = fattr,
  		.fh = fhandle,
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  
  	nfs_fattr_init(fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2351
2352
  	dprintk("NFS call  lookup %s
  ", name->name);
0c2e53f11   Trond Myklebust   NFS: Remove the u...
2353
  	status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, &res.seq_res, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2354
2355
2356
2357
  	dprintk("NFS reply lookup: %d
  ", status);
  	return status;
  }
7ebb93159   Bryan Schumaker   NFS: use secinfo ...
2358
2359
2360
2361
2362
2363
2364
2365
2366
  void nfs_fixup_secinfo_attributes(struct nfs_fattr *fattr, struct nfs_fh *fh)
  {
  	memset(fh, 0, sizeof(struct nfs_fh));
  	fattr->fsid.major = 1;
  	fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
  		NFS_ATTR_FATTR_NLINK | NFS_ATTR_FATTR_FSID | NFS_ATTR_FATTR_MOUNTPOINT;
  	fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
  	fattr->nlink = 2;
  }
7c5130588   Bryan Schumaker   NFS: lookup suppo...
2367
2368
  static int nfs4_proc_lookup(struct rpc_clnt *clnt, struct inode *dir, struct qstr *name,
  			    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2369
2370
2371
2372
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
0c2e53f11   Trond Myklebust   NFS: Remove the u...
2373
2374
2375
2376
  		int status;
  
  		status = _nfs4_proc_lookup(clnt, dir, name, fhandle, fattr);
  		switch (status) {
08ef7bd3b   Trond Myklebust   NFSv4: Translate ...
2377
2378
  		case -NFS4ERR_BADNAME:
  			return -ENOENT;
0c2e53f11   Trond Myklebust   NFS: Remove the u...
2379
  		case -NFS4ERR_MOVED:
a6f498a89   Trond Myklebust   NFS: Fix a regres...
2380
  			return nfs4_get_referral(dir, name, fattr, fhandle);
0c2e53f11   Trond Myklebust   NFS: Remove the u...
2381
  		case -NFS4ERR_WRONGSEC:
7ebb93159   Bryan Schumaker   NFS: use secinfo ...
2382
  			nfs_fixup_secinfo_attributes(fattr, fhandle);
0c2e53f11   Trond Myklebust   NFS: Remove the u...
2383
2384
2385
  		}
  		err = nfs4_handle_exception(NFS_SERVER(dir),
  				status, &exception);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2386
2387
2388
2389
2390
2391
  	} while (exception.retry);
  	return err;
  }
  
  static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
  {
76b32999d   Trond Myklebust   NFSv4: Make NFSv4...
2392
  	struct nfs_server *server = NFS_SERVER(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2393
2394
  	struct nfs4_accessargs args = {
  		.fh = NFS_FH(inode),
76b32999d   Trond Myklebust   NFSv4: Make NFSv4...
2395
2396
2397
2398
  		.bitmask = server->attr_bitmask,
  	};
  	struct nfs4_accessres res = {
  		.server = server,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2399
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  		.rpc_cred = entry->cred,
  	};
  	int mode = entry->mask;
  	int status;
  
  	/*
  	 * Determine which access bits we want to ask for...
  	 */
  	if (mode & MAY_READ)
  		args.access |= NFS4_ACCESS_READ;
  	if (S_ISDIR(inode->i_mode)) {
  		if (mode & MAY_WRITE)
  			args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;
  		if (mode & MAY_EXEC)
  			args.access |= NFS4_ACCESS_LOOKUP;
  	} else {
  		if (mode & MAY_WRITE)
  			args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;
  		if (mode & MAY_EXEC)
  			args.access |= NFS4_ACCESS_EXECUTE;
  	}
c407d41a1   Trond Myklebust   NFSv4: Reduce sta...
2425
2426
2427
2428
  
  	res.fattr = nfs_alloc_fattr();
  	if (res.fattr == NULL)
  		return -ENOMEM;
7c5130588   Bryan Schumaker   NFS: lookup suppo...
2429
  	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2430
2431
2432
2433
2434
2435
2436
2437
  	if (!status) {
  		entry->mask = 0;
  		if (res.access & NFS4_ACCESS_READ)
  			entry->mask |= MAY_READ;
  		if (res.access & (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
  			entry->mask |= MAY_WRITE;
  		if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
  			entry->mask |= MAY_EXEC;
c407d41a1   Trond Myklebust   NFSv4: Reduce sta...
2438
  		nfs_refresh_inode(inode, res.fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2439
  	}
c407d41a1   Trond Myklebust   NFSv4: Reduce sta...
2440
  	nfs_free_fattr(res.fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
  	return status;
  }
  
  static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(inode),
  				_nfs4_proc_access(inode, entry),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  /*
   * TODO: For the time being, we don't try to get any attributes
   * along with any of the zero-copy operations READ, READDIR,
   * READLINK, WRITE.
   *
   * In the case of the first three, we want to put the GETATTR
   * after the read-type operation -- this is because it is hard
   * to predict the length of a GETATTR response in v4, and thus
   * align the READ data correctly.  This means that the GETATTR
   * may end up partially falling into the page cache, and we should
   * shift it into the 'tail' of the xdr_buf before processing.
   * To do this efficiently, we need to know the total length
   * of data received, which doesn't seem to be available outside
   * of the RPC layer.
   *
   * In the case of WRITE, we also want to put the GETATTR after
   * the operation -- in this case because we want to make sure
   * we get the post-operation mtime and size.  This means that
   * we can't use xdr_encode_pages() as written: we need a variant
   * of it which would leave room in the 'tail' iovec.
   *
   * Both of these changes to the XDR layer would in fact be quite
   * minor, but I decided to leave them for a subsequent patch.
   */
  static int _nfs4_proc_readlink(struct inode *inode, struct page *page,
  		unsigned int pgbase, unsigned int pglen)
  {
  	struct nfs4_readlink args = {
  		.fh       = NFS_FH(inode),
  		.pgbase	  = pgbase,
  		.pglen    = pglen,
  		.pages    = &page,
  	};
f50c70008   Benny Halevy   nfs41: use nfs4_r...
2489
  	struct nfs4_readlink_res res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2490
2491
2492
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK],
  		.rpc_argp = &args,
f50c70008   Benny Halevy   nfs41: use nfs4_r...
2493
  		.rpc_resp = &res,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2494
  	};
7c5130588   Bryan Schumaker   NFS: lookup suppo...
2495
  	return nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode), &msg, &args.seq_args, &res.seq_res, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
  }
  
  static int nfs4_proc_readlink(struct inode *inode, struct page *page,
  		unsigned int pgbase, unsigned int pglen)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(inode),
  				_nfs4_proc_readlink(inode, page, pgbase, pglen),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
  /*
   * Got race?
   * We will need to arrange for the VFS layer to provide an atomic open.
   * Until then, this create/open method is prone to inefficiency and race
   * conditions due to the lookup, create, and open VFS calls from sys_open()
   * placed on the wire.
   *
   * Given the above sorry state of affairs, I'm simply sending an OPEN.
   * The file will be opened again in the subsequent VFS open call
   * (nfs4_proc_file_open).
   *
   * The open for read will just hang around to be used by any process that
   * opens the file O_RDONLY. This will all be resolved with the VFS changes.
   */
  
  static int
  nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
c0204fd2b   Trond Myklebust   NFS: Clean up nfs...
2527
                   int flags, struct nfs_open_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2528
  {
82a2c1b77   Al Viro   nfs4_opendata doe...
2529
  	struct dentry *de = dentry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2530
  	struct nfs4_state *state;
c0204fd2b   Trond Myklebust   NFS: Clean up nfs...
2531
2532
  	struct rpc_cred *cred = NULL;
  	fmode_t fmode = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2533
  	int status = 0;
c0204fd2b   Trond Myklebust   NFS: Clean up nfs...
2534
2535
  	if (ctx != NULL) {
  		cred = ctx->cred;
3d4ff43d8   Al Viro   nfs_open_context ...
2536
  		de = ctx->dentry;
c0204fd2b   Trond Myklebust   NFS: Clean up nfs...
2537
  		fmode = ctx->mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2538
  	}
a8a5da996   Aneesh Kumar K.V   nfs: Set MS_POSIX...
2539
  	sattr->ia_mode &= ~current_umask();
82a2c1b77   Al Viro   nfs4_opendata doe...
2540
  	state = nfs4_do_open(dir, de, fmode, flags, sattr, cred);
d4d9cdcb4   Trond Myklebust   NFS: Don't hash t...
2541
  	d_drop(dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2542
2543
  	if (IS_ERR(state)) {
  		status = PTR_ERR(state);
c0204fd2b   Trond Myklebust   NFS: Clean up nfs...
2544
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2545
  	}
d4d9cdcb4   Trond Myklebust   NFS: Don't hash t...
2546
  	d_add(dentry, igrab(state->inode));
d75340cc4   Trond Myklebust   NFSv4: Fix nfs_at...
2547
  	nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
c0204fd2b   Trond Myklebust   NFS: Clean up nfs...
2548
2549
  	if (ctx != NULL)
  		ctx->state = state;
02a913a73   Trond Myklebust   NFSv4: Eliminate ...
2550
  	else
643168c2d   Al Viro   nfs4_closedata do...
2551
  		nfs4_close_sync(state, fmode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2552
2553
2554
2555
2556
2557
  out:
  	return status;
  }
  
  static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
  {
16e429596   Trond Myklebust   NFSv4: Add post-o...
2558
  	struct nfs_server *server = NFS_SERVER(dir);
4fdc17b2a   Trond Myklebust   NFS: Introduce st...
2559
  	struct nfs_removeargs args = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2560
  		.fh = NFS_FH(dir),
4fdc17b2a   Trond Myklebust   NFS: Introduce st...
2561
2562
  		.name.len = name->len,
  		.name.name = name->name,
16e429596   Trond Myklebust   NFSv4: Add post-o...
2563
2564
  		.bitmask = server->attr_bitmask,
  	};
4fdc17b2a   Trond Myklebust   NFS: Introduce st...
2565
  	struct nfs_removeres res = {
16e429596   Trond Myklebust   NFSv4: Add post-o...
2566
  		.server = server,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2567
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2568
  	struct rpc_message msg = {
4fdc17b2a   Trond Myklebust   NFS: Introduce st...
2569
2570
2571
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2572
  	};
d346890be   Trond Myklebust   NFS: Reduce stack...
2573
2574
2575
2576
2577
  	int status = -ENOMEM;
  
  	res.dir_attr = nfs_alloc_fattr();
  	if (res.dir_attr == NULL)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2578

7c5130588   Bryan Schumaker   NFS: lookup suppo...
2579
  	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 1);
16e429596   Trond Myklebust   NFSv4: Add post-o...
2580
2581
  	if (status == 0) {
  		update_changeattr(dir, &res.cinfo);
d346890be   Trond Myklebust   NFS: Reduce stack...
2582
  		nfs_post_op_update_inode(dir, res.dir_attr);
16e429596   Trond Myklebust   NFSv4: Add post-o...
2583
  	}
d346890be   Trond Myklebust   NFS: Reduce stack...
2584
2585
  	nfs_free_fattr(res.dir_attr);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
  	return status;
  }
  
  static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(dir),
  				_nfs4_proc_remove(dir, name),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
2600
  static void nfs4_proc_unlink_setup(struct rpc_message *msg, struct inode *dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2601
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
2602
2603
2604
  	struct nfs_server *server = NFS_SERVER(dir);
  	struct nfs_removeargs *args = msg->rpc_argp;
  	struct nfs_removeres *res = msg->rpc_resp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2605

a65318bf3   Trond Myklebust   NFSv4: Simplify s...
2606
  	args->bitmask = server->cache_consistency_bitmask;
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
2607
  	res->server = server;
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
2608
  	res->seq_res.sr_slot = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2609
  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2610
  }
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
2611
  static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2612
  {
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
2613
  	struct nfs_removeres *res = task->tk_msg.rpc_resp;
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
2614
2615
  	if (!nfs4_sequence_done(task, &res->seq_res))
  		return 0;
9e33bed55   Trond Myklebust   NFSv4: Add recove...
2616
  	if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
2617
2618
  		return 0;
  	update_changeattr(dir, &res->cinfo);
d346890be   Trond Myklebust   NFS: Reduce stack...
2619
  	nfs_post_op_update_inode(dir, res->dir_attr);
e4eff1a62   Trond Myklebust   SUNRPC: Clean up ...
2620
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2621
  }
d3d4152a5   Jeff Layton   nfs: make sillyre...
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
  static void nfs4_proc_rename_setup(struct rpc_message *msg, struct inode *dir)
  {
  	struct nfs_server *server = NFS_SERVER(dir);
  	struct nfs_renameargs *arg = msg->rpc_argp;
  	struct nfs_renameres *res = msg->rpc_resp;
  
  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME];
  	arg->bitmask = server->attr_bitmask;
  	res->server = server;
  }
  
  static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
  				 struct inode *new_dir)
  {
  	struct nfs_renameres *res = task->tk_msg.rpc_resp;
  
  	if (!nfs4_sequence_done(task, &res->seq_res))
  		return 0;
  	if (nfs4_async_handle_error(task, res->server, NULL) == -EAGAIN)
  		return 0;
  
  	update_changeattr(old_dir, &res->old_cinfo);
  	nfs_post_op_update_inode(old_dir, res->old_fattr);
  	update_changeattr(new_dir, &res->new_cinfo);
  	nfs_post_op_update_inode(new_dir, res->new_fattr);
  	return 1;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2649
2650
2651
  static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
  		struct inode *new_dir, struct qstr *new_name)
  {
6caf2c827   Trond Myklebust   NFSv4: Add post-o...
2652
  	struct nfs_server *server = NFS_SERVER(old_dir);
920769f03   Jeff Layton   nfs: standardize ...
2653
  	struct nfs_renameargs arg = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2654
2655
2656
2657
  		.old_dir = NFS_FH(old_dir),
  		.new_dir = NFS_FH(new_dir),
  		.old_name = old_name,
  		.new_name = new_name,
6caf2c827   Trond Myklebust   NFSv4: Add post-o...
2658
2659
  		.bitmask = server->attr_bitmask,
  	};
e8582a8b9   Jeff Layton   nfs: standardize ...
2660
  	struct nfs_renameres res = {
6caf2c827   Trond Myklebust   NFSv4: Add post-o...
2661
  		.server = server,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2662
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2663
2664
2665
2666
2667
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME],
  		.rpc_argp = &arg,
  		.rpc_resp = &res,
  	};
011fff723   Trond Myklebust   NFS: Reduce stack...
2668
  	int status = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2669
  	
011fff723   Trond Myklebust   NFS: Reduce stack...
2670
2671
2672
2673
  	res.old_fattr = nfs_alloc_fattr();
  	res.new_fattr = nfs_alloc_fattr();
  	if (res.old_fattr == NULL || res.new_fattr == NULL)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2674

7c5130588   Bryan Schumaker   NFS: lookup suppo...
2675
  	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2676
2677
  	if (!status) {
  		update_changeattr(old_dir, &res.old_cinfo);
6caf2c827   Trond Myklebust   NFSv4: Add post-o...
2678
  		nfs_post_op_update_inode(old_dir, res.old_fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2679
  		update_changeattr(new_dir, &res.new_cinfo);
6caf2c827   Trond Myklebust   NFSv4: Add post-o...
2680
  		nfs_post_op_update_inode(new_dir, res.new_fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2681
  	}
011fff723   Trond Myklebust   NFS: Reduce stack...
2682
2683
2684
  out:
  	nfs_free_fattr(res.new_fattr);
  	nfs_free_fattr(res.old_fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
  	return status;
  }
  
  static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
  		struct inode *new_dir, struct qstr *new_name)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(old_dir),
  				_nfs4_proc_rename(old_dir, old_name,
  					new_dir, new_name),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
  {
91ba2eeec   Trond Myklebust   NFSv4: Add post-o...
2704
  	struct nfs_server *server = NFS_SERVER(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2705
2706
2707
2708
  	struct nfs4_link_arg arg = {
  		.fh     = NFS_FH(inode),
  		.dir_fh = NFS_FH(dir),
  		.name   = name,
91ba2eeec   Trond Myklebust   NFSv4: Add post-o...
2709
2710
  		.bitmask = server->attr_bitmask,
  	};
91ba2eeec   Trond Myklebust   NFSv4: Add post-o...
2711
2712
  	struct nfs4_link_res res = {
  		.server = server,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2713
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2714
2715
2716
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
  		.rpc_argp = &arg,
91ba2eeec   Trond Myklebust   NFSv4: Add post-o...
2717
  		.rpc_resp = &res,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2718
  	};
136f2627c   Trond Myklebust   NFS: Reduce the s...
2719
2720
2721
2722
2723
2724
  	int status = -ENOMEM;
  
  	res.fattr = nfs_alloc_fattr();
  	res.dir_attr = nfs_alloc_fattr();
  	if (res.fattr == NULL || res.dir_attr == NULL)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2725

7c5130588   Bryan Schumaker   NFS: lookup suppo...
2726
  	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
91ba2eeec   Trond Myklebust   NFSv4: Add post-o...
2727
2728
2729
  	if (!status) {
  		update_changeattr(dir, &res.cinfo);
  		nfs_post_op_update_inode(dir, res.dir_attr);
73a3d07c1   Trond Myklebust   NFS: Clean up ino...
2730
  		nfs_post_op_update_inode(inode, res.fattr);
91ba2eeec   Trond Myklebust   NFSv4: Add post-o...
2731
  	}
136f2627c   Trond Myklebust   NFS: Reduce the s...
2732
2733
2734
  out:
  	nfs_free_fattr(res.dir_attr);
  	nfs_free_fattr(res.fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
  	return status;
  }
  
  static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(inode),
  				_nfs4_proc_link(inode, dir, name),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
  struct nfs4_createdata {
  	struct rpc_message msg;
  	struct nfs4_create_arg arg;
  	struct nfs4_create_res res;
  	struct nfs_fh fh;
  	struct nfs_fattr fattr;
  	struct nfs_fattr dir_fattr;
  };
  
  static struct nfs4_createdata *nfs4_alloc_createdata(struct inode *dir,
  		struct qstr *name, struct iattr *sattr, u32 ftype)
  {
  	struct nfs4_createdata *data;
  
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
  	if (data != NULL) {
  		struct nfs_server *server = NFS_SERVER(dir);
  
  		data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE];
  		data->msg.rpc_argp = &data->arg;
  		data->msg.rpc_resp = &data->res;
  		data->arg.dir_fh = NFS_FH(dir);
  		data->arg.server = server;
  		data->arg.name = name;
  		data->arg.attrs = sattr;
  		data->arg.ftype = ftype;
  		data->arg.bitmask = server->attr_bitmask;
  		data->res.server = server;
  		data->res.fh = &data->fh;
  		data->res.fattr = &data->fattr;
  		data->res.dir_fattr = &data->dir_fattr;
  		nfs_fattr_init(data->res.fattr);
  		nfs_fattr_init(data->res.dir_fattr);
  	}
  	return data;
  }
  
  static int nfs4_do_create(struct inode *dir, struct dentry *dentry, struct nfs4_createdata *data)
  {
7c5130588   Bryan Schumaker   NFS: lookup suppo...
2788
  	int status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &data->msg,
e73b83f27   Bryan Schumaker   NFS: convert call...
2789
  				    &data->arg.seq_args, &data->res.seq_res, 1);
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
  	if (status == 0) {
  		update_changeattr(dir, &data->res.dir_cinfo);
  		nfs_post_op_update_inode(dir, data->res.dir_fattr);
  		status = nfs_instantiate(dentry, data->res.fh, data->res.fattr);
  	}
  	return status;
  }
  
  static void nfs4_free_createdata(struct nfs4_createdata *data)
  {
  	kfree(data);
  }
4f390c152   Chuck Lever   NFS: Fix double d...
2802
  static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
94a6d7532   Chuck Lever   NFS: Use cached p...
2803
  		struct page *page, unsigned int len, struct iattr *sattr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2804
  {
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2805
2806
  	struct nfs4_createdata *data;
  	int status = -ENAMETOOLONG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2807

94a6d7532   Chuck Lever   NFS: Use cached p...
2808
  	if (len > NFS4_MAXPATHLEN)
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2809
  		goto out;
4f390c152   Chuck Lever   NFS: Fix double d...
2810

57dc9a574   Trond Myklebust   NFS: Reduce the s...
2811
2812
2813
2814
2815
2816
2817
2818
  	status = -ENOMEM;
  	data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4LNK);
  	if (data == NULL)
  		goto out;
  
  	data->msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK];
  	data->arg.u.symlink.pages = &page;
  	data->arg.u.symlink.len = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2819
  	
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2820
2821
2822
2823
  	status = nfs4_do_create(dir, dentry, data);
  
  	nfs4_free_createdata(data);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2824
2825
  	return status;
  }
4f390c152   Chuck Lever   NFS: Fix double d...
2826
  static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
94a6d7532   Chuck Lever   NFS: Use cached p...
2827
  		struct page *page, unsigned int len, struct iattr *sattr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2828
2829
2830
2831
2832
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(dir),
94a6d7532   Chuck Lever   NFS: Use cached p...
2833
2834
  				_nfs4_proc_symlink(dir, dentry, page,
  							len, sattr),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2835
2836
2837
2838
2839
2840
2841
2842
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
  		struct iattr *sattr)
  {
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2843
2844
  	struct nfs4_createdata *data;
  	int status = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2845

57dc9a574   Trond Myklebust   NFS: Reduce the s...
2846
2847
2848
2849
2850
2851
2852
2853
  	data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4DIR);
  	if (data == NULL)
  		goto out;
  
  	status = nfs4_do_create(dir, dentry, data);
  
  	nfs4_free_createdata(data);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2854
2855
2856
2857
2858
2859
2860
2861
  	return status;
  }
  
  static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
  		struct iattr *sattr)
  {
  	struct nfs4_exception exception = { };
  	int err;
a8a5da996   Aneesh Kumar K.V   nfs: Set MS_POSIX...
2862
2863
  
  	sattr->ia_mode &= ~current_umask();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2864
2865
2866
2867
2868
2869
2870
2871
2872
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(dir),
  				_nfs4_proc_mkdir(dir, dentry, sattr),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
56e4ebf87   Bryan Schumaker   NFS: readdir with...
2873
  		u64 cookie, struct page **pages, unsigned int count, int plus)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2874
2875
2876
2877
  {
  	struct inode		*dir = dentry->d_inode;
  	struct nfs4_readdir_arg args = {
  		.fh = NFS_FH(dir),
56e4ebf87   Bryan Schumaker   NFS: readdir with...
2878
  		.pages = pages,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2879
2880
  		.pgbase = 0,
  		.count = count,
96d25e532   Trond Myklebust   NFSv4: Fix a cach...
2881
  		.bitmask = NFS_SERVER(dentry->d_inode)->attr_bitmask,
82f2e5472   Bryan Schumaker   NFS: Readdir plus...
2882
  		.plus = plus,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2883
2884
2885
2886
2887
2888
2889
2890
2891
  	};
  	struct nfs4_readdir_res res;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  		.rpc_cred = cred,
  	};
  	int			status;
3110ff804   Harvey Harrison   nfs: replace rema...
2892
2893
  	dprintk("%s: dentry = %s/%s, cookie = %Lu
  ", __func__,
eadf4598e   Trond Myklebust   [PATCH] NFS: Add ...
2894
2895
2896
  			dentry->d_parent->d_name.name,
  			dentry->d_name.name,
  			(unsigned long long)cookie);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2897
2898
  	nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
  	res.pgbase = args.pgbase;
7c5130588   Bryan Schumaker   NFS: lookup suppo...
2899
  	status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
ac3961282   Trond Myklebust   NFS: readdir shou...
2900
  	if (status >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2901
  		memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
ac3961282   Trond Myklebust   NFS: readdir shou...
2902
2903
  		status += args.pgbase;
  	}
c48129983   Trond Myklebust   NFS: Fix atime re...
2904
2905
  
  	nfs_invalidate_atime(dir);
3110ff804   Harvey Harrison   nfs: replace rema...
2906
2907
  	dprintk("%s: returns %d
  ", __func__, status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2908
2909
2910
2911
  	return status;
  }
  
  static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
56e4ebf87   Bryan Schumaker   NFS: readdir with...
2912
  		u64 cookie, struct page **pages, unsigned int count, int plus)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2913
2914
2915
2916
2917
2918
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode),
  				_nfs4_proc_readdir(dentry, cred, cookie,
56e4ebf87   Bryan Schumaker   NFS: readdir with...
2919
  					pages, count, plus),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2920
2921
2922
2923
2924
2925
2926
2927
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
  		struct iattr *sattr, dev_t rdev)
  {
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2928
2929
2930
  	struct nfs4_createdata *data;
  	int mode = sattr->ia_mode;
  	int status = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2931
2932
2933
  
  	BUG_ON(!(sattr->ia_valid & ATTR_MODE));
  	BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2934
2935
2936
2937
  
  	data = nfs4_alloc_createdata(dir, &dentry->d_name, sattr, NF4SOCK);
  	if (data == NULL)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2938
  	if (S_ISFIFO(mode))
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2939
  		data->arg.ftype = NF4FIFO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2940
  	else if (S_ISBLK(mode)) {
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2941
2942
2943
  		data->arg.ftype = NF4BLK;
  		data->arg.u.device.specdata1 = MAJOR(rdev);
  		data->arg.u.device.specdata2 = MINOR(rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2944
2945
  	}
  	else if (S_ISCHR(mode)) {
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2946
2947
2948
  		data->arg.ftype = NF4CHR;
  		data->arg.u.device.specdata1 = MAJOR(rdev);
  		data->arg.u.device.specdata2 = MINOR(rdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2949
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2950
  	
57dc9a574   Trond Myklebust   NFS: Reduce the s...
2951
2952
2953
2954
  	status = nfs4_do_create(dir, dentry, data);
  
  	nfs4_free_createdata(data);
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2955
2956
2957
2958
2959
2960
2961
2962
  	return status;
  }
  
  static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
  		struct iattr *sattr, dev_t rdev)
  {
  	struct nfs4_exception exception = { };
  	int err;
a8a5da996   Aneesh Kumar K.V   nfs: Set MS_POSIX...
2963
2964
  
  	sattr->ia_mode &= ~current_umask();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(dir),
  				_nfs4_proc_mknod(dir, dentry, sattr, rdev),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
  		 struct nfs_fsstat *fsstat)
  {
  	struct nfs4_statfs_arg args = {
  		.fh = fhandle,
  		.bitmask = server->attr_bitmask,
  	};
24ad148a0   Benny Halevy   nfs41: use nfs4_s...
2980
2981
2982
  	struct nfs4_statfs_res res = {
  		.fsstat = fsstat,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2983
2984
2985
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS],
  		.rpc_argp = &args,
24ad148a0   Benny Halevy   nfs41: use nfs4_s...
2986
  		.rpc_resp = &res,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2987
  	};
0e574af1b   Trond Myklebust   NFS: Cleanup init...
2988
  	nfs_fattr_init(fsstat->fattr);
7c5130588   Bryan Schumaker   NFS: lookup suppo...
2989
  	return  nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
  }
  
  static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(server,
  				_nfs4_proc_statfs(server, fhandle, fsstat),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
  		struct nfs_fsinfo *fsinfo)
  {
  	struct nfs4_fsinfo_arg args = {
  		.fh = fhandle,
  		.bitmask = server->attr_bitmask,
  	};
3dda5e434   Benny Halevy   nfs41: use nfs4_f...
3011
3012
3013
  	struct nfs4_fsinfo_res res = {
  		.fsinfo = fsinfo,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3014
3015
3016
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSINFO],
  		.rpc_argp = &args,
3dda5e434   Benny Halevy   nfs41: use nfs4_f...
3017
  		.rpc_resp = &res,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3018
  	};
7c5130588   Bryan Schumaker   NFS: lookup suppo...
3019
  	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
  }
  
  static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
  {
  	struct nfs4_exception exception = { };
  	int err;
  
  	do {
  		err = nfs4_handle_exception(server,
  				_nfs4_do_fsinfo(server, fhandle, fsinfo),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
  {
0e574af1b   Trond Myklebust   NFS: Cleanup init...
3037
  	nfs_fattr_init(fsinfo->fattr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
  	return nfs4_do_fsinfo(server, fhandle, fsinfo);
  }
  
  static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
  		struct nfs_pathconf *pathconf)
  {
  	struct nfs4_pathconf_arg args = {
  		.fh = fhandle,
  		.bitmask = server->attr_bitmask,
  	};
d45b2989a   Benny Halevy   nfs41: use nfs4_p...
3048
3049
3050
  	struct nfs4_pathconf_res res = {
  		.pathconf = pathconf,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3051
3052
3053
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF],
  		.rpc_argp = &args,
d45b2989a   Benny Halevy   nfs41: use nfs4_p...
3054
  		.rpc_resp = &res,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3055
3056
3057
3058
3059
3060
3061
  	};
  
  	/* None of the pathconf attributes are mandatory to implement */
  	if ((args.bitmask[0] & nfs4_pathconf_bitmap[0]) == 0) {
  		memset(pathconf, 0, sizeof(*pathconf));
  		return 0;
  	}
0e574af1b   Trond Myklebust   NFS: Cleanup init...
3062
  	nfs_fattr_init(pathconf->fattr);
7c5130588   Bryan Schumaker   NFS: lookup suppo...
3063
  	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
  }
  
  static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
  		struct nfs_pathconf *pathconf)
  {
  	struct nfs4_exception exception = { };
  	int err;
  
  	do {
  		err = nfs4_handle_exception(server,
  				_nfs4_proc_pathconf(server, fhandle, pathconf),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
d20581aa4   Benny Halevy   pnfs: support for...
3079
3080
3081
3082
  void __nfs4_read_done_cb(struct nfs_read_data *data)
  {
  	nfs_invalidate_atime(data->inode);
  }
cbdabc7f8   Andy Adamson   NFSv4.1: filelayo...
3083
  static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_read_data *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3084
  {
ec06c096e   Trond Myklebust   NFS: Cleanup of N...
3085
  	struct nfs_server *server = NFS_SERVER(data->inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3086

9e33bed55   Trond Myklebust   NFSv4: Add recove...
3087
  	if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
d00c5d438   Trond Myklebust   NFS: Get rid of n...
3088
  		rpc_restart_call_prepare(task);
ec06c096e   Trond Myklebust   NFS: Cleanup of N...
3089
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3090
  	}
8850df999   Trond Myklebust   NFS: Fix atime re...
3091

d20581aa4   Benny Halevy   pnfs: support for...
3092
  	__nfs4_read_done_cb(data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3093
  	if (task->tk_status > 0)
ec06c096e   Trond Myklebust   NFS: Cleanup of N...
3094
3095
  		renew_lease(server, data->timestamp);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3096
  }
cbdabc7f8   Andy Adamson   NFSv4.1: filelayo...
3097
3098
3099
3100
3101
3102
3103
3104
  static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
  {
  
  	dprintk("--> %s
  ", __func__);
  
  	if (!nfs4_sequence_done(task, &data->res.seq_res))
  		return -EAGAIN;
d20581aa4   Benny Halevy   pnfs: support for...
3105
3106
  	return data->read_done_cb ? data->read_done_cb(task, data) :
  				    nfs4_read_done_cb(task, data);
cbdabc7f8   Andy Adamson   NFSv4.1: filelayo...
3107
  }
bdc7f021f   Trond Myklebust   NFS: Clean up the...
3108
  static void nfs4_proc_read_setup(struct nfs_read_data *data, struct rpc_message *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3109
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3110
  	data->timestamp   = jiffies;
cbdabc7f8   Andy Adamson   NFSv4.1: filelayo...
3111
  	data->read_done_cb = nfs4_read_done_cb;
bdc7f021f   Trond Myklebust   NFS: Clean up the...
3112
  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3113
  }
cbdabc7f8   Andy Adamson   NFSv4.1: filelayo...
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
  /* Reset the the nfs_read_data to send the read to the MDS. */
  void nfs4_reset_read(struct rpc_task *task, struct nfs_read_data *data)
  {
  	dprintk("%s Reset task for i/o through
  ", __func__);
  	put_lseg(data->lseg);
  	data->lseg = NULL;
  	/* offsets will differ in the dense stripe case */
  	data->args.offset = data->mds_offset;
  	data->ds_clp = NULL;
  	data->args.fh     = NFS_FH(data->inode);
  	data->read_done_cb = nfs4_read_done_cb;
  	task->tk_ops = data->mds_ops;
  	rpc_task_reset_client(task, NFS_CLIENT(data->inode));
  }
  EXPORT_SYMBOL_GPL(nfs4_reset_read);
b029bc9b0   Fred Isaman   NFSv4.1: add call...
3130
  static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_write_data *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3131
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3132
3133
  	struct inode *inode = data->inode;
  	
9e33bed55   Trond Myklebust   NFSv4: Add recove...
3134
  	if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
d00c5d438   Trond Myklebust   NFS: Get rid of n...
3135
  		rpc_restart_call_prepare(task);
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
3136
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3137
  	}
4f9838c7e   Trond Myklebust   NFSv4: Add post-o...
3138
  	if (task->tk_status >= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3139
  		renew_lease(NFS_SERVER(inode), data->timestamp);
70ca88521   Trond Myklebust   NFS: Fake up 'wcc...
3140
  		nfs_post_op_update_inode_force_wcc(inode, data->res.fattr);
4f9838c7e   Trond Myklebust   NFSv4: Add post-o...
3141
  	}
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
3142
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3143
  }
b029bc9b0   Fred Isaman   NFSv4.1: add call...
3144
3145
3146
3147
  static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
  {
  	if (!nfs4_sequence_done(task, &data->res.seq_res))
  		return -EAGAIN;
d20581aa4   Benny Halevy   pnfs: support for...
3148
3149
  	return data->write_done_cb ? data->write_done_cb(task, data) :
  		nfs4_write_done_cb(task, data);
b029bc9b0   Fred Isaman   NFSv4.1: add call...
3150
  }
a69aef149   Fred Isaman   NFSv4.1: pnfs fil...
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
  /* Reset the the nfs_write_data to send the write to the MDS. */
  void nfs4_reset_write(struct rpc_task *task, struct nfs_write_data *data)
  {
  	dprintk("%s Reset task for i/o through
  ", __func__);
  	put_lseg(data->lseg);
  	data->lseg          = NULL;
  	data->ds_clp        = NULL;
  	data->write_done_cb = nfs4_write_done_cb;
  	data->args.fh       = NFS_FH(data->inode);
  	data->args.bitmask  = data->res.server->cache_consistency_bitmask;
  	data->args.offset   = data->mds_offset;
  	data->res.fattr     = &data->fattr;
  	task->tk_ops        = data->mds_ops;
  	rpc_task_reset_client(task, NFS_CLIENT(data->inode));
  }
  EXPORT_SYMBOL_GPL(nfs4_reset_write);
bdc7f021f   Trond Myklebust   NFS: Clean up the...
3168
  static void nfs4_proc_write_setup(struct nfs_write_data *data, struct rpc_message *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3169
  {
bdc7f021f   Trond Myklebust   NFS: Clean up the...
3170
  	struct nfs_server *server = NFS_SERVER(data->inode);
7ffd10640   Fred Isaman   NFSv4.1: remove G...
3171
3172
3173
3174
3175
  	if (data->lseg) {
  		data->args.bitmask = NULL;
  		data->res.fattr = NULL;
  	} else
  		data->args.bitmask = server->cache_consistency_bitmask;
b029bc9b0   Fred Isaman   NFSv4.1: add call...
3176
3177
  	if (!data->write_done_cb)
  		data->write_done_cb = nfs4_write_done_cb;
4f9838c7e   Trond Myklebust   NFSv4: Add post-o...
3178
  	data->res.server = server;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3179
  	data->timestamp   = jiffies;
bdc7f021f   Trond Myklebust   NFS: Clean up the...
3180
  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3181
  }
5f452431e   Fred Isaman   NFSv4.1: add call...
3182
  static int nfs4_commit_done_cb(struct rpc_task *task, struct nfs_write_data *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3183
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3184
  	struct inode *inode = data->inode;
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
3185

9e33bed55   Trond Myklebust   NFSv4: Add recove...
3186
  	if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
d00c5d438   Trond Myklebust   NFS: Get rid of n...
3187
  		rpc_restart_call_prepare(task);
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
3188
  		return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3189
  	}
9e08a3c5a   Trond Myklebust   NFS: Use nfs_refr...
3190
  	nfs_refresh_inode(inode, data->res.fattr);
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
3191
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3192
  }
5f452431e   Fred Isaman   NFSv4.1: add call...
3193
3194
3195
3196
3197
3198
  static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
  {
  	if (!nfs4_sequence_done(task, &data->res.seq_res))
  		return -EAGAIN;
  	return data->write_done_cb(task, data);
  }
bdc7f021f   Trond Myklebust   NFS: Clean up the...
3199
  static void nfs4_proc_commit_setup(struct nfs_write_data *data, struct rpc_message *msg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3200
  {
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
3201
  	struct nfs_server *server = NFS_SERVER(data->inode);
988b6dceb   Fred Isaman   NFSv4.1: remove G...
3202
3203
3204
3205
3206
3207
  
  	if (data->lseg) {
  		data->args.bitmask = NULL;
  		data->res.fattr = NULL;
  	} else
  		data->args.bitmask = server->cache_consistency_bitmask;
5f452431e   Fred Isaman   NFSv4.1: add call...
3208
3209
  	if (!data->write_done_cb)
  		data->write_done_cb = nfs4_commit_done_cb;
4f9838c7e   Trond Myklebust   NFSv4: Add post-o...
3210
  	data->res.server = server;
bdc7f021f   Trond Myklebust   NFS: Clean up the...
3211
  	msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMMIT];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3212
  }
9bc4e3ca4   Chuck Lever   NFS: Calldata for...
3213
3214
3215
3216
  struct nfs4_renewdata {
  	struct nfs_client	*client;
  	unsigned long		timestamp;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3217
3218
3219
3220
  /*
   * nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special
   * standalone procedure for queueing an asynchronous RENEW.
   */
9bc4e3ca4   Chuck Lever   NFS: Calldata for...
3221
  static void nfs4_renew_release(void *calldata)
dc96aef96   Alexandros Batsakis   nfs: prevent back...
3222
  {
9bc4e3ca4   Chuck Lever   NFS: Calldata for...
3223
3224
  	struct nfs4_renewdata *data = calldata;
  	struct nfs_client *clp = data->client;
dc96aef96   Alexandros Batsakis   nfs: prevent back...
3225

0851de061   Alexandros Batsakis   nfs4: renewd rene...
3226
3227
3228
  	if (atomic_read(&clp->cl_count) > 1)
  		nfs4_schedule_state_renewal(clp);
  	nfs_put_client(clp);
9bc4e3ca4   Chuck Lever   NFS: Calldata for...
3229
  	kfree(data);
dc96aef96   Alexandros Batsakis   nfs: prevent back...
3230
  }
9bc4e3ca4   Chuck Lever   NFS: Calldata for...
3231
  static void nfs4_renew_done(struct rpc_task *task, void *calldata)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3232
  {
9bc4e3ca4   Chuck Lever   NFS: Calldata for...
3233
3234
3235
  	struct nfs4_renewdata *data = calldata;
  	struct nfs_client *clp = data->client;
  	unsigned long timestamp = data->timestamp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3236
3237
  
  	if (task->tk_status < 0) {
95baa25c7   Trond Myklebust   NFSv4: Fix the ca...
3238
  		/* Unless we're shutting down, schedule state recovery! */
042b60beb   Trond Myklebust   NFSv4: renewd nee...
3239
3240
3241
  		if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0)
  			return;
  		if (task->tk_status != NFS4ERR_CB_PATH_DOWN) {
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
3242
  			nfs4_schedule_lease_recovery(clp);
042b60beb   Trond Myklebust   NFSv4: renewd nee...
3243
3244
3245
  			return;
  		}
  		nfs4_schedule_path_down_recovery(clp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3246
  	}
452e93523   Trond Myklebust   NFSv4: Clean up t...
3247
  	do_renew_lease(clp, timestamp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3248
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
3249
3250
  static const struct rpc_call_ops nfs4_renew_ops = {
  	.rpc_call_done = nfs4_renew_done,
dc96aef96   Alexandros Batsakis   nfs: prevent back...
3251
  	.rpc_release = nfs4_renew_release,
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
3252
  };
2f60ea6b8   Trond Myklebust   NFSv4: The NFSv4....
3253
  static int nfs4_proc_async_renew(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3254
3255
3256
3257
  {
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_RENEW],
  		.rpc_argp	= clp,
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
3258
  		.rpc_cred	= cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3259
  	};
9bc4e3ca4   Chuck Lever   NFS: Calldata for...
3260
  	struct nfs4_renewdata *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3261

2f60ea6b8   Trond Myklebust   NFSv4: The NFSv4....
3262
3263
  	if (renew_flags == 0)
  		return 0;
0851de061   Alexandros Batsakis   nfs4: renewd rene...
3264
3265
  	if (!atomic_inc_not_zero(&clp->cl_count))
  		return -EIO;
b569ad349   Trond Myklebust   NFSv4: nfs4_proc_...
3266
  	data = kmalloc(sizeof(*data), GFP_NOFS);
9bc4e3ca4   Chuck Lever   NFS: Calldata for...
3267
3268
3269
3270
  	if (data == NULL)
  		return -ENOMEM;
  	data->client = clp;
  	data->timestamp = jiffies;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3271
  	return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_SOFT,
9bc4e3ca4   Chuck Lever   NFS: Calldata for...
3272
  			&nfs4_renew_ops, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3273
  }
8534d4ec0   Trond Myklebust   NFSv4: nfs4_proc_...
3274
  static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3275
3276
3277
3278
  {
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_RENEW],
  		.rpc_argp	= clp,
b4454fe1a   Trond Myklebust   NFSv4: Remove req...
3279
  		.rpc_cred	= cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3280
3281
3282
3283
3284
3285
3286
  	};
  	unsigned long now = jiffies;
  	int status;
  
  	status = rpc_call_sync(clp->cl_rpcclient, &msg, 0);
  	if (status < 0)
  		return status;
452e93523   Trond Myklebust   NFSv4: Clean up t...
3287
  	do_renew_lease(clp, now);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3288
3289
  	return 0;
  }
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
  static inline int nfs4_server_supports_acls(struct nfs_server *server)
  {
  	return (server->caps & NFS_CAP_ACLS)
  		&& (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
  		&& (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
  }
  
  /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_CACHE_SIZE, and that
   * it's OK to put sizeof(void) * (XATTR_SIZE_MAX/PAGE_CACHE_SIZE) bytes on
   * the stack.
   */
  #define NFS4ACL_MAXPAGES (XATTR_SIZE_MAX >> PAGE_CACHE_SHIFT)
e9e3d724e   Neil Horman   nfs4: Ensure that...
3302
3303
3304
3305
3306
3307
3308
3309
3310
  static int buf_to_pages_noslab(const void *buf, size_t buflen,
  		struct page **pages, unsigned int *pgbase)
  {
  	struct page *newpage, **spages;
  	int rc = 0;
  	size_t len;
  	spages = pages;
  
  	do {
43b7c3f05   Jovi Zhang   nfs: fix compilat...
3311
  		len = min_t(size_t, PAGE_CACHE_SIZE, buflen);
e9e3d724e   Neil Horman   nfs4: Ensure that...
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
  		newpage = alloc_page(GFP_KERNEL);
  
  		if (newpage == NULL)
  			goto unwind;
  		memcpy(page_address(newpage), buf, len);
                  buf += len;
                  buflen -= len;
  		*pages++ = newpage;
  		rc++;
  	} while (buflen != 0);
  
  	return rc;
  
  unwind:
  	for(; rc > 0; rc--)
  		__free_page(spages[rc-1]);
  	return -ENOMEM;
  }
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3330
3331
3332
  struct nfs4_cached_acl {
  	int cached;
  	size_t len;
3e9d41543   Andrew Morton   [PATCH] NFSv4: em...
3333
  	char data[0];
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
  };
  
  static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl)
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  
  	spin_lock(&inode->i_lock);
  	kfree(nfsi->nfs4_acl);
  	nfsi->nfs4_acl = acl;
  	spin_unlock(&inode->i_lock);
  }
  
  static void nfs4_zap_acl_attr(struct inode *inode)
  {
  	nfs4_set_cached_acl(inode, NULL);
  }
  
  static inline ssize_t nfs4_read_cached_acl(struct inode *inode, char *buf, size_t buflen)
  {
  	struct nfs_inode *nfsi = NFS_I(inode);
  	struct nfs4_cached_acl *acl;
  	int ret = -ENOENT;
  
  	spin_lock(&inode->i_lock);
  	acl = nfsi->nfs4_acl;
  	if (acl == NULL)
  		goto out;
  	if (buf == NULL) /* user is just asking for length */
  		goto out_len;
  	if (acl->cached == 0)
  		goto out;
  	ret = -ERANGE; /* see getxattr(2) man page */
  	if (acl->len > buflen)
  		goto out;
  	memcpy(buf, acl->data, acl->len);
  out_len:
  	ret = acl->len;
  out:
  	spin_unlock(&inode->i_lock);
  	return ret;
  }
  
  static void nfs4_write_cached_acl(struct inode *inode, const char *buf, size_t acl_len)
  {
  	struct nfs4_cached_acl *acl;
  
  	if (buf && acl_len <= PAGE_SIZE) {
  		acl = kmalloc(sizeof(*acl) + acl_len, GFP_KERNEL);
  		if (acl == NULL)
  			goto out;
  		acl->cached = 1;
  		memcpy(acl->data, buf, acl_len);
  	} else {
  		acl = kmalloc(sizeof(*acl), GFP_KERNEL);
  		if (acl == NULL)
  			goto out;
  		acl->cached = 0;
  	}
  	acl->len = acl_len;
  out:
  	nfs4_set_cached_acl(inode, acl);
  }
bf118a342   Andy Adamson   NFSv4: include bi...
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
  /*
   * The getxattr API returns the required buffer length when called with a
   * NULL buf. The NFSv4 acl tool then calls getxattr again after allocating
   * the required buf.  On a NULL buf, we send a page of data to the server
   * guessing that the ACL request can be serviced by a page. If so, we cache
   * up to the page of ACL data, and the 2nd call to getxattr is serviced by
   * the cache. If not so, we throw away the page, and cache the required
   * length. The next getxattr call will then produce another round trip to
   * the server, this time with the input buf of the required size.
   */
16b4289c7   Trond Myklebust   NFSv4: Add v4 exc...
3406
  static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
3407
  {
bf118a342   Andy Adamson   NFSv4: include bi...
3408
  	struct page *pages[NFS4ACL_MAXPAGES] = {NULL, };
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
3409
3410
3411
3412
3413
  	struct nfs_getaclargs args = {
  		.fh = NFS_FH(inode),
  		.acl_pages = pages,
  		.acl_len = buflen,
  	};
663c79b3c   Benny Halevy   nfs41: use nfs4_g...
3414
3415
3416
  	struct nfs_getaclres res = {
  		.acl_len = buflen,
  	};
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3417
  	void *resp_buf;
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
3418
3419
3420
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],
  		.rpc_argp = &args,
663c79b3c   Benny Halevy   nfs41: use nfs4_g...
3421
  		.rpc_resp = &res,
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
3422
  	};
bf118a342   Andy Adamson   NFSv4: include bi...
3423
  	int ret = -ENOMEM, npages, i, acl_len = 0;
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
3424

bf118a342   Andy Adamson   NFSv4: include bi...
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
  	npages = (buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
  	/* As long as we're doing a round trip to the server anyway,
  	 * let's be prepared for a page of acl data. */
  	if (npages == 0)
  		npages = 1;
  
  	for (i = 0; i < npages; i++) {
  		pages[i] = alloc_page(GFP_KERNEL);
  		if (!pages[i])
  			goto out_free;
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3435
  	}
bf118a342   Andy Adamson   NFSv4: include bi...
3436
3437
3438
3439
3440
  	if (npages > 1) {
  		/* for decoding across pages */
  		args.acl_scratch = alloc_page(GFP_KERNEL);
  		if (!args.acl_scratch)
  			goto out_free;
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3441
  	}
bf118a342   Andy Adamson   NFSv4: include bi...
3442
3443
3444
3445
3446
3447
3448
  	args.acl_len = npages * PAGE_SIZE;
  	args.acl_pgbase = 0;
  	/* Let decode_getfacl know not to fail if the ACL data is larger than
  	 * the page we send as a guess */
  	if (buf == NULL)
  		res.acl_flags |= NFS4_ACL_LEN_REQUEST;
  	resp_buf = page_address(pages[0]);
de040becc   Peng Tao   NFS4: fix compile...
3449
3450
  	dprintk("%s  buf %p buflen %zu npages %d args.acl_len %zu
  ",
bf118a342   Andy Adamson   NFSv4: include bi...
3451
3452
3453
  		__func__, buf, buflen, npages, args.acl_len);
  	ret = nfs4_call_sync(NFS_SERVER(inode)->client, NFS_SERVER(inode),
  			     &msg, &args.seq_args, &res.seq_res, 0);
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3454
3455
  	if (ret)
  		goto out_free;
bf118a342   Andy Adamson   NFSv4: include bi...
3456
3457
3458
3459
  
  	acl_len = res.acl_len - res.acl_data_offset;
  	if (acl_len > args.acl_len)
  		nfs4_write_cached_acl(inode, NULL, acl_len);
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3460
  	else
bf118a342   Andy Adamson   NFSv4: include bi...
3461
3462
  		nfs4_write_cached_acl(inode, resp_buf + res.acl_data_offset,
  				      acl_len);
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3463
3464
  	if (buf) {
  		ret = -ERANGE;
bf118a342   Andy Adamson   NFSv4: include bi...
3465
  		if (acl_len > buflen)
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3466
  			goto out_free;
bf118a342   Andy Adamson   NFSv4: include bi...
3467
3468
  		_copy_from_pages(buf, pages, res.acl_data_offset,
  				res.acl_len);
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3469
  	}
bf118a342   Andy Adamson   NFSv4: include bi...
3470
  	ret = acl_len;
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3471
  out_free:
bf118a342   Andy Adamson   NFSv4: include bi...
3472
3473
3474
3475
3476
  	for (i = 0; i < npages; i++)
  		if (pages[i])
  			__free_page(pages[i]);
  	if (args.acl_scratch)
  		__free_page(args.acl_scratch);
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
3477
3478
  	return ret;
  }
16b4289c7   Trond Myklebust   NFSv4: Add v4 exc...
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
  static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
  {
  	struct nfs4_exception exception = { };
  	ssize_t ret;
  	do {
  		ret = __nfs4_get_acl_uncached(inode, buf, buflen);
  		if (ret >= 0)
  			break;
  		ret = nfs4_handle_exception(NFS_SERVER(inode), ret, &exception);
  	} while (exception.retry);
  	return ret;
  }
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
  static ssize_t nfs4_proc_get_acl(struct inode *inode, void *buf, size_t buflen)
  {
  	struct nfs_server *server = NFS_SERVER(inode);
  	int ret;
  
  	if (!nfs4_server_supports_acls(server))
  		return -EOPNOTSUPP;
  	ret = nfs_revalidate_inode(server, inode);
  	if (ret < 0)
  		return ret;
08a22b392   Aneesh Kumar K.V   nfs: Discard ACL ...
3501
3502
  	if (NFS_I(inode)->cache_validity & NFS_INO_INVALID_ACL)
  		nfs_zap_acl_cache(inode);
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3503
3504
  	ret = nfs4_read_cached_acl(inode, buf, buflen);
  	if (ret != -ENOENT)
bf118a342   Andy Adamson   NFSv4: include bi...
3505
3506
  		/* -ENOENT is returned if there is no ACL or if there is an ACL
  		 * but no cached acl data, just the acl length */
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
3507
3508
3509
  		return ret;
  	return nfs4_get_acl_uncached(inode, buf, buflen);
  }
16b4289c7   Trond Myklebust   NFSv4: Add v4 exc...
3510
  static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
4b580ee3d   J. Bruce Fields   [PATCH] NFSv4: AC...
3511
3512
3513
3514
3515
3516
3517
3518
  {
  	struct nfs_server *server = NFS_SERVER(inode);
  	struct page *pages[NFS4ACL_MAXPAGES];
  	struct nfs_setaclargs arg = {
  		.fh		= NFS_FH(inode),
  		.acl_pages	= pages,
  		.acl_len	= buflen,
  	};
73c403a9a   Benny Halevy   nfs41: use nfs4_s...
3519
  	struct nfs_setaclres res;
4b580ee3d   J. Bruce Fields   [PATCH] NFSv4: AC...
3520
3521
3522
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_SETACL],
  		.rpc_argp	= &arg,
73c403a9a   Benny Halevy   nfs41: use nfs4_s...
3523
  		.rpc_resp	= &res,
4b580ee3d   J. Bruce Fields   [PATCH] NFSv4: AC...
3524
  	};
e9e3d724e   Neil Horman   nfs4: Ensure that...
3525
  	int ret, i;
4b580ee3d   J. Bruce Fields   [PATCH] NFSv4: AC...
3526
3527
3528
  
  	if (!nfs4_server_supports_acls(server))
  		return -EOPNOTSUPP;
e9e3d724e   Neil Horman   nfs4: Ensure that...
3529
3530
3531
  	i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
  	if (i < 0)
  		return i;
642ac5492   Trond Myklebust   NFSv4: Return del...
3532
  	nfs_inode_return_delegation(inode);
7c5130588   Bryan Schumaker   NFS: lookup suppo...
3533
  	ret = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
e9e3d724e   Neil Horman   nfs4: Ensure that...
3534
3535
3536
3537
3538
3539
3540
  
  	/*
  	 * Free each page after tx, so the only ref left is
  	 * held by the network stack
  	 */
  	for (; i > 0; i--)
  		put_page(pages[i-1]);
08a22b392   Aneesh Kumar K.V   nfs: Discard ACL ...
3541
3542
3543
3544
3545
3546
3547
  	/*
  	 * Acl update can result in inode attribute update.
  	 * so mark the attribute cache invalid.
  	 */
  	spin_lock(&inode->i_lock);
  	NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ATTR;
  	spin_unlock(&inode->i_lock);
f41f74183   Trond Myklebust   NFS: Ensure we za...
3548
3549
  	nfs_access_zap_cache(inode);
  	nfs_zap_acl_cache(inode);
4b580ee3d   J. Bruce Fields   [PATCH] NFSv4: AC...
3550
3551
  	return ret;
  }
16b4289c7   Trond Myklebust   NFSv4: Add v4 exc...
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
  static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(inode),
  				__nfs4_proc_set_acl(inode, buf, buflen),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3563
  static int
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
3564
  nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server, struct nfs4_state *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3565
  {
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
3566
3567
3568
  	struct nfs_client *clp = server->nfs_client;
  
  	if (task->tk_status >= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3569
3570
  		return 0;
  	switch(task->tk_status) {
9e33bed55   Trond Myklebust   NFSv4: Add recove...
3571
3572
3573
3574
3575
  		case -NFS4ERR_ADMIN_REVOKED:
  		case -NFS4ERR_BAD_STATEID:
  		case -NFS4ERR_OPENMODE:
  			if (state == NULL)
  				break;
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
3576
3577
  			nfs4_schedule_stateid_recovery(server, state);
  			goto wait_on_recovery;
0ced63d1a   Trond Myklebust   NFSv4: Handle exp...
3578
3579
3580
  		case -NFS4ERR_EXPIRED:
  			if (state != NULL)
  				nfs4_schedule_stateid_recovery(server, state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3581
  		case -NFS4ERR_STALE_STATEID:
a2c0b9e29   Trond Myklebust   NFS: Ensure that ...
3582
  		case -NFS4ERR_STALE_CLIENTID:
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
3583
3584
  			nfs4_schedule_lease_recovery(clp);
  			goto wait_on_recovery;
4745e3154   Andy Adamson   nfs41: kick start...
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
  #if defined(CONFIG_NFS_V4_1)
  		case -NFS4ERR_BADSESSION:
  		case -NFS4ERR_BADSLOT:
  		case -NFS4ERR_BAD_HIGH_SLOT:
  		case -NFS4ERR_DEADSESSION:
  		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
  		case -NFS4ERR_SEQ_FALSE_RETRY:
  		case -NFS4ERR_SEQ_MISORDERED:
  			dprintk("%s ERROR %d, Reset session
  ", __func__,
  				task->tk_status);
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
3596
  			nfs4_schedule_session_recovery(clp->cl_session);
4745e3154   Andy Adamson   nfs41: kick start...
3597
3598
3599
  			task->tk_status = 0;
  			return -EAGAIN;
  #endif /* CONFIG_NFS_V4_1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3600
  		case -NFS4ERR_DELAY:
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
3601
  			nfs_inc_server_stats(server, NFSIOS_DELAY);
006ea73e5   Chuck Lever   NFS: add hooks to...
3602
  		case -NFS4ERR_GRACE:
2c6434888   Jeff Layton   nfs4: handle -EKE...
3603
  		case -EKEYEXPIRED:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3604
3605
3606
  			rpc_delay(task, NFS4_POLL_RETRY_MAX);
  			task->tk_status = 0;
  			return -EAGAIN;
a8a4ae3a8   Andy Adamson   NFSv41: Resend on...
3607
  		case -NFS4ERR_RETRY_UNCACHED_REP:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3608
3609
3610
3611
3612
3613
  		case -NFS4ERR_OLD_STATEID:
  			task->tk_status = 0;
  			return -EAGAIN;
  	}
  	task->tk_status = nfs4_map_errors(task->tk_status);
  	return 0;
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
3614
  wait_on_recovery:
a2c0b9e29   Trond Myklebust   NFS: Ensure that ...
3615
  	rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
a2c0b9e29   Trond Myklebust   NFS: Ensure that ...
3616
3617
3618
3619
  	if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
  		rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
  	task->tk_status = 0;
  	return -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3620
  }
bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
3621
3622
3623
  int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
  		unsigned short port, struct rpc_cred *cred,
  		struct nfs4_setclientid_res *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3624
3625
3626
3627
3628
  {
  	nfs4_verifier sc_verifier;
  	struct nfs4_setclientid setclientid = {
  		.sc_verifier = &sc_verifier,
  		.sc_prog = program,
f4eecd5da   Andy Adamson   NFS implement v4....
3629
  		.sc_cb_ident = clp->cl_cb_ident,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3630
3631
3632
3633
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
  		.rpc_argp = &setclientid,
bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
3634
  		.rpc_resp = res,
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
3635
  		.rpc_cred = cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3636
  	};
bc4785cd4   Al Viro   [PATCH] nfs: veri...
3637
  	__be32 *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3638
3639
  	int loop = 0;
  	int status;
bc4785cd4   Al Viro   [PATCH] nfs: veri...
3640
  	p = (__be32*)sc_verifier.data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3641
3642
3643
3644
3645
  	*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
  	*p = htonl((u32)clp->cl_boot_time.tv_nsec);
  
  	for(;;) {
  		setclientid.sc_name_len = scnprintf(setclientid.sc_name,
69dd716c5   Trond Myklebust   NFSv4: Add socket...
3646
  				sizeof(setclientid.sc_name), "%s/%s %s %s %u",
d4d3c5074   Chuck Lever   NFS: Enable NFS c...
3647
3648
3649
  				clp->cl_ipaddr,
  				rpc_peeraddr2str(clp->cl_rpcclient,
  							RPC_DISPLAY_ADDR),
69dd716c5   Trond Myklebust   NFSv4: Add socket...
3650
3651
  				rpc_peeraddr2str(clp->cl_rpcclient,
  							RPC_DISPLAY_PROTO),
78ea323be   Trond Myklebust   NFSv4: Don't use ...
3652
  				clp->cl_rpcclient->cl_auth->au_ops->au_name,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3653
3654
  				clp->cl_id_uniquifier);
  		setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
d4d3c5074   Chuck Lever   NFS: Enable NFS c...
3655
3656
3657
  				sizeof(setclientid.sc_netid),
  				rpc_peeraddr2str(clp->cl_rpcclient,
  							RPC_DISPLAY_NETID));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3658
  		setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
d4d3c5074   Chuck Lever   NFS: Enable NFS c...
3659
  				sizeof(setclientid.sc_uaddr), "%s.%u.%u",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3660
  				clp->cl_ipaddr, port >> 8, port & 255);
1bd714f2a   Trond Myklebust   NFSv4: Ensure tha...
3661
  		status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3662
3663
  		if (status != -NFS4ERR_CLID_INUSE)
  			break;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
3664
3665
  		if (loop != 0) {
  			++clp->cl_id_uniquifier;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3666
  			break;
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
3667
3668
3669
  		}
  		++loop;
  		ssleep(clp->cl_lease_time / HZ + 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3670
3671
3672
  	}
  	return status;
  }
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
3673
  int nfs4_proc_setclientid_confirm(struct nfs_client *clp,
bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
3674
3675
  		struct nfs4_setclientid_res *arg,
  		struct rpc_cred *cred)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3676
3677
3678
3679
  {
  	struct nfs_fsinfo fsinfo;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID_CONFIRM],
bb8b27e50   Trond Myklebust   NFSv4: Clean up t...
3680
  		.rpc_argp = arg,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3681
  		.rpc_resp = &fsinfo,
286d7d6a0   Trond Myklebust   NFSv4: Remove req...
3682
  		.rpc_cred = cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3683
3684
3685
3686
3687
  	};
  	unsigned long now;
  	int status;
  
  	now = jiffies;
1bd714f2a   Trond Myklebust   NFSv4: Ensure tha...
3688
  	status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3689
3690
3691
3692
3693
3694
3695
3696
  	if (status == 0) {
  		spin_lock(&clp->cl_lock);
  		clp->cl_lease_time = fsinfo.lease_time * HZ;
  		clp->cl_last_renewal = now;
  		spin_unlock(&clp->cl_lock);
  	}
  	return status;
  }
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3697
3698
  struct nfs4_delegreturndata {
  	struct nfs4_delegreturnargs args;
fa178f29c   Trond Myklebust   NFSv4: Ensure DEL...
3699
  	struct nfs4_delegreturnres res;
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3700
3701
  	struct nfs_fh fh;
  	nfs4_stateid stateid;
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
3702
  	unsigned long timestamp;
fa178f29c   Trond Myklebust   NFSv4: Ensure DEL...
3703
  	struct nfs_fattr fattr;
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3704
3705
  	int rpc_status;
  };
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3706
3707
3708
  static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_delegreturndata *data = calldata;
938e10109   Andy Adamson   nfs41 delegreturn...
3709

14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
3710
3711
  	if (!nfs4_sequence_done(task, &data->res.seq_res))
  		return;
938e10109   Andy Adamson   nfs41 delegreturn...
3712

797088611   Ricardo Labiaga   nfs41: Retry dele...
3713
3714
3715
3716
  	switch (task->tk_status) {
  	case -NFS4ERR_STALE_STATEID:
  	case -NFS4ERR_EXPIRED:
  	case 0:
fa178f29c   Trond Myklebust   NFSv4: Ensure DEL...
3717
  		renew_lease(data->res.server, data->timestamp);
797088611   Ricardo Labiaga   nfs41: Retry dele...
3718
3719
3720
3721
  		break;
  	default:
  		if (nfs4_async_handle_error(task, data->res.server, NULL) ==
  				-EAGAIN) {
d00c5d438   Trond Myklebust   NFS: Get rid of n...
3722
  			rpc_restart_call_prepare(task);
797088611   Ricardo Labiaga   nfs41: Retry dele...
3723
3724
3725
3726
  			return;
  		}
  	}
  	data->rpc_status = task->tk_status;
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3727
3728
3729
3730
  }
  
  static void nfs4_delegreturn_release(void *calldata)
  {
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3731
3732
  	kfree(calldata);
  }
938e10109   Andy Adamson   nfs41 delegreturn...
3733
3734
3735
3736
3737
3738
  #if defined(CONFIG_NFS_V4_1)
  static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
  {
  	struct nfs4_delegreturndata *d_data;
  
  	d_data = (struct nfs4_delegreturndata *)data;
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
3739
  	if (nfs4_setup_sequence(d_data->res.server,
938e10109   Andy Adamson   nfs41 delegreturn...
3740
3741
3742
3743
3744
3745
  				&d_data->args.seq_args,
  				&d_data->res.seq_res, 1, task))
  		return;
  	rpc_call_start(task);
  }
  #endif /* CONFIG_NFS_V4_1 */
c8d149f3d   Jesper Juhl   NFS: "const stati...
3746
  static const struct rpc_call_ops nfs4_delegreturn_ops = {
938e10109   Andy Adamson   nfs41 delegreturn...
3747
3748
3749
  #if defined(CONFIG_NFS_V4_1)
  	.rpc_call_prepare = nfs4_delegreturn_prepare,
  #endif /* CONFIG_NFS_V4_1 */
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3750
3751
3752
  	.rpc_call_done = nfs4_delegreturn_done,
  	.rpc_release = nfs4_delegreturn_release,
  };
e6f810759   Trond Myklebust   NFS: Add an async...
3753
  static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync)
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3754
3755
  {
  	struct nfs4_delegreturndata *data;
fa178f29c   Trond Myklebust   NFSv4: Ensure DEL...
3756
  	struct nfs_server *server = NFS_SERVER(inode);
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3757
  	struct rpc_task *task;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
3758
3759
3760
3761
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN],
  		.rpc_cred = cred,
  	};
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
3762
3763
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = server->client,
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
3764
  		.rpc_message = &msg,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
3765
3766
3767
  		.callback_ops = &nfs4_delegreturn_ops,
  		.flags = RPC_TASK_ASYNC,
  	};
e6f810759   Trond Myklebust   NFS: Add an async...
3768
  	int status = 0;
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3769

8535b2be5   Trond Myklebust   NFSv4: Don't use ...
3770
  	data = kzalloc(sizeof(*data), GFP_NOFS);
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3771
3772
3773
3774
  	if (data == NULL)
  		return -ENOMEM;
  	data->args.fhandle = &data->fh;
  	data->args.stateid = &data->stateid;
fa178f29c   Trond Myklebust   NFSv4: Ensure DEL...
3775
  	data->args.bitmask = server->attr_bitmask;
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3776
3777
  	nfs_copy_fh(&data->fh, NFS_FH(inode));
  	memcpy(&data->stateid, stateid, sizeof(data->stateid));
fa178f29c   Trond Myklebust   NFSv4: Ensure DEL...
3778
3779
  	data->res.fattr = &data->fattr;
  	data->res.server = server;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
3780
  	nfs_fattr_init(data->res.fattr);
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
3781
  	data->timestamp = jiffies;
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3782
  	data->rpc_status = 0;
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
3783
  	task_setup_data.callback_data = data;
1174dd1f8   Trond Myklebust   NFSv4: Convert a ...
3784
3785
  	msg.rpc_argp = &data->args;
  	msg.rpc_resp = &data->res;
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
3786
  	task = rpc_run_task(&task_setup_data);
7a1218a27   Trond Myklebust   SUNRPC: Ensure rp...
3787
  	if (IS_ERR(task))
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3788
  		return PTR_ERR(task);
e6f810759   Trond Myklebust   NFS: Add an async...
3789
3790
  	if (!issync)
  		goto out;
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3791
  	status = nfs4_wait_for_completion_rpc_task(task);
e6f810759   Trond Myklebust   NFS: Add an async...
3792
3793
3794
3795
3796
3797
3798
  	if (status != 0)
  		goto out;
  	status = data->rpc_status;
  	if (status != 0)
  		goto out;
  	nfs_refresh_inode(inode, &data->fattr);
  out:
e6b3c4db6   Trond Myklebust   Fix a second pote...
3799
  	rpc_put_task(task);
fe650407a   Trond Myklebust   NFSv4: Make DELEG...
3800
  	return status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3801
  }
e6f810759   Trond Myklebust   NFS: Add an async...
3802
  int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3803
3804
3805
3806
3807
  {
  	struct nfs_server *server = NFS_SERVER(inode);
  	struct nfs4_exception exception = { };
  	int err;
  	do {
e6f810759   Trond Myklebust   NFS: Add an async...
3808
  		err = _nfs4_proc_delegreturn(inode, cred, stateid, issync);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3809
3810
3811
  		switch (err) {
  			case -NFS4ERR_STALE_STATEID:
  			case -NFS4ERR_EXPIRED:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828
  			case 0:
  				return 0;
  		}
  		err = nfs4_handle_exception(server, err, &exception);
  	} while (exception.retry);
  	return err;
  }
  
  #define NFS4_LOCK_MINTIMEOUT (1 * HZ)
  #define NFS4_LOCK_MAXTIMEOUT (30 * HZ)
  
  /* 
   * sleep, with exponential backoff, and retry the LOCK operation. 
   */
  static unsigned long
  nfs4_set_lock_task_retry(unsigned long timeout)
  {
d310310cb   Jeff Layton   Freezer / sunrpc ...
3829
  	freezable_schedule_timeout_killable(timeout);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3830
3831
3832
3833
3834
  	timeout <<= 1;
  	if (timeout > NFS4_LOCK_MAXTIMEOUT)
  		return NFS4_LOCK_MAXTIMEOUT;
  	return timeout;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3835
3836
3837
3838
  static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
  {
  	struct inode *inode = state->inode;
  	struct nfs_server *server = NFS_SERVER(inode);
7539bbab8   David Howells   NFS: Rename nfs_s...
3839
  	struct nfs_client *clp = server->nfs_client;
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3840
  	struct nfs_lockt_args arg = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3841
  		.fh = NFS_FH(inode),
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3842
  		.fl = request,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3843
  	};
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3844
3845
  	struct nfs_lockt_res res = {
  		.denied = request,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3846
3847
3848
3849
3850
3851
3852
  	};
  	struct rpc_message msg = {
  		.rpc_proc	= &nfs4_procedures[NFSPROC4_CLNT_LOCKT],
  		.rpc_argp       = &arg,
  		.rpc_resp       = &res,
  		.rpc_cred	= state->owner->so_cred,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3853
3854
  	struct nfs4_lock_state *lsp;
  	int status;
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3855
  	arg.lock_owner.clientid = clp->cl_clientid;
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
3856
3857
3858
3859
  	status = nfs4_set_lock_state(state, request);
  	if (status != 0)
  		goto out;
  	lsp = request->fl_u.nfs4_fl.owner;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
3860
  	arg.lock_owner.id = lsp->ls_id.id;
d035c36c5   Trond Myklebust   NFSv4: Ensure con...
3861
  	arg.lock_owner.s_dev = server->s_dev;
7c5130588   Bryan Schumaker   NFS: lookup suppo...
3862
  	status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3863
3864
3865
3866
3867
3868
  	switch (status) {
  		case 0:
  			request->fl_type = F_UNLCK;
  			break;
  		case -NFS4ERR_DENIED:
  			status = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3869
  	}
70cc6487a   J. Bruce Fields   locks: make ->loc...
3870
  	request->fl_ops->fl_release_private(request);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
3871
  out:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
  	return status;
  }
  
  static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
  {
  	struct nfs4_exception exception = { };
  	int err;
  
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(state->inode),
  				_nfs4_proc_getlk(state, cmd, request),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
  
  static int do_vfs_lock(struct file *file, struct file_lock *fl)
  {
  	int res = 0;
  	switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
  		case FL_POSIX:
  			res = posix_lock_file_wait(file, fl);
  			break;
  		case FL_FLOCK:
  			res = flock_lock_file_wait(file, fl);
  			break;
  		default:
  			BUG();
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3901
3902
  	return res;
  }
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3903
  struct nfs4_unlockdata {
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3904
3905
  	struct nfs_locku_args arg;
  	struct nfs_locku_res res;
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3906
3907
  	struct nfs4_lock_state *lsp;
  	struct nfs_open_context *ctx;
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3908
3909
  	struct file_lock fl;
  	const struct nfs_server *server;
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
3910
  	unsigned long timestamp;
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3911
  };
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3912
3913
3914
3915
3916
3917
3918
  static struct nfs4_unlockdata *nfs4_alloc_unlockdata(struct file_lock *fl,
  		struct nfs_open_context *ctx,
  		struct nfs4_lock_state *lsp,
  		struct nfs_seqid *seqid)
  {
  	struct nfs4_unlockdata *p;
  	struct inode *inode = lsp->ls_state->inode;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
3919
  	p = kzalloc(sizeof(*p), GFP_NOFS);
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3920
3921
3922
3923
3924
  	if (p == NULL)
  		return NULL;
  	p->arg.fh = NFS_FH(inode);
  	p->arg.fl = &p->fl;
  	p->arg.seqid = seqid;
c1d519312   Trond Myklebust   NFSv4: Only incre...
3925
  	p->res.seqid = seqid;
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3926
3927
3928
3929
3930
3931
3932
3933
3934
  	p->arg.stateid = &lsp->ls_stateid;
  	p->lsp = lsp;
  	atomic_inc(&lsp->ls_count);
  	/* Ensure we don't close file until we're done freeing locks! */
  	p->ctx = get_nfs_open_context(ctx);
  	memcpy(&p->fl, fl, sizeof(p->fl));
  	p->server = NFS_SERVER(inode);
  	return p;
  }
06f814a3a   Trond Myklebust   NFSv4: Make locku...
3935
  static void nfs4_locku_release_calldata(void *data)
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3936
  {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
3937
  	struct nfs4_unlockdata *calldata = data;
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3938
  	nfs_free_seqid(calldata->arg.seqid);
06f814a3a   Trond Myklebust   NFSv4: Make locku...
3939
3940
3941
  	nfs4_put_lock_state(calldata->lsp);
  	put_nfs_open_context(calldata->ctx);
  	kfree(calldata);
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3942
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
3943
  static void nfs4_locku_done(struct rpc_task *task, void *data)
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3944
  {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
3945
  	struct nfs4_unlockdata *calldata = data;
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3946

14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
3947
3948
  	if (!nfs4_sequence_done(task, &calldata->res.seq_res))
  		return;
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3949
3950
3951
  	switch (task->tk_status) {
  		case 0:
  			memcpy(calldata->lsp->ls_stateid.data,
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3952
  					calldata->res.stateid.data,
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3953
  					sizeof(calldata->lsp->ls_stateid.data));
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
3954
  			renew_lease(calldata->server, calldata->timestamp);
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3955
  			break;
9e33bed55   Trond Myklebust   NFSv4: Add recove...
3956
3957
  		case -NFS4ERR_BAD_STATEID:
  		case -NFS4ERR_OLD_STATEID:
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3958
3959
  		case -NFS4ERR_STALE_STATEID:
  		case -NFS4ERR_EXPIRED:
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3960
3961
  			break;
  		default:
9e33bed55   Trond Myklebust   NFSv4: Add recove...
3962
  			if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
d00c5d438   Trond Myklebust   NFS: Get rid of n...
3963
  				rpc_restart_call_prepare(task);
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3964
  	}
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3965
  }
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
3966
  static void nfs4_locku_prepare(struct rpc_task *task, void *data)
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3967
  {
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
3968
  	struct nfs4_unlockdata *calldata = data;
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3969

911d1aaf2   Trond Myklebust   NFSv4: locking XD...
3970
  	if (nfs_wait_on_sequence(calldata->arg.seqid, task) != 0)
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3971
3972
  		return;
  	if ((calldata->lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0) {
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
3973
3974
  		/* Note: exit _without_ running nfs4_locku_done */
  		task->tk_action = NULL;
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3975
3976
  		return;
  	}
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
3977
  	calldata->timestamp = jiffies;
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
3978
  	if (nfs4_setup_sequence(calldata->server,
a893693c1   Andy Adamson   nfs41: locku sequ...
3979
3980
3981
  				&calldata->arg.seq_args,
  				&calldata->res.seq_res, 1, task))
  		return;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
3982
  	rpc_call_start(task);
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
3983
  }
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
3984
  static const struct rpc_call_ops nfs4_locku_ops = {
4ce70ada1   Trond Myklebust   SUNRPC: Further c...
3985
  	.rpc_call_prepare = nfs4_locku_prepare,
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
3986
  	.rpc_call_done = nfs4_locku_done,
06f814a3a   Trond Myklebust   NFSv4: Make locku...
3987
  	.rpc_release = nfs4_locku_release_calldata,
963d8fe53   Trond Myklebust   RPC: Clean up RPC...
3988
  };
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
3989
3990
3991
3992
3993
3994
  static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
  		struct nfs_open_context *ctx,
  		struct nfs4_lock_state *lsp,
  		struct nfs_seqid *seqid)
  {
  	struct nfs4_unlockdata *data;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
3995
3996
3997
3998
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU],
  		.rpc_cred = ctx->cred,
  	};
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
3999
4000
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = NFS_CLIENT(lsp->ls_state->inode),
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
4001
  		.rpc_message = &msg,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
4002
  		.callback_ops = &nfs4_locku_ops,
101070ca2   Trond Myklebust   NFS: Ensure that ...
4003
  		.workqueue = nfsiod_workqueue,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
4004
4005
  		.flags = RPC_TASK_ASYNC,
  	};
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4006

137d6acaa   Frank Filz   NFSv4: Make sure ...
4007
4008
4009
4010
  	/* Ensure this is an unlock - when canceling a lock, the
  	 * canceled lock is passed in, and it won't be an unlock.
  	 */
  	fl->fl_type = F_UNLCK;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4011
4012
4013
4014
4015
  	data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
  	if (data == NULL) {
  		nfs_free_seqid(seqid);
  		return ERR_PTR(-ENOMEM);
  	}
1174dd1f8   Trond Myklebust   NFSv4: Convert a ...
4016
4017
  	msg.rpc_argp = &data->arg;
  	msg.rpc_resp = &data->res;
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
4018
4019
  	task_setup_data.callback_data = data;
  	return rpc_run_task(&task_setup_data);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4020
  }
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
4021
4022
  static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
  {
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
4023
  	struct nfs_inode *nfsi = NFS_I(state->inode);
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
4024
  	struct nfs_seqid *seqid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4025
  	struct nfs4_lock_state *lsp;
06f814a3a   Trond Myklebust   NFSv4: Make locku...
4026
4027
  	struct rpc_task *task;
  	int status = 0;
536ff0f80   Trond Myklebust   NFSv4: Ensure we ...
4028
  	unsigned char fl_flags = request->fl_flags;
faf5f49c2   Trond Myklebust   NFSv4: Make NFS c...
4029

8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
4030
  	status = nfs4_set_lock_state(state, request);
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
4031
4032
  	/* Unlock _before_ we do the RPC call */
  	request->fl_flags |= FL_EXISTS;
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
4033
4034
4035
  	down_read(&nfsi->rwsem);
  	if (do_vfs_lock(request->fl_file, request) == -ENOENT) {
  		up_read(&nfsi->rwsem);
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
4036
  		goto out;
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
4037
4038
  	}
  	up_read(&nfsi->rwsem);
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
4039
  	if (status != 0)
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
4040
4041
4042
4043
  		goto out;
  	/* Is this a delegated lock? */
  	if (test_bit(NFS_DELEGATED_STATE, &state->flags))
  		goto out;
8d0a8a9d0   Trond Myklebust   [PATCH] NFSv4: Cl...
4044
  	lsp = request->fl_u.nfs4_fl.owner;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
4045
  	seqid = nfs_alloc_seqid(&lsp->ls_seqid, GFP_KERNEL);
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
4046
  	status = -ENOMEM;
911d1aaf2   Trond Myklebust   NFSv4: locking XD...
4047
  	if (seqid == NULL)
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
4048
  		goto out;
cd3758e37   Trond Myklebust   NFS: Replace file...
4049
  	task = nfs4_do_unlck(request, nfs_file_open_context(request->fl_file), lsp, seqid);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4050
4051
  	status = PTR_ERR(task);
  	if (IS_ERR(task))
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
4052
  		goto out;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4053
  	status = nfs4_wait_for_completion_rpc_task(task);
e6b3c4db6   Trond Myklebust   Fix a second pote...
4054
  	rpc_put_task(task);
9b0735749   Trond Myklebust   NLM,NFSv4: Don't ...
4055
  out:
536ff0f80   Trond Myklebust   NFSv4: Ensure we ...
4056
  	request->fl_flags = fl_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4057
4058
  	return status;
  }
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4059
4060
4061
4062
4063
4064
  struct nfs4_lockdata {
  	struct nfs_lock_args arg;
  	struct nfs_lock_res res;
  	struct nfs4_lock_state *lsp;
  	struct nfs_open_context *ctx;
  	struct file_lock fl;
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
4065
  	unsigned long timestamp;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4066
4067
  	int rpc_status;
  	int cancelled;
66179efee   Andy Adamson   nfs41: lock seque...
4068
  	struct nfs_server *server;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4069
4070
4071
  };
  
  static struct nfs4_lockdata *nfs4_alloc_lockdata(struct file_lock *fl,
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
4072
4073
  		struct nfs_open_context *ctx, struct nfs4_lock_state *lsp,
  		gfp_t gfp_mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4074
  {
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4075
4076
  	struct nfs4_lockdata *p;
  	struct inode *inode = lsp->ls_state->inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4077
  	struct nfs_server *server = NFS_SERVER(inode);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4078

8535b2be5   Trond Myklebust   NFSv4: Don't use ...
4079
  	p = kzalloc(sizeof(*p), gfp_mask);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4080
4081
4082
4083
4084
  	if (p == NULL)
  		return NULL;
  
  	p->arg.fh = NFS_FH(inode);
  	p->arg.fl = &p->fl;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
4085
  	p->arg.open_seqid = nfs_alloc_seqid(&lsp->ls_state->owner->so_seqid, gfp_mask);
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
4086
4087
  	if (p->arg.open_seqid == NULL)
  		goto out_free;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
4088
  	p->arg.lock_seqid = nfs_alloc_seqid(&lsp->ls_seqid, gfp_mask);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4089
  	if (p->arg.lock_seqid == NULL)
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
4090
  		goto out_free_seqid;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4091
  	p->arg.lock_stateid = &lsp->ls_stateid;
7539bbab8   David Howells   NFS: Rename nfs_s...
4092
  	p->arg.lock_owner.clientid = server->nfs_client->cl_clientid;
9f958ab88   Trond Myklebust   NFSv4: Reduce the...
4093
  	p->arg.lock_owner.id = lsp->ls_id.id;
d035c36c5   Trond Myklebust   NFSv4: Ensure con...
4094
  	p->arg.lock_owner.s_dev = server->s_dev;
c1d519312   Trond Myklebust   NFSv4: Only incre...
4095
  	p->res.lock_seqid = p->arg.lock_seqid;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4096
  	p->lsp = lsp;
66179efee   Andy Adamson   nfs41: lock seque...
4097
  	p->server = server;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4098
4099
4100
4101
  	atomic_inc(&lsp->ls_count);
  	p->ctx = get_nfs_open_context(ctx);
  	memcpy(&p->fl, fl, sizeof(p->fl));
  	return p;
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
4102
4103
  out_free_seqid:
  	nfs_free_seqid(p->arg.open_seqid);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4104
4105
4106
4107
4108
4109
4110
4111
4112
  out_free:
  	kfree(p);
  	return NULL;
  }
  
  static void nfs4_lock_prepare(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_lockdata *data = calldata;
  	struct nfs4_state *state = data->lsp->ls_state;
06735b345   Trond Myklebust   NFSv4: Fix up han...
4113

3110ff804   Harvey Harrison   nfs: replace rema...
4114
4115
  	dprintk("%s: begin!
  ", __func__);
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
4116
4117
  	if (nfs_wait_on_sequence(data->arg.lock_seqid, task) != 0)
  		return;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4118
4119
  	/* Do we need to do an open_to_lock_owner? */
  	if (!(data->arg.lock_seqid->sequence->flags & NFS_SEQID_CONFIRMED)) {
e6e21970b   Trond Myklebust   NFSv4: Fix open_t...
4120
4121
  		if (nfs_wait_on_sequence(data->arg.open_seqid, task) != 0)
  			return;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4122
4123
  		data->arg.open_stateid = &state->stateid;
  		data->arg.new_lock_owner = 1;
c1d519312   Trond Myklebust   NFSv4: Only incre...
4124
  		data->res.open_seqid = data->arg.open_seqid;
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
4125
4126
  	} else
  		data->arg.new_lock_owner = 0;
26e976a88   Trond Myklebust   NFSv4: OPEN/LOCK/...
4127
  	data->timestamp = jiffies;
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
4128
4129
  	if (nfs4_setup_sequence(data->server,
  				&data->arg.seq_args,
66179efee   Andy Adamson   nfs41: lock seque...
4130
4131
  				&data->res.seq_res, 1, task))
  		return;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
4132
  	rpc_call_start(task);
3110ff804   Harvey Harrison   nfs: replace rema...
4133
4134
  	dprintk("%s: done!, ret = %d
  ", __func__, data->rpc_status);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4135
  }
b257957e5   Alexandros Batsakis   nfs: make recover...
4136
4137
4138
4139
4140
  static void nfs4_recover_lock_prepare(struct rpc_task *task, void *calldata)
  {
  	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
  	nfs4_lock_prepare(task, calldata);
  }
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4141
4142
4143
  static void nfs4_lock_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_lockdata *data = calldata;
3110ff804   Harvey Harrison   nfs: replace rema...
4144
4145
  	dprintk("%s: begin!
  ", __func__);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4146

14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
4147
4148
  	if (!nfs4_sequence_done(task, &data->res.seq_res))
  		return;
66179efee   Andy Adamson   nfs41: lock seque...
4149

a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4150
  	data->rpc_status = task->tk_status;
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4151
  	if (data->arg.new_lock_owner != 0) {
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4152
4153
4154
4155
4156
4157
4158
4159
4160
  		if (data->rpc_status == 0)
  			nfs_confirm_seqid(&data->lsp->ls_seqid, 0);
  		else
  			goto out;
  	}
  	if (data->rpc_status == 0) {
  		memcpy(data->lsp->ls_stateid.data, data->res.stateid.data,
  					sizeof(data->lsp->ls_stateid.data));
  		data->lsp->ls_flags |= NFS_LOCK_INITIALIZED;
3d4ff43d8   Al Viro   nfs_open_context ...
4161
  		renew_lease(NFS_SERVER(data->ctx->dentry->d_inode), data->timestamp);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4162
  	}
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4163
  out:
3110ff804   Harvey Harrison   nfs: replace rema...
4164
4165
  	dprintk("%s: done, ret = %d!
  ", __func__, data->rpc_status);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4166
4167
4168
4169
4170
  }
  
  static void nfs4_lock_release(void *calldata)
  {
  	struct nfs4_lockdata *data = calldata;
3110ff804   Harvey Harrison   nfs: replace rema...
4171
4172
  	dprintk("%s: begin!
  ", __func__);
2f74c0a05   Trond Myklebust   NFSv4: Clean up t...
4173
  	nfs_free_seqid(data->arg.open_seqid);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4174
4175
4176
4177
4178
  	if (data->cancelled != 0) {
  		struct rpc_task *task;
  		task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp,
  				data->arg.lock_seqid);
  		if (!IS_ERR(task))
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
4179
  			rpc_put_task_async(task);
3110ff804   Harvey Harrison   nfs: replace rema...
4180
4181
  		dprintk("%s: cancelling lock!
  ", __func__);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4182
4183
4184
4185
4186
  	} else
  		nfs_free_seqid(data->arg.lock_seqid);
  	nfs4_put_lock_state(data->lsp);
  	put_nfs_open_context(data->ctx);
  	kfree(data);
3110ff804   Harvey Harrison   nfs: replace rema...
4187
4188
  	dprintk("%s: done!
  ", __func__);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4189
4190
4191
4192
4193
4194
4195
  }
  
  static const struct rpc_call_ops nfs4_lock_ops = {
  	.rpc_call_prepare = nfs4_lock_prepare,
  	.rpc_call_done = nfs4_lock_done,
  	.rpc_release = nfs4_lock_release,
  };
b257957e5   Alexandros Batsakis   nfs: make recover...
4196
4197
4198
4199
4200
  static const struct rpc_call_ops nfs4_recover_lock_ops = {
  	.rpc_call_prepare = nfs4_recover_lock_prepare,
  	.rpc_call_done = nfs4_lock_done,
  	.rpc_release = nfs4_lock_release,
  };
2bee72a6a   Trond Myklebust   NFSv4: Ensure tha...
4201
4202
  static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_state *lsp, int new_lock_owner, int error)
  {
2bee72a6a   Trond Myklebust   NFSv4: Ensure tha...
4203
4204
4205
  	switch (error) {
  	case -NFS4ERR_ADMIN_REVOKED:
  	case -NFS4ERR_BAD_STATEID:
ecac799a5   Trond Myklebust   NFSv4: Fix the se...
4206
  		lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
2bee72a6a   Trond Myklebust   NFSv4: Ensure tha...
4207
4208
  		if (new_lock_owner != 0 ||
  		   (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
ecac799a5   Trond Myklebust   NFSv4: Fix the se...
4209
  			nfs4_schedule_stateid_recovery(server, lsp->ls_state);
a2c0b9e29   Trond Myklebust   NFS: Ensure that ...
4210
4211
  		break;
  	case -NFS4ERR_STALE_STATEID:
a2c0b9e29   Trond Myklebust   NFS: Ensure that ...
4212
  		lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
ecac799a5   Trond Myklebust   NFSv4: Fix the se...
4213
4214
  	case -NFS4ERR_EXPIRED:
  		nfs4_schedule_lease_recovery(server->nfs_client);
2bee72a6a   Trond Myklebust   NFSv4: Ensure tha...
4215
4216
  	};
  }
afe6c27cc   Alexandros Batsakis   nfs: change nfs4_...
4217
  static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *fl, int recovery_type)
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4218
4219
4220
  {
  	struct nfs4_lockdata *data;
  	struct rpc_task *task;
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
4221
4222
4223
4224
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCK],
  		.rpc_cred = state->owner->so_cred,
  	};
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
4225
4226
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = NFS_CLIENT(state->inode),
5138fde01   Trond Myklebust   NFS/SUNRPC: Conve...
4227
  		.rpc_message = &msg,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
4228
  		.callback_ops = &nfs4_lock_ops,
101070ca2   Trond Myklebust   NFS: Ensure that ...
4229
  		.workqueue = nfsiod_workqueue,
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
4230
4231
  		.flags = RPC_TASK_ASYNC,
  	};
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4232
  	int ret;
3110ff804   Harvey Harrison   nfs: replace rema...
4233
4234
  	dprintk("%s: begin!
  ", __func__);
cd3758e37   Trond Myklebust   NFS: Replace file...
4235
  	data = nfs4_alloc_lockdata(fl, nfs_file_open_context(fl->fl_file),
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
4236
4237
  			fl->fl_u.nfs4_fl.owner,
  			recovery_type == NFS_LOCK_NEW ? GFP_KERNEL : GFP_NOFS);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4238
4239
4240
4241
  	if (data == NULL)
  		return -ENOMEM;
  	if (IS_SETLKW(cmd))
  		data->arg.block = 1;
b257957e5   Alexandros Batsakis   nfs: make recover...
4242
4243
  	if (recovery_type > NFS_LOCK_NEW) {
  		if (recovery_type == NFS_LOCK_RECLAIM)
afe6c27cc   Alexandros Batsakis   nfs: change nfs4_...
4244
  			data->arg.reclaim = NFS_LOCK_RECLAIM;
b257957e5   Alexandros Batsakis   nfs: make recover...
4245
4246
  		task_setup_data.callback_ops = &nfs4_recover_lock_ops;
  	}
1174dd1f8   Trond Myklebust   NFSv4: Convert a ...
4247
4248
  	msg.rpc_argp = &data->arg;
  	msg.rpc_resp = &data->res;
c970aa85e   Trond Myklebust   SUNRPC: Clean up ...
4249
4250
  	task_setup_data.callback_data = data;
  	task = rpc_run_task(&task_setup_data);
7a1218a27   Trond Myklebust   SUNRPC: Ensure rp...
4251
  	if (IS_ERR(task))
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4252
  		return PTR_ERR(task);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4253
4254
4255
  	ret = nfs4_wait_for_completion_rpc_task(task);
  	if (ret == 0) {
  		ret = data->rpc_status;
2bee72a6a   Trond Myklebust   NFSv4: Ensure tha...
4256
4257
4258
  		if (ret)
  			nfs4_handle_setlk_error(data->server, data->lsp,
  					data->arg.new_lock_owner, ret);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4259
4260
  	} else
  		data->cancelled = 1;
e6b3c4db6   Trond Myklebust   Fix a second pote...
4261
  	rpc_put_task(task);
3110ff804   Harvey Harrison   nfs: replace rema...
4262
4263
  	dprintk("%s: done, ret = %d!
  ", __func__, ret);
a5d16a4d0   Trond Myklebust   NFSv4: Convert LO...
4264
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4265
4266
4267
4268
  }
  
  static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
  {
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
4269
4270
4271
4272
4273
  	struct nfs_server *server = NFS_SERVER(state->inode);
  	struct nfs4_exception exception = { };
  	int err;
  
  	do {
42a2d13ee   Trond Myklebust   NFSv4: Ensure nfs...
4274
4275
4276
  		/* Cache the lock if possible... */
  		if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
  			return 0;
afe6c27cc   Alexandros Batsakis   nfs: change nfs4_...
4277
  		err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_RECLAIM);
168667c43   Trond Myklebust   NFSv4: The state ...
4278
  		if (err != -NFS4ERR_DELAY)
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
4279
4280
4281
4282
  			break;
  		nfs4_handle_exception(server, err, &exception);
  	} while (exception.retry);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4283
4284
4285
4286
  }
  
  static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request)
  {
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
4287
4288
4289
  	struct nfs_server *server = NFS_SERVER(state->inode);
  	struct nfs4_exception exception = { };
  	int err;
6bfc93ef9   Trond Myklebust   NFSv4: Teach NFSv...
4290
4291
4292
  	err = nfs4_set_lock_state(state, request);
  	if (err != 0)
  		return err;
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
4293
  	do {
42a2d13ee   Trond Myklebust   NFSv4: Ensure nfs...
4294
4295
  		if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
  			return 0;
afe6c27cc   Alexandros Batsakis   nfs: change nfs4_...
4296
  		err = _nfs4_do_setlk(state, F_SETLK, request, NFS_LOCK_EXPIRED);
a9ed2e258   Trond Myklebust   NFSv4: Handle NFS...
4297
4298
4299
4300
4301
4302
4303
4304
  		switch (err) {
  		default:
  			goto out;
  		case -NFS4ERR_GRACE:
  		case -NFS4ERR_DELAY:
  			nfs4_handle_exception(server, err, &exception);
  			err = 0;
  		}
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
4305
  	} while (exception.retry);
a9ed2e258   Trond Myklebust   NFSv4: Handle NFS...
4306
  out:
202b50dc1   Trond Myklebust   [PATCH] NFSv4: En...
4307
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4308
  }
f062eb6ce   Bryan Schumaker   NFS: test and fre...
4309
4310
4311
4312
4313
4314
4315
4316
4317
4318
4319
4320
4321
  #if defined(CONFIG_NFS_V4_1)
  static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
  {
  	int status;
  	struct nfs_server *server = NFS_SERVER(state->inode);
  
  	status = nfs41_test_stateid(server, state);
  	if (status == NFS_OK)
  		return 0;
  	nfs41_free_stateid(server, state);
  	return nfs4_lock_expired(state, request);
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4322
4323
  static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
  {
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
4324
  	struct nfs_inode *nfsi = NFS_I(state->inode);
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4325
  	unsigned char fl_flags = request->fl_flags;
8e469ebd6   Trond Myklebust   NFSv4: Don't allo...
4326
  	int status = -ENOLCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4327

8e469ebd6   Trond Myklebust   NFSv4: Don't allo...
4328
4329
4330
  	if ((fl_flags & FL_POSIX) &&
  			!test_bit(NFS_STATE_POSIX_LOCKS, &state->flags))
  		goto out;
6bfc93ef9   Trond Myklebust   NFSv4: Teach NFSv...
4331
  	/* Is this a delegated open? */
6bfc93ef9   Trond Myklebust   NFSv4: Teach NFSv...
4332
4333
4334
  	status = nfs4_set_lock_state(state, request);
  	if (status != 0)
  		goto out;
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4335
4336
4337
4338
  	request->fl_flags |= FL_ACCESS;
  	status = do_vfs_lock(request->fl_file, request);
  	if (status < 0)
  		goto out;
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
4339
  	down_read(&nfsi->rwsem);
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4340
  	if (test_bit(NFS_DELEGATED_STATE, &state->flags)) {
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4341
  		/* Yes: cache locks! */
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4342
  		/* ...but avoid races with delegation recall... */
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
4343
4344
4345
  		request->fl_flags = fl_flags & ~FL_SLEEP;
  		status = do_vfs_lock(request->fl_file, request);
  		goto out_unlock;
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4346
  	}
afe6c27cc   Alexandros Batsakis   nfs: change nfs4_...
4347
  	status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
6bfc93ef9   Trond Myklebust   NFSv4: Teach NFSv...
4348
  	if (status != 0)
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4349
  		goto out_unlock;
6bfc93ef9   Trond Myklebust   NFSv4: Teach NFSv...
4350
  	/* Note: we always want to sleep here! */
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4351
  	request->fl_flags = fl_flags | FL_SLEEP;
6bfc93ef9   Trond Myklebust   NFSv4: Teach NFSv...
4352
  	if (do_vfs_lock(request->fl_file, request) < 0)
3110ff804   Harvey Harrison   nfs: replace rema...
4353
4354
  		printk(KERN_WARNING "%s: VFS is out of sync with lock manager!
  ", __func__);
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4355
  out_unlock:
19e03c570   Trond Myklebust   NFSv4: Ensure tha...
4356
  	up_read(&nfsi->rwsem);
01c3b861c   Trond Myklebust   NLM,NFSv4: Wait o...
4357
4358
  out:
  	request->fl_flags = fl_flags;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4359
4360
4361
4362
4363
4364
4365
4366
4367
  	return status;
  }
  
  static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
  {
  	struct nfs4_exception exception = { };
  	int err;
  
  	do {
965b5d679   Trond Myklebust   NFSv4: Handle mor...
4368
4369
4370
  		err = _nfs4_proc_setlk(state, cmd, request);
  		if (err == -NFS4ERR_DENIED)
  			err = -EAGAIN;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4371
  		err = nfs4_handle_exception(NFS_SERVER(state->inode),
965b5d679   Trond Myklebust   NFSv4: Handle mor...
4372
  				err, &exception);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
  	} while (exception.retry);
  	return err;
  }
  
  static int
  nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
  {
  	struct nfs_open_context *ctx;
  	struct nfs4_state *state;
  	unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
  	int status;
  
  	/* verify open state */
cd3758e37   Trond Myklebust   NFS: Replace file...
4386
  	ctx = nfs_file_open_context(filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4387
4388
4389
4390
  	state = ctx->state;
  
  	if (request->fl_start < 0 || request->fl_end < 0)
  		return -EINVAL;
d953126a2   Trond Myklebust   NFSv4: Fix a prob...
4391
4392
4393
4394
4395
  	if (IS_GETLK(cmd)) {
  		if (state != NULL)
  			return nfs4_proc_getlk(state, F_GETLK, request);
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4396
4397
4398
  
  	if (!(IS_SETLK(cmd) || IS_SETLKW(cmd)))
  		return -EINVAL;
d953126a2   Trond Myklebust   NFSv4: Fix a prob...
4399
4400
4401
4402
4403
  	if (request->fl_type == F_UNLCK) {
  		if (state != NULL)
  			return nfs4_proc_unlck(state, cmd, request);
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4404

d953126a2   Trond Myklebust   NFSv4: Fix a prob...
4405
4406
  	if (state == NULL)
  		return -ENOLCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4407
4408
4409
4410
4411
4412
4413
4414
4415
  	do {
  		status = nfs4_proc_setlk(state, cmd, request);
  		if ((status != -EAGAIN) || IS_SETLK(cmd))
  			break;
  		timeout = nfs4_set_lock_task_retry(timeout);
  		status = -ERESTARTSYS;
  		if (signalled())
  			break;
  	} while(status < 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4416
4417
  	return status;
  }
888e694c1   Trond Myklebust   NFSv4: Recover lo...
4418
4419
4420
4421
4422
4423
4424
4425
4426
4427
  int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl)
  {
  	struct nfs_server *server = NFS_SERVER(state->inode);
  	struct nfs4_exception exception = { };
  	int err;
  
  	err = nfs4_set_lock_state(state, fl);
  	if (err != 0)
  		goto out;
  	do {
afe6c27cc   Alexandros Batsakis   nfs: change nfs4_...
4428
  		err = _nfs4_do_setlk(state, F_SETLK, fl, NFS_LOCK_NEW);
d5122201a   Trond Myklebust   NFSv4: Move error...
4429
4430
4431
4432
4433
4434
  		switch (err) {
  			default:
  				printk(KERN_ERR "%s: unhandled error %d.
  ",
  						__func__, err);
  			case 0:
965b5d679   Trond Myklebust   NFSv4: Handle mor...
4435
  			case -ESTALE:
d5122201a   Trond Myklebust   NFSv4: Move error...
4436
4437
  				goto out;
  			case -NFS4ERR_EXPIRED:
0ced63d1a   Trond Myklebust   NFSv4: Handle exp...
4438
  				nfs4_schedule_stateid_recovery(server, state);
d5122201a   Trond Myklebust   NFSv4: Move error...
4439
  			case -NFS4ERR_STALE_CLIENTID:
965b5d679   Trond Myklebust   NFSv4: Handle mor...
4440
  			case -NFS4ERR_STALE_STATEID:
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
4441
4442
  				nfs4_schedule_lease_recovery(server->nfs_client);
  				goto out;
74e7bb73a   Ricardo Labiaga   nfs41: Handle NFS...
4443
4444
4445
4446
4447
  			case -NFS4ERR_BADSESSION:
  			case -NFS4ERR_BADSLOT:
  			case -NFS4ERR_BAD_HIGH_SLOT:
  			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
  			case -NFS4ERR_DEADSESSION:
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
4448
  				nfs4_schedule_session_recovery(server->nfs_client->cl_session);
d5122201a   Trond Myklebust   NFSv4: Move error...
4449
  				goto out;
965b5d679   Trond Myklebust   NFSv4: Handle mor...
4450
4451
4452
4453
4454
4455
4456
4457
  			case -ERESTARTSYS:
  				/*
  				 * The show must go on: exit, but mark the
  				 * stateid as needing recovery.
  				 */
  			case -NFS4ERR_ADMIN_REVOKED:
  			case -NFS4ERR_BAD_STATEID:
  			case -NFS4ERR_OPENMODE:
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
4458
  				nfs4_schedule_stateid_recovery(server, state);
965b5d679   Trond Myklebust   NFSv4: Handle mor...
4459
4460
  				err = 0;
  				goto out;
168667c43   Trond Myklebust   NFSv4: The state ...
4461
4462
4463
4464
4465
4466
4467
4468
4469
  			case -EKEYEXPIRED:
  				/*
  				 * User RPCSEC_GSS context has expired.
  				 * We cannot recover this stateid now, so
  				 * skip it and allow recovery thread to
  				 * proceed.
  				 */
  				err = 0;
  				goto out;
965b5d679   Trond Myklebust   NFSv4: Handle mor...
4470
4471
4472
4473
4474
  			case -ENOMEM:
  			case -NFS4ERR_DENIED:
  				/* kill_proc(fl->fl_pid, SIGLOST, 1); */
  				err = 0;
  				goto out;
d5122201a   Trond Myklebust   NFSv4: Move error...
4475
4476
4477
  			case -NFS4ERR_DELAY:
  				break;
  		}
888e694c1   Trond Myklebust   NFSv4: Recover lo...
4478
4479
4480
4481
4482
  		err = nfs4_handle_exception(server, err, &exception);
  	} while (exception.retry);
  out:
  	return err;
  }
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
4483

d3c7b7ccc   Trond Myklebust   NFSv4: Add suppor...
4484
4485
4486
4487
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
4505
4506
4507
  static void nfs4_release_lockowner_release(void *calldata)
  {
  	kfree(calldata);
  }
  
  const struct rpc_call_ops nfs4_release_lockowner_ops = {
  	.rpc_release = nfs4_release_lockowner_release,
  };
  
  void nfs4_release_lockowner(const struct nfs4_lock_state *lsp)
  {
  	struct nfs_server *server = lsp->ls_state->owner->so_server;
  	struct nfs_release_lockowner_args *args;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
  	};
  
  	if (server->nfs_client->cl_mvops->minor_version != 0)
  		return;
  	args = kmalloc(sizeof(*args), GFP_NOFS);
  	if (!args)
  		return;
  	args->lock_owner.clientid = server->nfs_client->cl_clientid;
  	args->lock_owner.id = lsp->ls_id.id;
d035c36c5   Trond Myklebust   NFSv4: Ensure con...
4508
  	args->lock_owner.s_dev = server->s_dev;
d3c7b7ccc   Trond Myklebust   NFSv4: Add suppor...
4509
4510
4511
  	msg.rpc_argp = args;
  	rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, args);
  }
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
4512
  #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
4513
4514
4515
  static int nfs4_xattr_set_nfs4_acl(struct dentry *dentry, const char *key,
  				   const void *buf, size_t buflen,
  				   int flags, int type)
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
4516
  {
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
4517
4518
  	if (strcmp(key, "") != 0)
  		return -EINVAL;
4b580ee3d   J. Bruce Fields   [PATCH] NFSv4: AC...
4519

64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
4520
  	return nfs4_proc_set_acl(dentry->d_inode, buf, buflen);
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
4521
  }
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
4522
4523
  static int nfs4_xattr_get_nfs4_acl(struct dentry *dentry, const char *key,
  				   void *buf, size_t buflen, int type)
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
4524
  {
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
4525
4526
  	if (strcmp(key, "") != 0)
  		return -EINVAL;
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
4527

64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
4528
  	return nfs4_proc_get_acl(dentry->d_inode, buf, buflen);
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
4529
  }
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
4530
4531
4532
  static size_t nfs4_xattr_list_nfs4_acl(struct dentry *dentry, char *list,
  				       size_t list_len, const char *name,
  				       size_t name_len, int type)
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
4533
  {
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
4534
  	size_t len = sizeof(XATTR_NAME_NFSV4_ACL);
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
4535

096455a22   J. Bruce Fields   NFSv4: Dont list ...
4536
4537
  	if (!nfs4_server_supports_acls(NFS_SERVER(dentry->d_inode)))
  		return 0;
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
4538
4539
4540
  
  	if (list && len <= list_len)
  		memcpy(list, XATTR_NAME_NFSV4_ACL, len);
aa1870af9   J. Bruce Fields   [PATCH] NFSv4: AC...
4541
  	return len;
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
4542
  }
533eb4611   Andy Adamson   NFSv4.1: allow nf...
4543
4544
4545
  /*
   * nfs_fhget will use either the mounted_on_fileid or the fileid
   */
69aaaae18   Trond Myklebust   NFSv4: A referral...
4546
4547
  static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr)
  {
533eb4611   Andy Adamson   NFSv4.1: allow nf...
4548
4549
4550
4551
  	if (!(((fattr->valid & NFS_ATTR_FATTR_MOUNTED_ON_FILEID) ||
  	       (fattr->valid & NFS_ATTR_FATTR_FILEID)) &&
  	      (fattr->valid & NFS_ATTR_FATTR_FSID) &&
  	      (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL)))
69aaaae18   Trond Myklebust   NFSv4: A referral...
4552
4553
4554
4555
4556
4557
4558
  		return;
  
  	fattr->valid |= NFS_ATTR_FATTR_TYPE | NFS_ATTR_FATTR_MODE |
  		NFS_ATTR_FATTR_NLINK;
  	fattr->mode = S_IFDIR | S_IRUGO | S_IXUGO;
  	fattr->nlink = 2;
  }
56659e992   Trond Myklebust   NFSv4: 'constify'...
4559
  int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
7aaa0b3bd   Manoj Naik   NFSv4: convert fs...
4560
  		struct nfs4_fs_locations *fs_locations, struct page *page)
683b57b43   Trond Myklebust   NFSv4: Implement ...
4561
4562
4563
  {
  	struct nfs_server *server = NFS_SERVER(dir);
  	u32 bitmask[2] = {
361e624f6   Manoj Naik   NFSv4: GETATTR at...
4564
  		[0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
683b57b43   Trond Myklebust   NFSv4: Implement ...
4565
4566
4567
  	};
  	struct nfs4_fs_locations_arg args = {
  		.dir_fh = NFS_FH(dir),
c228fd3ae   Trond Myklebust   NFSv4: Cleanups f...
4568
  		.name = name,
683b57b43   Trond Myklebust   NFSv4: Implement ...
4569
4570
4571
  		.page = page,
  		.bitmask = bitmask,
  	};
22958463d   Benny Halevy   nfs41: use nfs4_f...
4572
4573
4574
  	struct nfs4_fs_locations_res res = {
  		.fs_locations = fs_locations,
  	};
683b57b43   Trond Myklebust   NFSv4: Implement ...
4575
4576
4577
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
  		.rpc_argp = &args,
22958463d   Benny Halevy   nfs41: use nfs4_f...
4578
  		.rpc_resp = &res,
683b57b43   Trond Myklebust   NFSv4: Implement ...
4579
4580
  	};
  	int status;
3110ff804   Harvey Harrison   nfs: replace rema...
4581
4582
  	dprintk("%s: start
  ", __func__);
533eb4611   Andy Adamson   NFSv4.1: allow nf...
4583
4584
4585
4586
4587
4588
4589
  
  	/* Ask for the fileid of the absent filesystem if mounted_on_fileid
  	 * is not supported */
  	if (NFS_SERVER(dir)->attr_bitmask[1] & FATTR4_WORD1_MOUNTED_ON_FILEID)
  		bitmask[1] |= FATTR4_WORD1_MOUNTED_ON_FILEID;
  	else
  		bitmask[0] |= FATTR4_WORD0_FILEID;
c228fd3ae   Trond Myklebust   NFSv4: Cleanups f...
4590
  	nfs_fattr_init(&fs_locations->fattr);
683b57b43   Trond Myklebust   NFSv4: Implement ...
4591
  	fs_locations->server = server;
830b8e33f   Manoj Naik   NFSv4: Define an ...
4592
  	fs_locations->nlocations = 0;
7c5130588   Bryan Schumaker   NFS: lookup suppo...
4593
  	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
3110ff804   Harvey Harrison   nfs: replace rema...
4594
4595
  	dprintk("%s: returned status = %d
  ", __func__, status);
683b57b43   Trond Myklebust   NFSv4: Implement ...
4596
4597
  	return status;
  }
5a5ea0d48   Bryan Schumaker   NFS: Add secinfo ...
4598
4599
4600
4601
4602
4603
4604
4605
4606
4607
4608
4609
4610
4611
4612
4613
4614
4615
4616
4617
4618
4619
4620
4621
4622
4623
4624
4625
4626
4627
4628
4629
4630
4631
4632
  static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
  {
  	int status;
  	struct nfs4_secinfo_arg args = {
  		.dir_fh = NFS_FH(dir),
  		.name   = name,
  	};
  	struct nfs4_secinfo_res res = {
  		.flavors     = flavors,
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  
  	dprintk("NFS call  secinfo %s
  ", name->name);
  	status = nfs4_call_sync(NFS_SERVER(dir)->client, NFS_SERVER(dir), &msg, &args.seq_args, &res.seq_res, 0);
  	dprintk("NFS reply  secinfo: %d
  ", status);
  	return status;
  }
  
  int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct nfs4_secinfo_flavors *flavors)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(NFS_SERVER(dir),
  				_nfs4_proc_secinfo(dir, name, flavors),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
557134a39   Andy Adamson   nfs41: sessions c...
4633
  #ifdef CONFIG_NFS_V4_1
99fe60d06   Benny Halevy   nfs41: exchange_i...
4634
  /*
357f54d6b   Andy Adamson   NFS fix the setti...
4635
4636
4637
4638
4639
4640
4641
4642
4643
4644
4645
4646
4647
4648
4649
4650
4651
   * Check the exchange flags returned by the server for invalid flags, having
   * both PNFS and NON_PNFS flags set, and not having one of NON_PNFS, PNFS, or
   * DS flags set.
   */
  static int nfs4_check_cl_exchange_flags(u32 flags)
  {
  	if (flags & ~EXCHGID4_FLAG_MASK_R)
  		goto out_inval;
  	if ((flags & EXCHGID4_FLAG_USE_PNFS_MDS) &&
  	    (flags & EXCHGID4_FLAG_USE_NON_PNFS))
  		goto out_inval;
  	if (!(flags & (EXCHGID4_FLAG_MASK_PNFS)))
  		goto out_inval;
  	return NFS_OK;
  out_inval:
  	return -NFS4ERR_INVAL;
  }
78fe0f41d   Weston Andros Adamson   NFS: use scope fr...
4652
4653
4654
4655
4656
4657
4658
4659
4660
  static bool
  nfs41_same_server_scope(struct server_scope *a, struct server_scope *b)
  {
  	if (a->server_scope_sz == b->server_scope_sz &&
  	    memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0)
  		return true;
  
  	return false;
  }
357f54d6b   Andy Adamson   NFS fix the setti...
4661
  /*
99fe60d06   Benny Halevy   nfs41: exchange_i...
4662
4663
4664
4665
4666
4667
4668
   * nfs4_proc_exchange_id()
   *
   * Since the clientid has expired, all compounds using sessions
   * associated with the stale clientid will be returning
   * NFS4ERR_BADSESSION in the sequence operation, and will therefore
   * be in some phase of session reset.
   */
4d643d1df   Andy Adamson   nfs41: add create...
4669
  int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
99fe60d06   Benny Halevy   nfs41: exchange_i...
4670
4671
4672
4673
  {
  	nfs4_verifier verifier;
  	struct nfs41_exchange_id_args args = {
  		.client = clp,
357f54d6b   Andy Adamson   NFS fix the setti...
4674
  		.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER,
99fe60d06   Benny Halevy   nfs41: exchange_i...
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
  	};
  	struct nfs41_exchange_id_res res = {
  		.client = clp,
  	};
  	int status;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  		.rpc_cred = cred,
  	};
  	__be32 *p;
  
  	dprintk("--> %s
  ", __func__);
  	BUG_ON(clp == NULL);
a7b721037   Andy Adamson   nfs41: introduce ...
4691

99fe60d06   Benny Halevy   nfs41: exchange_i...
4692
4693
4694
4695
  	p = (u32 *)verifier.data;
  	*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
  	*p = htonl((u32)clp->cl_boot_time.tv_nsec);
  	args.verifier = &verifier;
c7a360b05   Andy Adamson   NFS construct con...
4696
4697
4698
4699
4700
4701
  	args.id_len = scnprintf(args.id, sizeof(args.id),
  				"%s/%s.%s/%u",
  				clp->cl_ipaddr,
  				init_utsname()->nodename,
  				init_utsname()->domainname,
  				clp->cl_rpcclient->cl_auth->au_flavor);
99fe60d06   Benny Halevy   nfs41: exchange_i...
4702

78fe0f41d   Weston Andros Adamson   NFS: use scope fr...
4703
4704
4705
  	res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL);
  	if (unlikely(!res.server_scope))
  		return -ENOMEM;
1bd714f2a   Trond Myklebust   NFSv4: Ensure tha...
4706
  	status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
c7a360b05   Andy Adamson   NFS construct con...
4707
4708
  	if (!status)
  		status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags);
78fe0f41d   Weston Andros Adamson   NFS: use scope fr...
4709
4710
4711
4712
4713
4714
4715
4716
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
  
  	if (!status) {
  		if (clp->server_scope &&
  		    !nfs41_same_server_scope(clp->server_scope,
  					     res.server_scope)) {
  			dprintk("%s: server_scope mismatch detected
  ",
  				__func__);
  			set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state);
  			kfree(clp->server_scope);
  			clp->server_scope = NULL;
  		}
  
  		if (!clp->server_scope)
  			clp->server_scope = res.server_scope;
  		else
  			kfree(res.server_scope);
  	}
99fe60d06   Benny Halevy   nfs41: exchange_i...
4727
4728
4729
4730
  	dprintk("<-- %s status= %d
  ", __func__, status);
  	return status;
  }
2050f0cc0   Andy Adamson   nfs41: get_lease_...
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
  struct nfs4_get_lease_time_data {
  	struct nfs4_get_lease_time_args *args;
  	struct nfs4_get_lease_time_res *res;
  	struct nfs_client *clp;
  };
  
  static void nfs4_get_lease_time_prepare(struct rpc_task *task,
  					void *calldata)
  {
  	int ret;
  	struct nfs4_get_lease_time_data *data =
  			(struct nfs4_get_lease_time_data *)calldata;
  
  	dprintk("--> %s
  ", __func__);
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
4746
  	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
2050f0cc0   Andy Adamson   nfs41: get_lease_...
4747
4748
4749
  	/* just setup sequence, do not trigger session recovery
  	   since we're invoked within one */
  	ret = nfs41_setup_sequence(data->clp->cl_session,
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
4750
4751
  				   &data->args->la_seq_args,
  				   &data->res->lr_seq_res, 0, task);
2050f0cc0   Andy Adamson   nfs41: get_lease_...
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
  
  	BUG_ON(ret == -EAGAIN);
  	rpc_call_start(task);
  	dprintk("<-- %s
  ", __func__);
  }
  
  /*
   * Called from nfs4_state_manager thread for session setup, so don't recover
   * from sequence operation or clientid errors.
   */
  static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_get_lease_time_data *data =
  			(struct nfs4_get_lease_time_data *)calldata;
  
  	dprintk("--> %s
  ", __func__);
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
4770
4771
  	if (!nfs41_sequence_done(task, &data->res->lr_seq_res))
  		return;
2050f0cc0   Andy Adamson   nfs41: get_lease_...
4772
4773
4774
4775
4776
4777
4778
  	switch (task->tk_status) {
  	case -NFS4ERR_DELAY:
  	case -NFS4ERR_GRACE:
  		dprintk("%s Retry: tk_status %d
  ", __func__, task->tk_status);
  		rpc_delay(task, NFS4_POLL_RETRY_MIN);
  		task->tk_status = 0;
a8a4ae3a8   Andy Adamson   NFSv41: Resend on...
4779
4780
  		/* fall through */
  	case -NFS4ERR_RETRY_UNCACHED_REP:
d00c5d438   Trond Myklebust   NFS: Get rid of n...
4781
  		rpc_restart_call_prepare(task);
2050f0cc0   Andy Adamson   nfs41: get_lease_...
4782
4783
  		return;
  	}
2050f0cc0   Andy Adamson   nfs41: get_lease_...
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
4808
4809
4810
4811
4812
4813
  	dprintk("<-- %s
  ", __func__);
  }
  
  struct rpc_call_ops nfs4_get_lease_time_ops = {
  	.rpc_call_prepare = nfs4_get_lease_time_prepare,
  	.rpc_call_done = nfs4_get_lease_time_done,
  };
  
  int nfs4_proc_get_lease_time(struct nfs_client *clp, struct nfs_fsinfo *fsinfo)
  {
  	struct rpc_task *task;
  	struct nfs4_get_lease_time_args args;
  	struct nfs4_get_lease_time_res res = {
  		.lr_fsinfo = fsinfo,
  	};
  	struct nfs4_get_lease_time_data data = {
  		.args = &args,
  		.res = &res,
  		.clp = clp,
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GET_LEASE_TIME],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  	struct rpc_task_setup task_setup = {
  		.rpc_client = clp->cl_rpcclient,
  		.rpc_message = &msg,
  		.callback_ops = &nfs4_get_lease_time_ops,
1bd714f2a   Trond Myklebust   NFSv4: Ensure tha...
4814
4815
  		.callback_data = &data,
  		.flags = RPC_TASK_TIMEOUT,
2050f0cc0   Andy Adamson   nfs41: get_lease_...
4816
4817
  	};
  	int status;
2050f0cc0   Andy Adamson   nfs41: get_lease_...
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
  	dprintk("--> %s
  ", __func__);
  	task = rpc_run_task(&task_setup);
  
  	if (IS_ERR(task))
  		status = PTR_ERR(task);
  	else {
  		status = task->tk_status;
  		rpc_put_task(task);
  	}
  	dprintk("<-- %s return %d
  ", __func__, status);
  
  	return status;
  }
b73dafa7a   Ricardo Labiaga   nfs41: Backchanne...
4833
4834
4835
  /*
   * Reset a slot table
   */
104aeba48   Andy Adamson   nfs41: resize slo...
4836
4837
  static int nfs4_reset_slot_table(struct nfs4_slot_table *tbl, u32 max_reqs,
  				 int ivalue)
ac72b7b3b   Andy Adamson   nfs41: reset the ...
4838
  {
104aeba48   Andy Adamson   nfs41: resize slo...
4839
  	struct nfs4_slot *new = NULL;
b73dafa7a   Ricardo Labiaga   nfs41: Backchanne...
4840
  	int i;
ac72b7b3b   Andy Adamson   nfs41: reset the ...
4841
  	int ret = 0;
104aeba48   Andy Adamson   nfs41: resize slo...
4842
4843
4844
  	dprintk("--> %s: max_reqs=%u, tbl->max_slots %d
  ", __func__,
  		max_reqs, tbl->max_slots);
ac72b7b3b   Andy Adamson   nfs41: reset the ...
4845

104aeba48   Andy Adamson   nfs41: resize slo...
4846
4847
4848
4849
  	/* Does the newly negotiated max_reqs match the existing slot table? */
  	if (max_reqs != tbl->max_slots) {
  		ret = -ENOMEM;
  		new = kmalloc(max_reqs * sizeof(struct nfs4_slot),
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
4850
  			      GFP_NOFS);
104aeba48   Andy Adamson   nfs41: resize slo...
4851
4852
4853
4854
  		if (!new)
  			goto out;
  		ret = 0;
  		kfree(tbl->slots);
ac72b7b3b   Andy Adamson   nfs41: reset the ...
4855
4856
  	}
  	spin_lock(&tbl->slot_tbl_lock);
104aeba48   Andy Adamson   nfs41: resize slo...
4857
4858
4859
4860
4861
  	if (new) {
  		tbl->slots = new;
  		tbl->max_slots = max_reqs;
  	}
  	for (i = 0; i < tbl->max_slots; ++i)
b73dafa7a   Ricardo Labiaga   nfs41: Backchanne...
4862
  		tbl->slots[i].seq_nr = ivalue;
ac72b7b3b   Andy Adamson   nfs41: reset the ...
4863
4864
4865
4866
4867
4868
4869
4870
4871
  	spin_unlock(&tbl->slot_tbl_lock);
  	dprintk("%s: tbl=%p slots=%p max_slots=%d
  ", __func__,
  		tbl, tbl->slots, tbl->max_slots);
  out:
  	dprintk("<-- %s: return %d
  ", __func__, ret);
  	return ret;
  }
f8625a6a4   Ricardo Labiaga   nfs41: Backchanne...
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
  /* Destroy the slot table */
  static void nfs4_destroy_slot_tables(struct nfs4_session *session)
  {
  	if (session->fc_slot_table.slots != NULL) {
  		kfree(session->fc_slot_table.slots);
  		session->fc_slot_table.slots = NULL;
  	}
  	if (session->bc_slot_table.slots != NULL) {
  		kfree(session->bc_slot_table.slots);
  		session->bc_slot_table.slots = NULL;
  	}
  	return;
  }
b73dafa7a   Ricardo Labiaga   nfs41: Backchanne...
4885
  /*
fc931582c   Andy Adamson   nfs41: create_ses...
4886
4887
   * Initialize slot table
   */
050047ce7   Ricardo Labiaga   nfs41: Backchanne...
4888
4889
  static int nfs4_init_slot_table(struct nfs4_slot_table *tbl,
  		int max_slots, int ivalue)
fc931582c   Andy Adamson   nfs41: create_ses...
4890
  {
fc931582c   Andy Adamson   nfs41: create_ses...
4891
4892
4893
4894
  	struct nfs4_slot *slot;
  	int ret = -ENOMEM;
  
  	BUG_ON(max_slots > NFS4_MAX_SLOT_TABLE);
050047ce7   Ricardo Labiaga   nfs41: Backchanne...
4895
4896
  	dprintk("--> %s: max_reqs=%u
  ", __func__, max_slots);
fc931582c   Andy Adamson   nfs41: create_ses...
4897

8535b2be5   Trond Myklebust   NFSv4: Don't use ...
4898
  	slot = kcalloc(max_slots, sizeof(struct nfs4_slot), GFP_NOFS);
fc931582c   Andy Adamson   nfs41: create_ses...
4899
4900
  	if (!slot)
  		goto out;
fc931582c   Andy Adamson   nfs41: create_ses...
4901
4902
4903
  	ret = 0;
  
  	spin_lock(&tbl->slot_tbl_lock);
fc931582c   Andy Adamson   nfs41: create_ses...
4904
4905
4906
4907
4908
4909
4910
4911
4912
4913
4914
  	tbl->max_slots = max_slots;
  	tbl->slots = slot;
  	tbl->highest_used_slotid = -1;  /* no slot is currently used */
  	spin_unlock(&tbl->slot_tbl_lock);
  	dprintk("%s: tbl=%p slots=%p max_slots=%d
  ", __func__,
  		tbl, tbl->slots, tbl->max_slots);
  out:
  	dprintk("<-- %s: return %d
  ", __func__, ret);
  	return ret;
fc931582c   Andy Adamson   nfs41: create_ses...
4915
  }
050047ce7   Ricardo Labiaga   nfs41: Backchanne...
4916
  /*
aacd55372   Andy Adamson   NFSv4.1: cleanup ...
4917
   * Initialize or reset the forechannel and backchannel tables
050047ce7   Ricardo Labiaga   nfs41: Backchanne...
4918
   */
aacd55372   Andy Adamson   NFSv4.1: cleanup ...
4919
  static int nfs4_setup_session_slot_tables(struct nfs4_session *ses)
050047ce7   Ricardo Labiaga   nfs41: Backchanne...
4920
  {
f26468fb9   Trond Myklebust   NFSv41: Fix nfs4_...
4921
  	struct nfs4_slot_table *tbl;
aacd55372   Andy Adamson   NFSv4.1: cleanup ...
4922
  	int status;
050047ce7   Ricardo Labiaga   nfs41: Backchanne...
4923

aacd55372   Andy Adamson   NFSv4.1: cleanup ...
4924
4925
4926
4927
  	dprintk("--> %s
  ", __func__);
  	/* Fore channel */
  	tbl = &ses->fc_slot_table;
f26468fb9   Trond Myklebust   NFSv41: Fix nfs4_...
4928
  	if (tbl->slots == NULL) {
aacd55372   Andy Adamson   NFSv4.1: cleanup ...
4929
4930
4931
4932
4933
  		status = nfs4_init_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
  		if (status) /* -ENOMEM */
  			return status;
  	} else {
  		status = nfs4_reset_slot_table(tbl, ses->fc_attrs.max_reqs, 1);
f26468fb9   Trond Myklebust   NFSv41: Fix nfs4_...
4934
4935
4936
  		if (status)
  			return status;
  	}
aacd55372   Andy Adamson   NFSv4.1: cleanup ...
4937
4938
  	/* Back channel */
  	tbl = &ses->bc_slot_table;
f26468fb9   Trond Myklebust   NFSv41: Fix nfs4_...
4939
  	if (tbl->slots == NULL) {
aacd55372   Andy Adamson   NFSv4.1: cleanup ...
4940
  		status = nfs4_init_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
f26468fb9   Trond Myklebust   NFSv41: Fix nfs4_...
4941
  		if (status)
aacd55372   Andy Adamson   NFSv4.1: cleanup ...
4942
4943
4944
4945
4946
  			/* Fore and back channel share a connection so get
  			 * both slot tables or neither */
  			nfs4_destroy_slot_tables(ses);
  	} else
  		status = nfs4_reset_slot_table(tbl, ses->bc_attrs.max_reqs, 0);
f8625a6a4   Ricardo Labiaga   nfs41: Backchanne...
4947
  	return status;
557134a39   Andy Adamson   nfs41: sessions c...
4948
4949
4950
4951
4952
4953
  }
  
  struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
  {
  	struct nfs4_session *session;
  	struct nfs4_slot_table *tbl;
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
4954
  	session = kzalloc(sizeof(struct nfs4_session), GFP_NOFS);
557134a39   Andy Adamson   nfs41: sessions c...
4955
4956
  	if (!session)
  		return NULL;
76db6d950   Andy Adamson   nfs41: add sessio...
4957

557134a39   Andy Adamson   nfs41: sessions c...
4958
  	tbl = &session->fc_slot_table;
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
4959
  	tbl->highest_used_slotid = -1;
557134a39   Andy Adamson   nfs41: sessions c...
4960
  	spin_lock_init(&tbl->slot_tbl_lock);
689cf5c15   Alexandros Batsakis   nfs: enforce FIFO...
4961
  	rpc_init_priority_wait_queue(&tbl->slot_tbl_waitq, "ForeChannel Slot table");
42acd0218   Andy Adamson   NFS add session b...
4962
  	init_completion(&tbl->complete);
f8625a6a4   Ricardo Labiaga   nfs41: Backchanne...
4963
4964
  
  	tbl = &session->bc_slot_table;
9dfdf404c   Ricardo Labiaga   nfs41: Don't clea...
4965
  	tbl->highest_used_slotid = -1;
f8625a6a4   Ricardo Labiaga   nfs41: Backchanne...
4966
4967
  	spin_lock_init(&tbl->slot_tbl_lock);
  	rpc_init_wait_queue(&tbl->slot_tbl_waitq, "BackChannel Slot table");
42acd0218   Andy Adamson   NFS add session b...
4968
  	init_completion(&tbl->complete);
f8625a6a4   Ricardo Labiaga   nfs41: Backchanne...
4969

1055d76d9   Trond Myklebust   NFSv4.1: There is...
4970
  	session->session_state = 1<<NFS4_SESSION_INITING;
557134a39   Andy Adamson   nfs41: sessions c...
4971
4972
4973
4974
4975
4976
  	session->clp = clp;
  	return session;
  }
  
  void nfs4_destroy_session(struct nfs4_session *session)
  {
5a0ffe544   Andy Adamson   nfs41: Release ba...
4977
4978
4979
4980
4981
4982
  	nfs4_proc_destroy_session(session);
  	dprintk("%s Destroy backchannel for xprt %p
  ",
  		__func__, session->clp->cl_rpcclient->cl_xprt);
  	xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt,
  				NFS41_BC_MIN_CALLBACKS);
f8625a6a4   Ricardo Labiaga   nfs41: Backchanne...
4983
  	nfs4_destroy_slot_tables(session);
557134a39   Andy Adamson   nfs41: sessions c...
4984
4985
  	kfree(session);
  }
fc931582c   Andy Adamson   nfs41: create_ses...
4986
4987
4988
4989
4990
4991
4992
4993
4994
4995
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
  /*
   * Initialize the values to be used by the client in CREATE_SESSION
   * If nfs4_init_session set the fore channel request and response sizes,
   * use them.
   *
   * Set the back channel max_resp_sz_cached to zero to force the client to
   * always set csa_cachethis to FALSE because the current implementation
   * of the back channel DRC only supports caching the CB_SEQUENCE operation.
   */
  static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args)
  {
  	struct nfs4_session *session = args->client->cl_session;
  	unsigned int mxrqst_sz = session->fc_attrs.max_rqst_sz,
  		     mxresp_sz = session->fc_attrs.max_resp_sz;
  
  	if (mxrqst_sz == 0)
  		mxrqst_sz = NFS_MAX_FILE_IO_SIZE;
  	if (mxresp_sz == 0)
  		mxresp_sz = NFS_MAX_FILE_IO_SIZE;
  	/* Fore channel attributes */
fc931582c   Andy Adamson   nfs41: create_ses...
5006
5007
  	args->fc_attrs.max_rqst_sz = mxrqst_sz;
  	args->fc_attrs.max_resp_sz = mxresp_sz;
fc931582c   Andy Adamson   nfs41: create_ses...
5008
5009
5010
5011
  	args->fc_attrs.max_ops = NFS4_MAX_OPS;
  	args->fc_attrs.max_reqs = session->clp->cl_rpcclient->cl_xprt->max_reqs;
  
  	dprintk("%s: Fore Channel : max_rqst_sz=%u max_resp_sz=%u "
8e0d46e13   Mike Sager   nfs41: Adjust max...
5012
5013
  		"max_ops=%u max_reqs=%u
  ",
fc931582c   Andy Adamson   nfs41: create_ses...
5014
5015
  		__func__,
  		args->fc_attrs.max_rqst_sz, args->fc_attrs.max_resp_sz,
8e0d46e13   Mike Sager   nfs41: Adjust max...
5016
  		args->fc_attrs.max_ops, args->fc_attrs.max_reqs);
fc931582c   Andy Adamson   nfs41: create_ses...
5017
5018
  
  	/* Back channel attributes */
fc931582c   Andy Adamson   nfs41: create_ses...
5019
5020
5021
5022
5023
5024
5025
5026
5027
5028
5029
5030
5031
5032
  	args->bc_attrs.max_rqst_sz = PAGE_SIZE;
  	args->bc_attrs.max_resp_sz = PAGE_SIZE;
  	args->bc_attrs.max_resp_sz_cached = 0;
  	args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS;
  	args->bc_attrs.max_reqs = 1;
  
  	dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u "
  		"max_resp_sz_cached=%u max_ops=%u max_reqs=%u
  ",
  		__func__,
  		args->bc_attrs.max_rqst_sz, args->bc_attrs.max_resp_sz,
  		args->bc_attrs.max_resp_sz_cached, args->bc_attrs.max_ops,
  		args->bc_attrs.max_reqs);
  }
43c2e885b   J. Bruce Fields   nfs4: fix channel...
5033
  static int nfs4_verify_fore_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
8d35301d7   Andy Adamson   nfs41: verify ses...
5034
  {
43c2e885b   J. Bruce Fields   nfs4: fix channel...
5035
5036
  	struct nfs4_channel_attrs *sent = &args->fc_attrs;
  	struct nfs4_channel_attrs *rcvd = &session->fc_attrs;
43c2e885b   J. Bruce Fields   nfs4: fix channel...
5037
5038
5039
5040
5041
5042
5043
5044
5045
5046
5047
5048
5049
  	if (rcvd->max_resp_sz > sent->max_resp_sz)
  		return -EINVAL;
  	/*
  	 * Our requested max_ops is the minimum we need; we're not
  	 * prepared to break up compounds into smaller pieces than that.
  	 * So, no point even trying to continue if the server won't
  	 * cooperate:
  	 */
  	if (rcvd->max_ops < sent->max_ops)
  		return -EINVAL;
  	if (rcvd->max_reqs == 0)
  		return -EINVAL;
  	return 0;
8d35301d7   Andy Adamson   nfs41: verify ses...
5050
  }
43c2e885b   J. Bruce Fields   nfs4: fix channel...
5051
5052
5053
5054
  static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args, struct nfs4_session *session)
  {
  	struct nfs4_channel_attrs *sent = &args->bc_attrs;
  	struct nfs4_channel_attrs *rcvd = &session->bc_attrs;
8d35301d7   Andy Adamson   nfs41: verify ses...
5055

43c2e885b   J. Bruce Fields   nfs4: fix channel...
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
  	if (rcvd->max_rqst_sz > sent->max_rqst_sz)
  		return -EINVAL;
  	if (rcvd->max_resp_sz < sent->max_resp_sz)
  		return -EINVAL;
  	if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
  		return -EINVAL;
  	/* These would render the backchannel useless: */
  	if (rcvd->max_ops  == 0)
  		return -EINVAL;
  	if (rcvd->max_reqs == 0)
  		return -EINVAL;
  	return 0;
  }
8d35301d7   Andy Adamson   nfs41: verify ses...
5069

8d35301d7   Andy Adamson   nfs41: verify ses...
5070
5071
5072
  static int nfs4_verify_channel_attrs(struct nfs41_create_session_args *args,
  				     struct nfs4_session *session)
  {
43c2e885b   J. Bruce Fields   nfs4: fix channel...
5073
  	int ret;
8d35301d7   Andy Adamson   nfs41: verify ses...
5074

43c2e885b   J. Bruce Fields   nfs4: fix channel...
5075
5076
5077
5078
  	ret = nfs4_verify_fore_channel_attrs(args, session);
  	if (ret)
  		return ret;
  	return nfs4_verify_back_channel_attrs(args, session);
8d35301d7   Andy Adamson   nfs41: verify ses...
5079
  }
fc931582c   Andy Adamson   nfs41: create_ses...
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
5091
5092
5093
5094
5095
5096
5097
  static int _nfs4_proc_create_session(struct nfs_client *clp)
  {
  	struct nfs4_session *session = clp->cl_session;
  	struct nfs41_create_session_args args = {
  		.client = clp,
  		.cb_program = NFS4_CALLBACK,
  	};
  	struct nfs41_create_session_res res = {
  		.client = clp,
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE_SESSION],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  	int status;
  
  	nfs4_init_channel_attrs(&args);
0f91421e8   Andy Adamson   nfs41: Client ind...
5098
  	args.flags = (SESSION4_PERSIST | SESSION4_BACK_CHAN);
fc931582c   Andy Adamson   nfs41: create_ses...
5099

1bd714f2a   Trond Myklebust   NFSv4: Ensure tha...
5100
  	status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
fc931582c   Andy Adamson   nfs41: create_ses...
5101

8d35301d7   Andy Adamson   nfs41: verify ses...
5102
5103
5104
  	if (!status)
  		/* Verify the session's negotiated channel_attrs values */
  		status = nfs4_verify_channel_attrs(&args, session);
fc931582c   Andy Adamson   nfs41: create_ses...
5105
5106
5107
5108
5109
5110
5111
5112
5113
5114
5115
5116
5117
  	if (!status) {
  		/* Increment the clientid slot sequence id */
  		clp->cl_seqid++;
  	}
  
  	return status;
  }
  
  /*
   * Issues a CREATE_SESSION operation to the server.
   * It is the responsibility of the caller to verify the session is
   * expired before calling this routine.
   */
f26468fb9   Trond Myklebust   NFSv41: Fix nfs4_...
5118
  int nfs4_proc_create_session(struct nfs_client *clp)
fc931582c   Andy Adamson   nfs41: create_ses...
5119
5120
5121
  {
  	int status;
  	unsigned *ptr;
fc931582c   Andy Adamson   nfs41: create_ses...
5122
5123
5124
5125
  	struct nfs4_session *session = clp->cl_session;
  
  	dprintk("--> %s clp=%p session=%p
  ", __func__, clp, session);
fd954ae12   Trond Myklebust   NFSv4.1: Don't lo...
5126
  	status = _nfs4_proc_create_session(clp);
fc931582c   Andy Adamson   nfs41: create_ses...
5127
5128
  	if (status)
  		goto out;
aacd55372   Andy Adamson   NFSv4.1: cleanup ...
5129
5130
5131
5132
  	/* Init or reset the session slot tables */
  	status = nfs4_setup_session_slot_tables(session);
  	dprintk("slot table setup returned %d
  ", status);
fc931582c   Andy Adamson   nfs41: create_ses...
5133
5134
5135
5136
5137
5138
5139
  	if (status)
  		goto out;
  
  	ptr = (unsigned *)&session->sess_id.data[0];
  	dprintk("%s client>seqid %d sessionid %u:%u:%u:%u
  ", __func__,
  		clp->cl_seqid, ptr[0], ptr[1], ptr[2], ptr[3]);
fc931582c   Andy Adamson   nfs41: create_ses...
5140
5141
5142
5143
5144
  out:
  	dprintk("<-- %s
  ", __func__);
  	return status;
  }
0f3e66c6a   Andy Adamson   nfs41: destroy_se...
5145
5146
5147
5148
5149
5150
5151
5152
5153
5154
5155
5156
5157
5158
5159
5160
5161
5162
5163
5164
  /*
   * Issue the over-the-wire RPC DESTROY_SESSION.
   * The caller must serialize access to this routine.
   */
  int nfs4_proc_destroy_session(struct nfs4_session *session)
  {
  	int status = 0;
  	struct rpc_message msg;
  
  	dprintk("--> nfs4_proc_destroy_session
  ");
  
  	/* session is still being setup */
  	if (session->clp->cl_cons_state != NFS_CS_READY)
  		return status;
  
  	msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DESTROY_SESSION];
  	msg.rpc_argp = session;
  	msg.rpc_resp = NULL;
  	msg.rpc_cred = NULL;
1bd714f2a   Trond Myklebust   NFSv4: Ensure tha...
5165
  	status = rpc_call_sync(session->clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
0f3e66c6a   Andy Adamson   nfs41: destroy_se...
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
  
  	if (status)
  		printk(KERN_WARNING
  			"Got error %d from the server on DESTROY_SESSION. "
  			"Session has been destroyed regardless...
  ", status);
  
  	dprintk("<-- nfs4_proc_destroy_session
  ");
  	return status;
  }
fccba8045   Trond Myklebust   NFSv4: Fix an NFS...
5177
5178
5179
  int nfs4_init_session(struct nfs_server *server)
  {
  	struct nfs_client *clp = server->nfs_client;
2449ea2e1   Alexandros Batsakis   nfs41: V2 adjust ...
5180
  	struct nfs4_session *session;
68bf05efb   Andy Adamson   nfs41: fix sessio...
5181
  	unsigned int rsize, wsize;
fccba8045   Trond Myklebust   NFSv4: Fix an NFS...
5182
5183
5184
5185
  	int ret;
  
  	if (!nfs4_has_session(clp))
  		return 0;
1055d76d9   Trond Myklebust   NFSv4.1: There is...
5186
5187
5188
  	session = clp->cl_session;
  	if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state))
  		return 0;
68bf05efb   Andy Adamson   nfs41: fix sessio...
5189
5190
5191
5192
5193
5194
  	rsize = server->rsize;
  	if (rsize == 0)
  		rsize = NFS_MAX_FILE_IO_SIZE;
  	wsize = server->wsize;
  	if (wsize == 0)
  		wsize = NFS_MAX_FILE_IO_SIZE;
68bf05efb   Andy Adamson   nfs41: fix sessio...
5195
5196
  	session->fc_attrs.max_rqst_sz = wsize + nfs41_maxwrite_overhead;
  	session->fc_attrs.max_resp_sz = rsize + nfs41_maxread_overhead;
2449ea2e1   Alexandros Batsakis   nfs41: V2 adjust ...
5197

fccba8045   Trond Myklebust   NFSv4: Fix an NFS...
5198
5199
5200
5201
5202
  	ret = nfs4_recover_expired_lease(server);
  	if (!ret)
  		ret = nfs4_check_client_ready(clp);
  	return ret;
  }
d83217c13   Andy Adamson   NFSv4.1: data ser...
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
  int nfs4_init_ds_session(struct nfs_client *clp)
  {
  	struct nfs4_session *session = clp->cl_session;
  	int ret;
  
  	if (!test_and_clear_bit(NFS4_SESSION_INITING, &session->session_state))
  		return 0;
  
  	ret = nfs4_client_recover_expired_lease(clp);
  	if (!ret)
  		/* Test for the DS role */
  		if (!is_ds_client(clp))
  			ret = -ENODEV;
  	if (!ret)
  		ret = nfs4_check_client_ready(clp);
  	return ret;
  
  }
  EXPORT_SYMBOL_GPL(nfs4_init_ds_session);
fc01cea96   Andy Adamson   nfs41: sequence o...
5222
5223
5224
  /*
   * Renew the cl_session lease.
   */
d5f8d3fe7   Trond Myklebust   NFSv41: Fix a mem...
5225
5226
5227
5228
5229
  struct nfs4_sequence_data {
  	struct nfs_client *clp;
  	struct nfs4_sequence_args args;
  	struct nfs4_sequence_res res;
  };
dc96aef96   Alexandros Batsakis   nfs: prevent back...
5230
5231
  static void nfs41_sequence_release(void *data)
  {
d5f8d3fe7   Trond Myklebust   NFSv41: Fix a mem...
5232
5233
  	struct nfs4_sequence_data *calldata = data;
  	struct nfs_client *clp = calldata->clp;
dc96aef96   Alexandros Batsakis   nfs: prevent back...
5234

7135840fc   Alexandros Batsakis   nfs41: renewd seq...
5235
5236
5237
  	if (atomic_read(&clp->cl_count) > 1)
  		nfs4_schedule_state_renewal(clp);
  	nfs_put_client(clp);
d5f8d3fe7   Trond Myklebust   NFSv41: Fix a mem...
5238
  	kfree(calldata);
dc96aef96   Alexandros Batsakis   nfs: prevent back...
5239
  }
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
5240
5241
5242
5243
  static int nfs41_sequence_handle_errors(struct rpc_task *task, struct nfs_client *clp)
  {
  	switch(task->tk_status) {
  	case -NFS4ERR_DELAY:
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
5244
5245
5246
  		rpc_delay(task, NFS4_POLL_RETRY_MAX);
  		return -EAGAIN;
  	default:
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
5247
  		nfs4_schedule_lease_recovery(clp);
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
5248
5249
5250
  	}
  	return 0;
  }
dc96aef96   Alexandros Batsakis   nfs: prevent back...
5251
  static void nfs41_sequence_call_done(struct rpc_task *task, void *data)
fc01cea96   Andy Adamson   nfs41: sequence o...
5252
  {
d5f8d3fe7   Trond Myklebust   NFSv41: Fix a mem...
5253
5254
  	struct nfs4_sequence_data *calldata = data;
  	struct nfs_client *clp = calldata->clp;
fc01cea96   Andy Adamson   nfs41: sequence o...
5255

14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
5256
5257
  	if (!nfs41_sequence_done(task, task->tk_msg.rpc_resp))
  		return;
fc01cea96   Andy Adamson   nfs41: sequence o...
5258
5259
5260
5261
  
  	if (task->tk_status < 0) {
  		dprintk("%s ERROR %d
  ", __func__, task->tk_status);
7135840fc   Alexandros Batsakis   nfs41: renewd seq...
5262
5263
  		if (atomic_read(&clp->cl_count) == 1)
  			goto out;
fc01cea96   Andy Adamson   nfs41: sequence o...
5264

aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
5265
5266
  		if (nfs41_sequence_handle_errors(task, clp) == -EAGAIN) {
  			rpc_restart_call_prepare(task);
fc01cea96   Andy Adamson   nfs41: sequence o...
5267
5268
5269
  			return;
  		}
  	}
fc01cea96   Andy Adamson   nfs41: sequence o...
5270
5271
  	dprintk("%s rpc_cred %p
  ", __func__, task->tk_msg.rpc_cred);
7135840fc   Alexandros Batsakis   nfs41: renewd seq...
5272
  out:
fc01cea96   Andy Adamson   nfs41: sequence o...
5273
5274
5275
5276
5277
5278
  	dprintk("<-- %s
  ", __func__);
  }
  
  static void nfs41_sequence_prepare(struct rpc_task *task, void *data)
  {
d5f8d3fe7   Trond Myklebust   NFSv41: Fix a mem...
5279
5280
  	struct nfs4_sequence_data *calldata = data;
  	struct nfs_client *clp = calldata->clp;
fc01cea96   Andy Adamson   nfs41: sequence o...
5281
5282
  	struct nfs4_sequence_args *args;
  	struct nfs4_sequence_res *res;
fc01cea96   Andy Adamson   nfs41: sequence o...
5283
5284
  	args = task->tk_msg.rpc_argp;
  	res = task->tk_msg.rpc_resp;
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
5285
  	if (nfs41_setup_sequence(clp->cl_session, args, res, 0, task))
fc01cea96   Andy Adamson   nfs41: sequence o...
5286
5287
5288
5289
5290
5291
5292
  		return;
  	rpc_call_start(task);
  }
  
  static const struct rpc_call_ops nfs41_sequence_ops = {
  	.rpc_call_done = nfs41_sequence_call_done,
  	.rpc_call_prepare = nfs41_sequence_prepare,
dc96aef96   Alexandros Batsakis   nfs: prevent back...
5293
  	.rpc_release = nfs41_sequence_release,
fc01cea96   Andy Adamson   nfs41: sequence o...
5294
  };
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5295
  static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
fc01cea96   Andy Adamson   nfs41: sequence o...
5296
  {
d5f8d3fe7   Trond Myklebust   NFSv41: Fix a mem...
5297
  	struct nfs4_sequence_data *calldata;
fc01cea96   Andy Adamson   nfs41: sequence o...
5298
5299
5300
5301
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SEQUENCE],
  		.rpc_cred = cred,
  	};
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5302
5303
5304
5305
5306
5307
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = clp->cl_rpcclient,
  		.rpc_message = &msg,
  		.callback_ops = &nfs41_sequence_ops,
  		.flags = RPC_TASK_ASYNC | RPC_TASK_SOFT,
  	};
fc01cea96   Andy Adamson   nfs41: sequence o...
5308

7135840fc   Alexandros Batsakis   nfs41: renewd seq...
5309
  	if (!atomic_inc_not_zero(&clp->cl_count))
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5310
  		return ERR_PTR(-EIO);
dfb4f3098   Benny Halevy   NFSv4.1: keep seq...
5311
  	calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
d5f8d3fe7   Trond Myklebust   NFSv41: Fix a mem...
5312
  	if (calldata == NULL) {
7135840fc   Alexandros Batsakis   nfs41: renewd seq...
5313
  		nfs_put_client(clp);
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5314
  		return ERR_PTR(-ENOMEM);
fc01cea96   Andy Adamson   nfs41: sequence o...
5315
  	}
d5f8d3fe7   Trond Myklebust   NFSv41: Fix a mem...
5316
5317
5318
  	msg.rpc_argp = &calldata->args;
  	msg.rpc_resp = &calldata->res;
  	calldata->clp = clp;
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5319
  	task_setup_data.callback_data = calldata;
fc01cea96   Andy Adamson   nfs41: sequence o...
5320

71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5321
5322
  	return rpc_run_task(&task_setup_data);
  }
2f60ea6b8   Trond Myklebust   NFSv4: The NFSv4....
5323
  static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags)
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5324
5325
5326
  {
  	struct rpc_task *task;
  	int ret = 0;
2f60ea6b8   Trond Myklebust   NFSv4: The NFSv4....
5327
5328
  	if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
  		return 0;
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5329
5330
5331
5332
  	task = _nfs41_proc_sequence(clp, cred);
  	if (IS_ERR(task))
  		ret = PTR_ERR(task);
  	else
bf294b41c   Trond Myklebust   SUNRPC: Close a r...
5333
  		rpc_put_task_async(task);
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5334
5335
5336
5337
5338
5339
5340
5341
5342
5343
5344
5345
5346
5347
5348
5349
  	dprintk("<-- %s status=%d
  ", __func__, ret);
  	return ret;
  }
  
  static int nfs4_proc_sequence(struct nfs_client *clp, struct rpc_cred *cred)
  {
  	struct rpc_task *task;
  	int ret;
  
  	task = _nfs41_proc_sequence(clp, cred);
  	if (IS_ERR(task)) {
  		ret = PTR_ERR(task);
  		goto out;
  	}
  	ret = rpc_wait_for_completion_task(task);
b4410c2f7   Trond Myklebust   NFSv4.1: Fix the ...
5350
5351
5352
5353
5354
  	if (!ret) {
  		struct nfs4_sequence_res *res = task->tk_msg.rpc_resp;
  
  		if (task->tk_status == 0)
  			nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5355
  		ret = task->tk_status;
b4410c2f7   Trond Myklebust   NFSv4.1: Fix the ...
5356
  	}
71ac6da99   Trond Myklebust   NFSv4.1: Merge th...
5357
5358
5359
5360
5361
  	rpc_put_task(task);
  out:
  	dprintk("<-- %s status=%d
  ", __func__, ret);
  	return ret;
fc01cea96   Andy Adamson   nfs41: sequence o...
5362
  }
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5363
5364
5365
5366
5367
5368
5369
5370
5371
  struct nfs4_reclaim_complete_data {
  	struct nfs_client *clp;
  	struct nfs41_reclaim_complete_args arg;
  	struct nfs41_reclaim_complete_res res;
  };
  
  static void nfs4_reclaim_complete_prepare(struct rpc_task *task, void *data)
  {
  	struct nfs4_reclaim_complete_data *calldata = data;
b257957e5   Alexandros Batsakis   nfs: make recover...
5372
  	rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
035168ab3   Trond Myklebust   NFSv4.1: Make nfs...
5373
5374
  	if (nfs41_setup_sequence(calldata->clp->cl_session,
  				&calldata->arg.seq_args,
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5375
5376
5377
5378
5379
  				&calldata->res.seq_res, 0, task))
  		return;
  
  	rpc_call_start(task);
  }
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
5380
5381
5382
5383
5384
5385
5386
5387
  static int nfs41_reclaim_complete_handle_errors(struct rpc_task *task, struct nfs_client *clp)
  {
  	switch(task->tk_status) {
  	case 0:
  	case -NFS4ERR_COMPLETE_ALREADY:
  	case -NFS4ERR_WRONG_CRED: /* What to do here? */
  		break;
  	case -NFS4ERR_DELAY:
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
5388
  		rpc_delay(task, NFS4_POLL_RETRY_MAX);
a8a4ae3a8   Andy Adamson   NFSv41: Resend on...
5389
5390
  		/* fall through */
  	case -NFS4ERR_RETRY_UNCACHED_REP:
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
5391
5392
  		return -EAGAIN;
  	default:
0400a6b0c   Trond Myklebust   NFSv4/4.1: Fix nf...
5393
  		nfs4_schedule_lease_recovery(clp);
aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
5394
5395
5396
  	}
  	return 0;
  }
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5397
5398
5399
5400
5401
5402
5403
5404
  static void nfs4_reclaim_complete_done(struct rpc_task *task, void *data)
  {
  	struct nfs4_reclaim_complete_data *calldata = data;
  	struct nfs_client *clp = calldata->clp;
  	struct nfs4_sequence_res *res = &calldata->res.seq_res;
  
  	dprintk("--> %s
  ", __func__);
14516c3a3   Trond Myklebust   NFSv4.1: Handle N...
5405
5406
  	if (!nfs41_sequence_done(task, res))
  		return;
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5407

aa5190d0e   Trond Myklebust   NFSv4: Kill nfs4_...
5408
5409
5410
5411
  	if (nfs41_reclaim_complete_handle_errors(task, clp) == -EAGAIN) {
  		rpc_restart_call_prepare(task);
  		return;
  	}
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
5439
5440
5441
5442
5443
5444
5445
5446
5447
5448
  	dprintk("<-- %s
  ", __func__);
  }
  
  static void nfs4_free_reclaim_complete_data(void *data)
  {
  	struct nfs4_reclaim_complete_data *calldata = data;
  
  	kfree(calldata);
  }
  
  static const struct rpc_call_ops nfs4_reclaim_complete_call_ops = {
  	.rpc_call_prepare = nfs4_reclaim_complete_prepare,
  	.rpc_call_done = nfs4_reclaim_complete_done,
  	.rpc_release = nfs4_free_reclaim_complete_data,
  };
  
  /*
   * Issue a global reclaim complete.
   */
  static int nfs41_proc_reclaim_complete(struct nfs_client *clp)
  {
  	struct nfs4_reclaim_complete_data *calldata;
  	struct rpc_task *task;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RECLAIM_COMPLETE],
  	};
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = clp->cl_rpcclient,
  		.rpc_message = &msg,
  		.callback_ops = &nfs4_reclaim_complete_call_ops,
  		.flags = RPC_TASK_ASYNC,
  	};
  	int status = -ENOMEM;
  
  	dprintk("--> %s
  ", __func__);
8535b2be5   Trond Myklebust   NFSv4: Don't use ...
5449
  	calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5450
5451
5452
5453
  	if (calldata == NULL)
  		goto out;
  	calldata->clp = clp;
  	calldata->arg.one_fs = 0;
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5454
5455
5456
5457
5458
  
  	msg.rpc_argp = &calldata->arg;
  	msg.rpc_resp = &calldata->res;
  	task_setup_data.callback_data = calldata;
  	task = rpc_run_task(&task_setup_data);
acf82b85a   Dan Carpenter   nfs: fix some iss...
5459
  	if (IS_ERR(task)) {
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5460
  		status = PTR_ERR(task);
acf82b85a   Dan Carpenter   nfs: fix some iss...
5461
5462
  		goto out;
  	}
c34c32ea9   Andy Adamson   NFSv4.1 reclaim c...
5463
5464
5465
  	status = nfs4_wait_for_completion_rpc_task(task);
  	if (status == 0)
  		status = task->tk_status;
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5466
  	rpc_put_task(task);
acf82b85a   Dan Carpenter   nfs: fix some iss...
5467
  	return 0;
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
5468
5469
5470
5471
5472
  out:
  	dprintk("<-- %s status=%d
  ", __func__, status);
  	return status;
  }
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5473
5474
5475
5476
5477
  
  static void
  nfs4_layoutget_prepare(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_layoutget *lgp = calldata;
c31663d4a   Fred Isaman   pnfs: layoutget r...
5478
  	struct nfs_server *server = NFS_SERVER(lgp->args.inode);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5479
5480
5481
  
  	dprintk("--> %s
  ", __func__);
c31663d4a   Fred Isaman   pnfs: layoutget r...
5482
5483
5484
5485
5486
  	/* Note the is a race here, where a CB_LAYOUTRECALL can come in
  	 * right now covering the LAYOUTGET we are about to send.
  	 * However, that is not so catastrophic, and there seems
  	 * to be no way to prevent it completely.
  	 */
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5487
5488
5489
  	if (nfs4_setup_sequence(server, &lgp->args.seq_args,
  				&lgp->res.seq_res, 0, task))
  		return;
cf7d63f1f   Fred Isaman   pnfs: serialize L...
5490
5491
5492
5493
5494
5495
  	if (pnfs_choose_layoutget_stateid(&lgp->args.stateid,
  					  NFS_I(lgp->args.inode)->layout,
  					  lgp->args.ctx->state)) {
  		rpc_exit(task, NFS4_OK);
  		return;
  	}
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5496
5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
5519
5520
5521
5522
  	rpc_call_start(task);
  }
  
  static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_layoutget *lgp = calldata;
  	struct nfs_server *server = NFS_SERVER(lgp->args.inode);
  
  	dprintk("--> %s
  ", __func__);
  
  	if (!nfs4_sequence_done(task, &lgp->res.seq_res))
  		return;
  
  	switch (task->tk_status) {
  	case 0:
  		break;
  	case -NFS4ERR_LAYOUTTRYLATER:
  	case -NFS4ERR_RECALLCONFLICT:
  		task->tk_status = -NFS4ERR_DELAY;
  		/* Fall through */
  	default:
  		if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
  			rpc_restart_call_prepare(task);
  			return;
  		}
  	}
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5523
5524
5525
5526
5527
5528
5529
5530
5531
5532
  	dprintk("<-- %s
  ", __func__);
  }
  
  static void nfs4_layoutget_release(void *calldata)
  {
  	struct nfs4_layoutget *lgp = calldata;
  
  	dprintk("--> %s
  ", __func__);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
  	put_nfs_open_context(lgp->args.ctx);
  	kfree(calldata);
  	dprintk("<-- %s
  ", __func__);
  }
  
  static const struct rpc_call_ops nfs4_layoutget_call_ops = {
  	.rpc_call_prepare = nfs4_layoutget_prepare,
  	.rpc_call_done = nfs4_layoutget_done,
  	.rpc_release = nfs4_layoutget_release,
  };
  
  int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
  {
  	struct nfs_server *server = NFS_SERVER(lgp->args.inode);
  	struct rpc_task *task;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
  		.rpc_argp = &lgp->args,
  		.rpc_resp = &lgp->res,
  	};
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = server->client,
  		.rpc_message = &msg,
  		.callback_ops = &nfs4_layoutget_call_ops,
  		.callback_data = lgp,
  		.flags = RPC_TASK_ASYNC,
  	};
  	int status = 0;
  
  	dprintk("--> %s
  ", __func__);
35124a099   Weston Andros Adamson   Cleanup XDR parsi...
5565
  	lgp->res.layoutp = &lgp->args.layout;
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5566
5567
5568
5569
5570
  	lgp->res.seq_res.sr_slot = NULL;
  	task = rpc_run_task(&task_setup_data);
  	if (IS_ERR(task))
  		return PTR_ERR(task);
  	status = nfs4_wait_for_completion_rpc_task(task);
c31663d4a   Fred Isaman   pnfs: layoutget r...
5571
5572
5573
5574
  	if (status == 0)
  		status = task->tk_status;
  	if (status == 0)
  		status = pnfs_layout_process(lgp);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5575
5576
5577
5578
5579
  	rpc_put_task(task);
  	dprintk("<-- %s status=%d
  ", __func__, status);
  	return status;
  }
cbe826036   Benny Halevy   pnfs: layoutreturn
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
  static void
  nfs4_layoutreturn_prepare(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_layoutreturn *lrp = calldata;
  
  	dprintk("--> %s
  ", __func__);
  	if (nfs41_setup_sequence(lrp->clp->cl_session, &lrp->args.seq_args,
  				&lrp->res.seq_res, 0, task))
  		return;
  	rpc_call_start(task);
  }
  
  static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_layoutreturn *lrp = calldata;
  	struct nfs_server *server;
a56aaa02b   Trond Myklebust   NFSv4.1: Clean up...
5597
  	struct pnfs_layout_hdr *lo = lrp->args.layout;
cbe826036   Benny Halevy   pnfs: layoutreturn
5598
5599
5600
5601
5602
5603
5604
5605
5606
  
  	dprintk("--> %s
  ", __func__);
  
  	if (!nfs4_sequence_done(task, &lrp->res.seq_res))
  		return;
  
  	server = NFS_SERVER(lrp->args.inode);
  	if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
d00c5d438   Trond Myklebust   NFS: Get rid of n...
5607
  		rpc_restart_call_prepare(task);
cbe826036   Benny Halevy   pnfs: layoutreturn
5608
5609
  		return;
  	}
a2e1d4f2e   Fred Isaman   nfs4.1: fix sever...
5610
  	spin_lock(&lo->plh_inode->i_lock);
cbe826036   Benny Halevy   pnfs: layoutreturn
5611
  	if (task->tk_status == 0) {
cbe826036   Benny Halevy   pnfs: layoutreturn
5612
  		if (lrp->res.lrs_present) {
cbe826036   Benny Halevy   pnfs: layoutreturn
5613
  			pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
cbe826036   Benny Halevy   pnfs: layoutreturn
5614
5615
5616
  		} else
  			BUG_ON(!list_empty(&lo->plh_segs));
  	}
a2e1d4f2e   Fred Isaman   nfs4.1: fix sever...
5617
5618
  	lo->plh_block_lgets--;
  	spin_unlock(&lo->plh_inode->i_lock);
cbe826036   Benny Halevy   pnfs: layoutreturn
5619
5620
5621
5622
5623
5624
5625
5626
5627
5628
  	dprintk("<-- %s
  ", __func__);
  }
  
  static void nfs4_layoutreturn_release(void *calldata)
  {
  	struct nfs4_layoutreturn *lrp = calldata;
  
  	dprintk("--> %s
  ", __func__);
a56aaa02b   Trond Myklebust   NFSv4.1: Clean up...
5629
  	put_layout_hdr(lrp->args.layout);
cbe826036   Benny Halevy   pnfs: layoutreturn
5630
5631
5632
5633
5634
5635
5636
5637
5638
5639
5640
5641
5642
5643
5644
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
  	kfree(calldata);
  	dprintk("<-- %s
  ", __func__);
  }
  
  static const struct rpc_call_ops nfs4_layoutreturn_call_ops = {
  	.rpc_call_prepare = nfs4_layoutreturn_prepare,
  	.rpc_call_done = nfs4_layoutreturn_done,
  	.rpc_release = nfs4_layoutreturn_release,
  };
  
  int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp)
  {
  	struct rpc_task *task;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTRETURN],
  		.rpc_argp = &lrp->args,
  		.rpc_resp = &lrp->res,
  	};
  	struct rpc_task_setup task_setup_data = {
  		.rpc_client = lrp->clp->cl_rpcclient,
  		.rpc_message = &msg,
  		.callback_ops = &nfs4_layoutreturn_call_ops,
  		.callback_data = lrp,
  	};
  	int status;
  
  	dprintk("--> %s
  ", __func__);
  	task = rpc_run_task(&task_setup_data);
  	if (IS_ERR(task))
  		return PTR_ERR(task);
  	status = task->tk_status;
  	dprintk("<-- %s status=%d
  ", __func__, status);
  	rpc_put_task(task);
  	return status;
  }
7f11d8d38   Andy Adamson   pnfs: GETDEVICELIST
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
  /*
   * Retrieve the list of Data Server devices from the MDS.
   */
  static int _nfs4_getdevicelist(struct nfs_server *server,
  				    const struct nfs_fh *fh,
  				    struct pnfs_devicelist *devlist)
  {
  	struct nfs4_getdevicelist_args args = {
  		.fh = fh,
  		.layoutclass = server->pnfs_curr_ld->id,
  	};
  	struct nfs4_getdevicelist_res res = {
  		.devlist = devlist,
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICELIST],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  	int status;
  
  	dprintk("--> %s
  ", __func__);
  	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args,
  				&res.seq_res, 0);
  	dprintk("<-- %s status=%d
  ", __func__, status);
  	return status;
  }
  
  int nfs4_proc_getdevicelist(struct nfs_server *server,
  			    const struct nfs_fh *fh,
  			    struct pnfs_devicelist *devlist)
  {
  	struct nfs4_exception exception = { };
  	int err;
  
  	do {
  		err = nfs4_handle_exception(server,
  				_nfs4_getdevicelist(server, fh, devlist),
  				&exception);
  	} while (exception.retry);
  
  	dprintk("%s: err=%d, num_devs=%u
  ", __func__,
  		err, devlist->num_devs);
  
  	return err;
  }
  EXPORT_SYMBOL_GPL(nfs4_proc_getdevicelist);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
  static int
  _nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
  {
  	struct nfs4_getdeviceinfo_args args = {
  		.pdev = pdev,
  	};
  	struct nfs4_getdeviceinfo_res res = {
  		.pdev = pdev,
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETDEVICEINFO],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  	int status;
  
  	dprintk("--> %s
  ", __func__);
7c5130588   Bryan Schumaker   NFS: lookup suppo...
5736
  	status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
b1f69b754   Andy Adamson   NFSv4.1: pnfs: ad...
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
  	dprintk("<-- %s status=%d
  ", __func__, status);
  
  	return status;
  }
  
  int nfs4_proc_getdeviceinfo(struct nfs_server *server, struct pnfs_device *pdev)
  {
  	struct nfs4_exception exception = { };
  	int err;
  
  	do {
  		err = nfs4_handle_exception(server,
  					_nfs4_proc_getdeviceinfo(server, pdev),
  					&exception);
  	} while (exception.retry);
  	return err;
  }
  EXPORT_SYMBOL_GPL(nfs4_proc_getdeviceinfo);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
5784
  static void nfs4_layoutcommit_prepare(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_layoutcommit_data *data = calldata;
  	struct nfs_server *server = NFS_SERVER(data->args.inode);
  
  	if (nfs4_setup_sequence(server, &data->args.seq_args,
  				&data->res.seq_res, 1, task))
  		return;
  	rpc_call_start(task);
  }
  
  static void
  nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
  {
  	struct nfs4_layoutcommit_data *data = calldata;
  	struct nfs_server *server = NFS_SERVER(data->args.inode);
  
  	if (!nfs4_sequence_done(task, &data->res.seq_res))
  		return;
  
  	switch (task->tk_status) { /* Just ignore these failures */
  	case NFS4ERR_DELEG_REVOKED: /* layout was recalled */
  	case NFS4ERR_BADIOMODE:     /* no IOMODE_RW layout for range */
  	case NFS4ERR_BADLAYOUT:     /* no layout */
  	case NFS4ERR_GRACE:	    /* loca_recalim always false */
  		task->tk_status = 0;
  	}
  
  	if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
d00c5d438   Trond Myklebust   NFS: Get rid of n...
5785
  		rpc_restart_call_prepare(task);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795
5796
  		return;
  	}
  
  	if (task->tk_status == 0)
  		nfs_post_op_update_inode_force_wcc(data->args.inode,
  						   data->res.fattr);
  }
  
  static void nfs4_layoutcommit_release(void *calldata)
  {
  	struct nfs4_layoutcommit_data *data = calldata;
a9bae5666   Peng Tao   pnfs: let layoutc...
5797
  	struct pnfs_layout_segment *lseg, *tmp;
92407e75c   Peng Tao   nfs4: serialize l...
5798
  	unsigned long *bitlock = &NFS_I(data->args.inode)->flags;
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
5799

db29c0890   Andy Adamson   pnfs: cleanup_lay...
5800
  	pnfs_cleanup_layoutcommit(data);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
5801
  	/* Matched by references in pnfs_set_layoutcommit */
a9bae5666   Peng Tao   pnfs: let layoutc...
5802
5803
5804
5805
5806
5807
  	list_for_each_entry_safe(lseg, tmp, &data->lseg_list, pls_lc_list) {
  		list_del_init(&lseg->pls_lc_list);
  		if (test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT,
  				       &lseg->pls_flags))
  			put_lseg(lseg);
  	}
92407e75c   Peng Tao   nfs4: serialize l...
5808
5809
5810
5811
  
  	clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
  	smp_mb__after_clear_bit();
  	wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
  	put_rpccred(data->cred);
  	kfree(data);
  }
  
  static const struct rpc_call_ops nfs4_layoutcommit_ops = {
  	.rpc_call_prepare = nfs4_layoutcommit_prepare,
  	.rpc_call_done = nfs4_layoutcommit_done,
  	.rpc_release = nfs4_layoutcommit_release,
  };
  
  int
ef3115378   Andy Adamson   NFSv4.1 convert l...
5823
  nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync)
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
  {
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTCOMMIT],
  		.rpc_argp = &data->args,
  		.rpc_resp = &data->res,
  		.rpc_cred = data->cred,
  	};
  	struct rpc_task_setup task_setup_data = {
  		.task = &data->task,
  		.rpc_client = NFS_CLIENT(data->args.inode),
  		.rpc_message = &msg,
  		.callback_ops = &nfs4_layoutcommit_ops,
  		.callback_data = data,
  		.flags = RPC_TASK_ASYNC,
  	};
  	struct rpc_task *task;
  	int status = 0;
  
  	dprintk("NFS: %4d initiating layoutcommit call. sync %d "
  		"lbw: %llu inode %lu
  ",
  		data->task.tk_pid, sync,
  		data->args.lastbytewritten,
  		data->args.inode->i_ino);
  
  	task = rpc_run_task(&task_setup_data);
  	if (IS_ERR(task))
  		return PTR_ERR(task);
ef3115378   Andy Adamson   NFSv4.1 convert l...
5852
  	if (sync == false)
863a3c6c6   Andy Adamson   NFSv4.1: layoutco...
5853
5854
5855
5856
5857
5858
5859
5860
5861
5862
5863
  		goto out;
  	status = nfs4_wait_for_completion_rpc_task(task);
  	if (status != 0)
  		goto out;
  	status = task->tk_status;
  out:
  	dprintk("%s: status %d
  ", __func__, status);
  	rpc_put_task(task);
  	return status;
  }
fca78d6d2   Bryan Schumaker   NFS: Add SECINFO_...
5864
5865
5866
5867
5868
5869
5870
5871
5872
5873
5874
5875
5876
5877
5878
5879
5880
5881
5882
5883
5884
5885
5886
5887
5888
5889
5890
5891
5892
5893
5894
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907
5908
5909
5910
5911
5912
5913
5914
5915
5916
5917
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
5931
5932
5933
5934
5935
5936
5937
5938
5939
5940
5941
5942
  
  static int
  _nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
  		    struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
  {
  	struct nfs41_secinfo_no_name_args args = {
  		.style = SECINFO_STYLE_CURRENT_FH,
  	};
  	struct nfs4_secinfo_res res = {
  		.flavors = flavors,
  	};
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO_NO_NAME],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  	return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
  }
  
  static int
  nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
  			   struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
  		switch (err) {
  		case 0:
  		case -NFS4ERR_WRONGSEC:
  		case -NFS4ERR_NOTSUPP:
  			break;
  		default:
  			err = nfs4_handle_exception(server, err, &exception);
  		}
  	} while (exception.retry);
  	return err;
  }
  
  static int
  nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
  		    struct nfs_fsinfo *info)
  {
  	int err;
  	struct page *page;
  	rpc_authflavor_t flavor;
  	struct nfs4_secinfo_flavors *flavors;
  
  	page = alloc_page(GFP_KERNEL);
  	if (!page) {
  		err = -ENOMEM;
  		goto out;
  	}
  
  	flavors = page_address(page);
  	err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors);
  
  	/*
  	 * Fall back on "guess and check" method if
  	 * the server doesn't support SECINFO_NO_NAME
  	 */
  	if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) {
  		err = nfs4_find_root_sec(server, fhandle, info);
  		goto out_freepage;
  	}
  	if (err)
  		goto out_freepage;
  
  	flavor = nfs_find_best_sec(flavors);
  	if (err == 0)
  		err = nfs4_lookup_root_sec(server, fhandle, info, flavor);
  
  out_freepage:
  	put_page(page);
  	if (err == -EACCES)
  		return -EPERM;
  out:
  	return err;
  }
7d9747947   Bryan Schumaker   NFS: Added TEST_S...
5943
5944
5945
5946
5947
5948
5949
5950
5951
5952
5953
5954
5955
5956
5957
5958
5959
5960
5961
5962
5963
5964
5965
5966
5967
5968
5969
5970
  static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
  {
  	int status;
  	struct nfs41_test_stateid_args args = {
  		.stateid = &state->stateid,
  	};
  	struct nfs41_test_stateid_res res;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  	args.seq_args.sa_session = res.seq_res.sr_session = NULL;
  	status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
  	return status;
  }
  
  static int nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(server,
  				_nfs41_test_stateid(server, state),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
9aeda35fd   Bryan Schumaker   NFS: added FREE_S...
5971
5972
5973
5974
5975
5976
5977
5978
5979
5980
5981
5982
5983
5984
5985
5986
5987
5988
5989
5990
5991
5992
5993
5994
5995
5996
5997
5998
5999
6000
  
  static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *state)
  {
  	int status;
  	struct nfs41_free_stateid_args args = {
  		.stateid = &state->stateid,
  	};
  	struct nfs41_free_stateid_res res;
  	struct rpc_message msg = {
  		.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID],
  		.rpc_argp = &args,
  		.rpc_resp = &res,
  	};
  
  	args.seq_args.sa_session = res.seq_res.sr_session = NULL;
  	status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1);
  	return status;
  }
  
  static int nfs41_free_stateid(struct nfs_server *server, struct nfs4_state *state)
  {
  	struct nfs4_exception exception = { };
  	int err;
  	do {
  		err = nfs4_handle_exception(server,
  				_nfs4_free_stateid(server, state),
  				&exception);
  	} while (exception.retry);
  	return err;
  }
557134a39   Andy Adamson   nfs41: sessions c...
6001
  #endif /* CONFIG_NFS_V4_1 */
591d71cbd   Andy Adamson   nfs41: establish ...
6002
  struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
6003
  	.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
6004
  	.state_flag_bit	= NFS_STATE_RECLAIM_REBOOT,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6005
6006
  	.recover_open	= nfs4_open_reclaim,
  	.recover_lock	= nfs4_lock_reclaim,
591d71cbd   Andy Adamson   nfs41: establish ...
6007
  	.establish_clid = nfs4_init_clientid,
90a16617e   Andy Adamson   nfs41: add a get_...
6008
  	.get_clid_cred	= nfs4_get_setclientid_cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6009
  };
591d71cbd   Andy Adamson   nfs41: establish ...
6010
6011
6012
6013
6014
6015
  #if defined(CONFIG_NFS_V4_1)
  struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
  	.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
  	.state_flag_bit	= NFS_STATE_RECLAIM_REBOOT,
  	.recover_open	= nfs4_open_reclaim,
  	.recover_lock	= nfs4_lock_reclaim,
4d643d1df   Andy Adamson   nfs41: add create...
6016
  	.establish_clid = nfs41_init_clientid,
b4b82607f   Andy Adamson   nfs41: get_clid_c...
6017
  	.get_clid_cred	= nfs4_get_exchange_id_cred,
fce5c838e   Ricardo Labiaga   nfs41: RECLAIM_CO...
6018
  	.reclaim_complete = nfs41_proc_reclaim_complete,
591d71cbd   Andy Adamson   nfs41: establish ...
6019
6020
6021
6022
6023
6024
6025
6026
6027
  };
  #endif /* CONFIG_NFS_V4_1 */
  
  struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
  	.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
  	.state_flag_bit	= NFS_STATE_RECLAIM_NOGRACE,
  	.recover_open	= nfs4_open_expired,
  	.recover_lock	= nfs4_lock_expired,
  	.establish_clid = nfs4_init_clientid,
90a16617e   Andy Adamson   nfs41: add a get_...
6028
  	.get_clid_cred	= nfs4_get_setclientid_cred,
591d71cbd   Andy Adamson   nfs41: establish ...
6029
6030
6031
6032
  };
  
  #if defined(CONFIG_NFS_V4_1)
  struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
7eff03aec   Trond Myklebust   NFSv4: Add a reco...
6033
  	.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
b79a4a1b4   Trond Myklebust   NFSv4: Fix state ...
6034
  	.state_flag_bit	= NFS_STATE_RECLAIM_NOGRACE,
f062eb6ce   Bryan Schumaker   NFS: test and fre...
6035
6036
  	.recover_open	= nfs41_open_expired,
  	.recover_lock	= nfs41_lock_expired,
4d643d1df   Andy Adamson   nfs41: add create...
6037
  	.establish_clid = nfs41_init_clientid,
b4b82607f   Andy Adamson   nfs41: get_clid_c...
6038
  	.get_clid_cred	= nfs4_get_exchange_id_cred,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6039
  };
591d71cbd   Andy Adamson   nfs41: establish ...
6040
  #endif /* CONFIG_NFS_V4_1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6041

29fba38b7   Benny Halevy   nfs41: lease renewal
6042
6043
  struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
  	.sched_state_renewal = nfs4_proc_async_renew,
a7b721037   Andy Adamson   nfs41: introduce ...
6044
  	.get_state_renewal_cred_locked = nfs4_get_renew_cred_locked,
8e69514f2   Benny Halevy   nfs41: support mi...
6045
  	.renew_lease = nfs4_proc_renew,
29fba38b7   Benny Halevy   nfs41: lease renewal
6046
6047
6048
6049
6050
  };
  
  #if defined(CONFIG_NFS_V4_1)
  struct nfs4_state_maintenance_ops nfs41_state_renewal_ops = {
  	.sched_state_renewal = nfs41_proc_async_sequence,
a7b721037   Andy Adamson   nfs41: introduce ...
6051
  	.get_state_renewal_cred_locked = nfs4_get_machine_cred_locked,
8e69514f2   Benny Halevy   nfs41: support mi...
6052
  	.renew_lease = nfs4_proc_sequence,
29fba38b7   Benny Halevy   nfs41: lease renewal
6053
6054
  };
  #endif
97dc13594   Trond Myklebust   NFSv41: Clean up ...
6055
6056
6057
  static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
  	.minor_version = 0,
  	.call_sync = _nfs4_call_sync,
e047a10c1   Trond Myklebust   NFSv41: Fix nfs_a...
6058
  	.validate_stateid = nfs4_validate_delegation_stateid,
fca78d6d2   Bryan Schumaker   NFS: Add SECINFO_...
6059
  	.find_root_sec = nfs4_find_root_sec,
c48f4f354   Trond Myklebust   NFSv41: Convert t...
6060
6061
6062
  	.reboot_recovery_ops = &nfs40_reboot_recovery_ops,
  	.nograce_recovery_ops = &nfs40_nograce_recovery_ops,
  	.state_renewal_ops = &nfs40_state_renewal_ops,
97dc13594   Trond Myklebust   NFSv41: Clean up ...
6063
6064
6065
6066
6067
6068
  };
  
  #if defined(CONFIG_NFS_V4_1)
  static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
  	.minor_version = 1,
  	.call_sync = _nfs4_call_sync_session,
e047a10c1   Trond Myklebust   NFSv41: Fix nfs_a...
6069
  	.validate_stateid = nfs41_validate_delegation_stateid,
fca78d6d2   Bryan Schumaker   NFS: Add SECINFO_...
6070
  	.find_root_sec = nfs41_find_root_sec,
c48f4f354   Trond Myklebust   NFSv41: Convert t...
6071
6072
6073
  	.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
  	.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
  	.state_renewal_ops = &nfs41_state_renewal_ops,
97dc13594   Trond Myklebust   NFSv41: Clean up ...
6074
6075
  };
  #endif
97dc13594   Trond Myklebust   NFSv41: Clean up ...
6076
6077
6078
6079
6080
6081
  const struct nfs4_minor_version_ops *nfs_v4_minor_ops[] = {
  	[0] = &nfs_v4_0_minor_ops,
  #if defined(CONFIG_NFS_V4_1)
  	[1] = &nfs_v4_1_minor_ops,
  #endif
  };
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
6082
  static const struct inode_operations nfs4_file_inode_operations = {
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
6083
6084
6085
  	.permission	= nfs_permission,
  	.getattr	= nfs_getattr,
  	.setattr	= nfs_setattr,
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
6086
6087
6088
6089
  	.getxattr	= generic_getxattr,
  	.setxattr	= generic_setxattr,
  	.listxattr	= generic_listxattr,
  	.removexattr	= generic_removexattr,
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
6090
  };
509de8111   David Howells   NFS: Add extra co...
6091
  const struct nfs_rpc_ops nfs_v4_clientops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6092
6093
6094
  	.version	= 4,			/* protocol version */
  	.dentry_ops	= &nfs4_dentry_operations,
  	.dir_inode_ops	= &nfs4_dir_inode_operations,
6b3b5496d   J. Bruce Fields   [PATCH] NFSv4: Ad...
6095
  	.file_inode_ops	= &nfs4_file_inode_operations,
1788ea6e3   Jeff Layton   nfs: when attempt...
6096
  	.file_ops	= &nfs4_file_operations,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6097
6098
6099
6100
6101
6102
  	.getroot	= nfs4_proc_get_root,
  	.getattr	= nfs4_proc_getattr,
  	.setattr	= nfs4_proc_setattr,
  	.lookup		= nfs4_proc_lookup,
  	.access		= nfs4_proc_access,
  	.readlink	= nfs4_proc_readlink,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6103
6104
6105
6106
6107
  	.create		= nfs4_proc_create,
  	.remove		= nfs4_proc_remove,
  	.unlink_setup	= nfs4_proc_unlink_setup,
  	.unlink_done	= nfs4_proc_unlink_done,
  	.rename		= nfs4_proc_rename,
d3d4152a5   Jeff Layton   nfs: make sillyre...
6108
6109
  	.rename_setup	= nfs4_proc_rename_setup,
  	.rename_done	= nfs4_proc_rename_done,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6110
6111
6112
6113
6114
6115
6116
6117
6118
  	.link		= nfs4_proc_link,
  	.symlink	= nfs4_proc_symlink,
  	.mkdir		= nfs4_proc_mkdir,
  	.rmdir		= nfs4_proc_remove,
  	.readdir	= nfs4_proc_readdir,
  	.mknod		= nfs4_proc_mknod,
  	.statfs		= nfs4_proc_statfs,
  	.fsinfo		= nfs4_proc_fsinfo,
  	.pathconf	= nfs4_proc_pathconf,
e9326dcab   David Howells   NFS: Add a server...
6119
  	.set_capabilities = nfs4_server_capabilities,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6120
6121
  	.decode_dirent	= nfs4_decode_dirent,
  	.read_setup	= nfs4_proc_read_setup,
ec06c096e   Trond Myklebust   NFS: Cleanup of N...
6122
  	.read_done	= nfs4_read_done,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6123
  	.write_setup	= nfs4_proc_write_setup,
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
6124
  	.write_done	= nfs4_write_done,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6125
  	.commit_setup	= nfs4_proc_commit_setup,
788e7a89a   Trond Myklebust   NFS: Cleanup of N...
6126
  	.commit_done	= nfs4_commit_done,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6127
  	.lock		= nfs4_proc_lock,
e50a1c2e1   J. Bruce Fields   [PATCH] NFSv4: cl...
6128
  	.clear_acl_cache = nfs4_zap_acl_attr,
7fe5c398f   Trond Myklebust   NFS: Optimise NFS...
6129
  	.close_context  = nfs4_close_context,
2b484297e   Trond Myklebust   NFS: Add an 'open...
6130
  	.open_context	= nfs4_atomic_open,
45a52a020   Andy Adamson   NFS move nfs_clie...
6131
  	.init_client	= nfs4_init_client,
5a5ea0d48   Bryan Schumaker   NFS: Add secinfo ...
6132
  	.secinfo	= nfs4_proc_secinfo,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6133
  };
64c2ce8b7   Aneesh Kumar K.V   nfsv4: Switch to ...
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
  static const struct xattr_handler nfs4_xattr_nfs4_acl_handler = {
  	.prefix	= XATTR_NAME_NFSV4_ACL,
  	.list	= nfs4_xattr_list_nfs4_acl,
  	.get	= nfs4_xattr_get_nfs4_acl,
  	.set	= nfs4_xattr_set_nfs4_acl,
  };
  
  const struct xattr_handler *nfs4_xattr_handlers[] = {
  	&nfs4_xattr_nfs4_acl_handler,
  	NULL
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6145
6146
6147
6148
6149
  /*
   * Local variables:
   *  c-basic-offset: 8
   * End:
   */