diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /fs/nfsd/nfs4state.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 3944 |
1 files changed, 1763 insertions, 2181 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ac8ed96c419..6f8bcc733f7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -38,37 +38,35 @@ | |||
38 | #include <linux/namei.h> | 38 | #include <linux/namei.h> |
39 | #include <linux/swap.h> | 39 | #include <linux/swap.h> |
40 | #include <linux/pagemap.h> | 40 | #include <linux/pagemap.h> |
41 | #include <linux/ratelimit.h> | ||
42 | #include <linux/sunrpc/svcauth_gss.h> | 41 | #include <linux/sunrpc/svcauth_gss.h> |
43 | #include <linux/sunrpc/clnt.h> | 42 | #include <linux/sunrpc/clnt.h> |
44 | #include "xdr4.h" | 43 | #include "xdr4.h" |
45 | #include "vfs.h" | 44 | #include "vfs.h" |
46 | #include "current_stateid.h" | ||
47 | |||
48 | #include "netns.h" | ||
49 | 45 | ||
50 | #define NFSDDBG_FACILITY NFSDDBG_PROC | 46 | #define NFSDDBG_FACILITY NFSDDBG_PROC |
51 | 47 | ||
52 | #define all_ones {{~0,~0},~0} | 48 | /* Globals */ |
53 | static const stateid_t one_stateid = { | 49 | time_t nfsd4_lease = 90; /* default lease time */ |
54 | .si_generation = ~0, | 50 | time_t nfsd4_grace = 90; |
55 | .si_opaque = all_ones, | 51 | static time_t boot_time; |
56 | }; | 52 | static u32 current_ownerid = 1; |
57 | static const stateid_t zero_stateid = { | 53 | static u32 current_fileid = 1; |
58 | /* all fields zero */ | 54 | static u32 current_delegid = 1; |
59 | }; | 55 | static stateid_t zerostateid; /* bits all 0 */ |
60 | static const stateid_t currentstateid = { | 56 | static stateid_t onestateid; /* bits all 1 */ |
61 | .si_generation = 1, | ||
62 | }; | ||
63 | |||
64 | static u64 current_sessionid = 1; | 57 | static u64 current_sessionid = 1; |
65 | 58 | ||
66 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) | 59 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) |
67 | #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) | 60 | #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) |
68 | #define CURRENT_STATEID(stateid) (!memcmp((stateid), ¤tstateid, sizeof(stateid_t))) | ||
69 | 61 | ||
70 | /* forward declarations */ | 62 | /* forward declarations */ |
71 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); | 63 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); |
64 | static struct nfs4_stateid * search_for_stateid(stateid_t *stid); | ||
65 | static struct nfs4_delegation * search_for_delegation(stateid_t *stid); | ||
66 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); | ||
67 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | ||
68 | static void nfs4_set_recdir(char *recdir); | ||
69 | static int check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner); | ||
72 | 70 | ||
73 | /* Locking: */ | 71 | /* Locking: */ |
74 | 72 | ||
@@ -82,8 +80,7 @@ static DEFINE_MUTEX(client_mutex); | |||
82 | */ | 80 | */ |
83 | static DEFINE_SPINLOCK(recall_lock); | 81 | static DEFINE_SPINLOCK(recall_lock); |
84 | 82 | ||
85 | static struct kmem_cache *openowner_slab = NULL; | 83 | static struct kmem_cache *stateowner_slab = NULL; |
86 | static struct kmem_cache *lockowner_slab = NULL; | ||
87 | static struct kmem_cache *file_slab = NULL; | 84 | static struct kmem_cache *file_slab = NULL; |
88 | static struct kmem_cache *stateid_slab = NULL; | 85 | static struct kmem_cache *stateid_slab = NULL; |
89 | static struct kmem_cache *deleg_slab = NULL; | 86 | static struct kmem_cache *deleg_slab = NULL; |
@@ -94,19 +91,6 @@ nfs4_lock_state(void) | |||
94 | mutex_lock(&client_mutex); | 91 | mutex_lock(&client_mutex); |
95 | } | 92 | } |
96 | 93 | ||
97 | static void free_session(struct kref *); | ||
98 | |||
99 | /* Must be called under the client_lock */ | ||
100 | static void nfsd4_put_session_locked(struct nfsd4_session *ses) | ||
101 | { | ||
102 | kref_put(&ses->se_ref, free_session); | ||
103 | } | ||
104 | |||
105 | static void nfsd4_get_session(struct nfsd4_session *ses) | ||
106 | { | ||
107 | kref_get(&ses->se_ref); | ||
108 | } | ||
109 | |||
110 | void | 94 | void |
111 | nfs4_unlock_state(void) | 95 | nfs4_unlock_state(void) |
112 | { | 96 | { |
@@ -128,11 +112,6 @@ opaque_hashval(const void *ptr, int nbytes) | |||
128 | 112 | ||
129 | static struct list_head del_recall_lru; | 113 | static struct list_head del_recall_lru; |
130 | 114 | ||
131 | static void nfsd4_free_file(struct nfs4_file *f) | ||
132 | { | ||
133 | kmem_cache_free(file_slab, f); | ||
134 | } | ||
135 | |||
136 | static inline void | 115 | static inline void |
137 | put_nfs4_file(struct nfs4_file *fi) | 116 | put_nfs4_file(struct nfs4_file *fi) |
138 | { | 117 | { |
@@ -140,7 +119,7 @@ put_nfs4_file(struct nfs4_file *fi) | |||
140 | list_del(&fi->fi_hash); | 119 | list_del(&fi->fi_hash); |
141 | spin_unlock(&recall_lock); | 120 | spin_unlock(&recall_lock); |
142 | iput(fi->fi_inode); | 121 | iput(fi->fi_inode); |
143 | nfsd4_free_file(fi); | 122 | kmem_cache_free(file_slab, fi); |
144 | } | 123 | } |
145 | } | 124 | } |
146 | 125 | ||
@@ -157,35 +136,39 @@ unsigned int max_delegations; | |||
157 | * Open owner state (share locks) | 136 | * Open owner state (share locks) |
158 | */ | 137 | */ |
159 | 138 | ||
160 | /* hash tables for lock and open owners */ | 139 | /* hash tables for nfs4_stateowner */ |
161 | #define OWNER_HASH_BITS 8 | 140 | #define OWNER_HASH_BITS 8 |
162 | #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) | 141 | #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS) |
163 | #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) | 142 | #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1) |
164 | 143 | ||
165 | static unsigned int ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername) | 144 | #define ownerid_hashval(id) \ |
166 | { | 145 | ((id) & OWNER_HASH_MASK) |
167 | unsigned int ret; | 146 | #define ownerstr_hashval(clientid, ownername) \ |
147 | (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK) | ||
168 | 148 | ||
169 | ret = opaque_hashval(ownername->data, ownername->len); | 149 | static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE]; |
170 | ret += clientid; | 150 | static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE]; |
171 | return ret & OWNER_HASH_MASK; | ||
172 | } | ||
173 | 151 | ||
174 | /* hash table for nfs4_file */ | 152 | /* hash table for nfs4_file */ |
175 | #define FILE_HASH_BITS 8 | 153 | #define FILE_HASH_BITS 8 |
176 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) | 154 | #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) |
177 | 155 | ||
178 | static unsigned int file_hashval(struct inode *ino) | 156 | /* hash table for (open)nfs4_stateid */ |
179 | { | 157 | #define STATEID_HASH_BITS 10 |
180 | /* XXX: why are we hashing on inode pointer, anyway? */ | 158 | #define STATEID_HASH_SIZE (1 << STATEID_HASH_BITS) |
181 | return hash_ptr(ino, FILE_HASH_BITS); | 159 | #define STATEID_HASH_MASK (STATEID_HASH_SIZE - 1) |
182 | } | 160 | |
161 | #define file_hashval(x) \ | ||
162 | hash_ptr(x, FILE_HASH_BITS) | ||
163 | #define stateid_hashval(owner_id, file_id) \ | ||
164 | (((owner_id) + (file_id)) & STATEID_HASH_MASK) | ||
183 | 165 | ||
184 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; | 166 | static struct list_head file_hashtbl[FILE_HASH_SIZE]; |
167 | static struct list_head stateid_hashtbl[STATEID_HASH_SIZE]; | ||
185 | 168 | ||
186 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) | 169 | static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag) |
187 | { | 170 | { |
188 | WARN_ON_ONCE(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); | 171 | BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR])); |
189 | atomic_inc(&fp->fi_access[oflag]); | 172 | atomic_inc(&fp->fi_access[oflag]); |
190 | } | 173 | } |
191 | 174 | ||
@@ -230,73 +213,8 @@ static void nfs4_file_put_access(struct nfs4_file *fp, int oflag) | |||
230 | __nfs4_file_put_access(fp, oflag); | 213 | __nfs4_file_put_access(fp, oflag); |
231 | } | 214 | } |
232 | 215 | ||
233 | static inline int get_new_stid(struct nfs4_stid *stid) | ||
234 | { | ||
235 | static int min_stateid = 0; | ||
236 | struct idr *stateids = &stid->sc_client->cl_stateids; | ||
237 | int new_stid; | ||
238 | int error; | ||
239 | |||
240 | error = idr_get_new_above(stateids, stid, min_stateid, &new_stid); | ||
241 | /* | ||
242 | * Note: the necessary preallocation was done in | ||
243 | * nfs4_alloc_stateid(). The idr code caps the number of | ||
244 | * preallocations that can exist at a time, but the state lock | ||
245 | * prevents anyone from using ours before we get here: | ||
246 | */ | ||
247 | WARN_ON_ONCE(error); | ||
248 | /* | ||
249 | * It shouldn't be a problem to reuse an opaque stateid value. | ||
250 | * I don't think it is for 4.1. But with 4.0 I worry that, for | ||
251 | * example, a stray write retransmission could be accepted by | ||
252 | * the server when it should have been rejected. Therefore, | ||
253 | * adopt a trick from the sctp code to attempt to maximize the | ||
254 | * amount of time until an id is reused, by ensuring they always | ||
255 | * "increase" (mod INT_MAX): | ||
256 | */ | ||
257 | |||
258 | min_stateid = new_stid+1; | ||
259 | if (min_stateid == INT_MAX) | ||
260 | min_stateid = 0; | ||
261 | return new_stid; | ||
262 | } | ||
263 | |||
264 | static void init_stid(struct nfs4_stid *stid, struct nfs4_client *cl, unsigned char type) | ||
265 | { | ||
266 | stateid_t *s = &stid->sc_stateid; | ||
267 | int new_id; | ||
268 | |||
269 | stid->sc_type = type; | ||
270 | stid->sc_client = cl; | ||
271 | s->si_opaque.so_clid = cl->cl_clientid; | ||
272 | new_id = get_new_stid(stid); | ||
273 | s->si_opaque.so_id = (u32)new_id; | ||
274 | /* Will be incremented before return to client: */ | ||
275 | s->si_generation = 0; | ||
276 | } | ||
277 | |||
278 | static struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *slab) | ||
279 | { | ||
280 | struct idr *stateids = &cl->cl_stateids; | ||
281 | |||
282 | if (!idr_pre_get(stateids, GFP_KERNEL)) | ||
283 | return NULL; | ||
284 | /* | ||
285 | * Note: if we fail here (or any time between now and the time | ||
286 | * we actually get the new idr), we won't need to undo the idr | ||
287 | * preallocation, since the idr code caps the number of | ||
288 | * preallocated entries. | ||
289 | */ | ||
290 | return kmem_cache_alloc(slab, GFP_KERNEL); | ||
291 | } | ||
292 | |||
293 | static struct nfs4_ol_stateid * nfs4_alloc_stateid(struct nfs4_client *clp) | ||
294 | { | ||
295 | return openlockstateid(nfs4_alloc_stid(clp, stateid_slab)); | ||
296 | } | ||
297 | |||
298 | static struct nfs4_delegation * | 216 | static struct nfs4_delegation * |
299 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type) | 217 | alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type) |
300 | { | 218 | { |
301 | struct nfs4_delegation *dp; | 219 | struct nfs4_delegation *dp; |
302 | struct nfs4_file *fp = stp->st_file; | 220 | struct nfs4_file *fp = stp->st_file; |
@@ -313,27 +231,25 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct sv | |||
313 | return NULL; | 231 | return NULL; |
314 | if (num_delegations > max_delegations) | 232 | if (num_delegations > max_delegations) |
315 | return NULL; | 233 | return NULL; |
316 | dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab)); | 234 | dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL); |
317 | if (dp == NULL) | 235 | if (dp == NULL) |
318 | return dp; | 236 | return dp; |
319 | init_stid(&dp->dl_stid, clp, NFS4_DELEG_STID); | ||
320 | /* | ||
321 | * delegation seqid's are never incremented. The 4.1 special | ||
322 | * meaning of seqid 0 isn't meaningful, really, but let's avoid | ||
323 | * 0 anyway just for consistency and use 1: | ||
324 | */ | ||
325 | dp->dl_stid.sc_stateid.si_generation = 1; | ||
326 | num_delegations++; | 237 | num_delegations++; |
327 | INIT_LIST_HEAD(&dp->dl_perfile); | 238 | INIT_LIST_HEAD(&dp->dl_perfile); |
328 | INIT_LIST_HEAD(&dp->dl_perclnt); | 239 | INIT_LIST_HEAD(&dp->dl_perclnt); |
329 | INIT_LIST_HEAD(&dp->dl_recall_lru); | 240 | INIT_LIST_HEAD(&dp->dl_recall_lru); |
241 | dp->dl_client = clp; | ||
330 | get_nfs4_file(fp); | 242 | get_nfs4_file(fp); |
331 | dp->dl_file = fp; | 243 | dp->dl_file = fp; |
332 | dp->dl_type = type; | 244 | dp->dl_type = type; |
245 | dp->dl_stateid.si_boot = boot_time; | ||
246 | dp->dl_stateid.si_stateownerid = current_delegid++; | ||
247 | dp->dl_stateid.si_fileid = 0; | ||
248 | dp->dl_stateid.si_generation = 0; | ||
333 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); | 249 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
334 | dp->dl_time = 0; | 250 | dp->dl_time = 0; |
335 | atomic_set(&dp->dl_count, 1); | 251 | atomic_set(&dp->dl_count, 1); |
336 | nfsd4_init_callback(&dp->dl_recall); | 252 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc); |
337 | return dp; | 253 | return dp; |
338 | } | 254 | } |
339 | 255 | ||
@@ -358,18 +274,10 @@ static void nfs4_put_deleg_lease(struct nfs4_file *fp) | |||
358 | } | 274 | } |
359 | } | 275 | } |
360 | 276 | ||
361 | static void unhash_stid(struct nfs4_stid *s) | ||
362 | { | ||
363 | struct idr *stateids = &s->sc_client->cl_stateids; | ||
364 | |||
365 | idr_remove(stateids, s->sc_stateid.si_opaque.so_id); | ||
366 | } | ||
367 | |||
368 | /* Called under the state lock. */ | 277 | /* Called under the state lock. */ |
369 | static void | 278 | static void |
370 | unhash_delegation(struct nfs4_delegation *dp) | 279 | unhash_delegation(struct nfs4_delegation *dp) |
371 | { | 280 | { |
372 | unhash_stid(&dp->dl_stid); | ||
373 | list_del_init(&dp->dl_perclnt); | 281 | list_del_init(&dp->dl_perclnt); |
374 | spin_lock(&recall_lock); | 282 | spin_lock(&recall_lock); |
375 | list_del_init(&dp->dl_perfile); | 283 | list_del_init(&dp->dl_perfile); |
@@ -383,15 +291,42 @@ unhash_delegation(struct nfs4_delegation *dp) | |||
383 | * SETCLIENTID state | 291 | * SETCLIENTID state |
384 | */ | 292 | */ |
385 | 293 | ||
386 | static unsigned int clientid_hashval(u32 id) | 294 | /* client_lock protects the client lru list and session hash table */ |
387 | { | 295 | static DEFINE_SPINLOCK(client_lock); |
388 | return id & CLIENT_HASH_MASK; | ||
389 | } | ||
390 | 296 | ||
391 | static unsigned int clientstr_hashval(const char *name) | 297 | /* Hash tables for nfs4_clientid state */ |
392 | { | 298 | #define CLIENT_HASH_BITS 4 |
393 | return opaque_hashval(name, 8) & CLIENT_HASH_MASK; | 299 | #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS) |
394 | } | 300 | #define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1) |
301 | |||
302 | #define clientid_hashval(id) \ | ||
303 | ((id) & CLIENT_HASH_MASK) | ||
304 | #define clientstr_hashval(name) \ | ||
305 | (opaque_hashval((name), 8) & CLIENT_HASH_MASK) | ||
306 | /* | ||
307 | * reclaim_str_hashtbl[] holds known client info from previous reset/reboot | ||
308 | * used in reboot/reset lease grace period processing | ||
309 | * | ||
310 | * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed | ||
311 | * setclientid_confirmed info. | ||
312 | * | ||
313 | * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed | ||
314 | * setclientid info. | ||
315 | * | ||
316 | * client_lru holds client queue ordered by nfs4_client.cl_time | ||
317 | * for lease renewal. | ||
318 | * | ||
319 | * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time | ||
320 | * for last close replay. | ||
321 | */ | ||
322 | static struct list_head reclaim_str_hashtbl[CLIENT_HASH_SIZE]; | ||
323 | static int reclaim_str_hashtbl_size = 0; | ||
324 | static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE]; | ||
325 | static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE]; | ||
326 | static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE]; | ||
327 | static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; | ||
328 | static struct list_head client_lru; | ||
329 | static struct list_head close_lru; | ||
395 | 330 | ||
396 | /* | 331 | /* |
397 | * We store the NONE, READ, WRITE, and BOTH bits separately in the | 332 | * We store the NONE, READ, WRITE, and BOTH bits separately in the |
@@ -411,69 +346,37 @@ static unsigned int clientstr_hashval(const char *name) | |||
411 | * | 346 | * |
412 | * which we should reject. | 347 | * which we should reject. |
413 | */ | 348 | */ |
414 | static unsigned int | 349 | static void |
415 | bmap_to_share_mode(unsigned long bmap) { | 350 | set_access(unsigned int *access, unsigned long bmap) { |
416 | int i; | 351 | int i; |
417 | unsigned int access = 0; | ||
418 | 352 | ||
353 | *access = 0; | ||
419 | for (i = 1; i < 4; i++) { | 354 | for (i = 1; i < 4; i++) { |
420 | if (test_bit(i, &bmap)) | 355 | if (test_bit(i, &bmap)) |
421 | access |= i; | 356 | *access |= i; |
422 | } | 357 | } |
423 | return access; | ||
424 | } | ||
425 | |||
426 | static bool | ||
427 | test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) { | ||
428 | unsigned int access, deny; | ||
429 | |||
430 | access = bmap_to_share_mode(stp->st_access_bmap); | ||
431 | deny = bmap_to_share_mode(stp->st_deny_bmap); | ||
432 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) | ||
433 | return false; | ||
434 | return true; | ||
435 | } | 358 | } |
436 | 359 | ||
437 | /* set share access for a given stateid */ | 360 | static void |
438 | static inline void | 361 | set_deny(unsigned int *deny, unsigned long bmap) { |
439 | set_access(u32 access, struct nfs4_ol_stateid *stp) | 362 | int i; |
440 | { | ||
441 | __set_bit(access, &stp->st_access_bmap); | ||
442 | } | ||
443 | |||
444 | /* clear share access for a given stateid */ | ||
445 | static inline void | ||
446 | clear_access(u32 access, struct nfs4_ol_stateid *stp) | ||
447 | { | ||
448 | __clear_bit(access, &stp->st_access_bmap); | ||
449 | } | ||
450 | |||
451 | /* test whether a given stateid has access */ | ||
452 | static inline bool | ||
453 | test_access(u32 access, struct nfs4_ol_stateid *stp) | ||
454 | { | ||
455 | return test_bit(access, &stp->st_access_bmap); | ||
456 | } | ||
457 | 363 | ||
458 | /* set share deny for a given stateid */ | 364 | *deny = 0; |
459 | static inline void | 365 | for (i = 0; i < 4; i++) { |
460 | set_deny(u32 access, struct nfs4_ol_stateid *stp) | 366 | if (test_bit(i, &bmap)) |
461 | { | 367 | *deny |= i ; |
462 | __set_bit(access, &stp->st_deny_bmap); | 368 | } |
463 | } | 369 | } |
464 | 370 | ||
465 | /* clear share deny for a given stateid */ | 371 | static int |
466 | static inline void | 372 | test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) { |
467 | clear_deny(u32 access, struct nfs4_ol_stateid *stp) | 373 | unsigned int access, deny; |
468 | { | ||
469 | __clear_bit(access, &stp->st_deny_bmap); | ||
470 | } | ||
471 | 374 | ||
472 | /* test whether a given stateid is denying specific access */ | 375 | set_access(&access, stp->st_access_bmap); |
473 | static inline bool | 376 | set_deny(&deny, stp->st_deny_bmap); |
474 | test_deny(u32 access, struct nfs4_ol_stateid *stp) | 377 | if ((access & open->op_share_deny) || (deny & open->op_share_access)) |
475 | { | 378 | return 0; |
476 | return test_bit(access, &stp->st_deny_bmap); | 379 | return 1; |
477 | } | 380 | } |
478 | 381 | ||
479 | static int nfs4_access_to_omode(u32 access) | 382 | static int nfs4_access_to_omode(u32 access) |
@@ -486,132 +389,107 @@ static int nfs4_access_to_omode(u32 access) | |||
486 | case NFS4_SHARE_ACCESS_BOTH: | 389 | case NFS4_SHARE_ACCESS_BOTH: |
487 | return O_RDWR; | 390 | return O_RDWR; |
488 | } | 391 | } |
489 | WARN_ON_ONCE(1); | 392 | BUG(); |
490 | return O_RDONLY; | ||
491 | } | ||
492 | |||
493 | /* release all access and file references for a given stateid */ | ||
494 | static void | ||
495 | release_all_access(struct nfs4_ol_stateid *stp) | ||
496 | { | ||
497 | int i; | ||
498 | |||
499 | for (i = 1; i < 4; i++) { | ||
500 | if (test_access(i, stp)) | ||
501 | nfs4_file_put_access(stp->st_file, | ||
502 | nfs4_access_to_omode(i)); | ||
503 | clear_access(i, stp); | ||
504 | } | ||
505 | } | 393 | } |
506 | 394 | ||
507 | static void unhash_generic_stateid(struct nfs4_ol_stateid *stp) | 395 | static void unhash_generic_stateid(struct nfs4_stateid *stp) |
508 | { | 396 | { |
397 | list_del(&stp->st_hash); | ||
509 | list_del(&stp->st_perfile); | 398 | list_del(&stp->st_perfile); |
510 | list_del(&stp->st_perstateowner); | 399 | list_del(&stp->st_perstateowner); |
511 | } | 400 | } |
512 | 401 | ||
513 | static void close_generic_stateid(struct nfs4_ol_stateid *stp) | 402 | static void free_generic_stateid(struct nfs4_stateid *stp) |
514 | { | 403 | { |
515 | release_all_access(stp); | 404 | int i; |
516 | put_nfs4_file(stp->st_file); | ||
517 | stp->st_file = NULL; | ||
518 | } | ||
519 | 405 | ||
520 | static void free_generic_stateid(struct nfs4_ol_stateid *stp) | 406 | if (stp->st_access_bmap) { |
521 | { | 407 | for (i = 1; i < 4; i++) { |
408 | if (test_bit(i, &stp->st_access_bmap)) | ||
409 | nfs4_file_put_access(stp->st_file, | ||
410 | nfs4_access_to_omode(i)); | ||
411 | } | ||
412 | } | ||
413 | put_nfs4_file(stp->st_file); | ||
522 | kmem_cache_free(stateid_slab, stp); | 414 | kmem_cache_free(stateid_slab, stp); |
523 | } | 415 | } |
524 | 416 | ||
525 | static void release_lock_stateid(struct nfs4_ol_stateid *stp) | 417 | static void release_lock_stateid(struct nfs4_stateid *stp) |
526 | { | 418 | { |
527 | struct file *file; | 419 | struct file *file; |
528 | 420 | ||
529 | unhash_generic_stateid(stp); | 421 | unhash_generic_stateid(stp); |
530 | unhash_stid(&stp->st_stid); | ||
531 | file = find_any_file(stp->st_file); | 422 | file = find_any_file(stp->st_file); |
532 | if (file) | 423 | if (file) |
533 | locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner)); | 424 | locks_remove_posix(file, (fl_owner_t)stp->st_stateowner); |
534 | close_generic_stateid(stp); | ||
535 | free_generic_stateid(stp); | 425 | free_generic_stateid(stp); |
536 | } | 426 | } |
537 | 427 | ||
538 | static void unhash_lockowner(struct nfs4_lockowner *lo) | 428 | static void unhash_lockowner(struct nfs4_stateowner *sop) |
539 | { | 429 | { |
540 | struct nfs4_ol_stateid *stp; | 430 | struct nfs4_stateid *stp; |
541 | 431 | ||
542 | list_del(&lo->lo_owner.so_strhash); | 432 | list_del(&sop->so_idhash); |
543 | list_del(&lo->lo_perstateid); | 433 | list_del(&sop->so_strhash); |
544 | list_del(&lo->lo_owner_ino_hash); | 434 | list_del(&sop->so_perstateid); |
545 | while (!list_empty(&lo->lo_owner.so_stateids)) { | 435 | while (!list_empty(&sop->so_stateids)) { |
546 | stp = list_first_entry(&lo->lo_owner.so_stateids, | 436 | stp = list_first_entry(&sop->so_stateids, |
547 | struct nfs4_ol_stateid, st_perstateowner); | 437 | struct nfs4_stateid, st_perstateowner); |
548 | release_lock_stateid(stp); | 438 | release_lock_stateid(stp); |
549 | } | 439 | } |
550 | } | 440 | } |
551 | 441 | ||
552 | static void release_lockowner(struct nfs4_lockowner *lo) | 442 | static void release_lockowner(struct nfs4_stateowner *sop) |
553 | { | 443 | { |
554 | unhash_lockowner(lo); | 444 | unhash_lockowner(sop); |
555 | nfs4_free_lockowner(lo); | 445 | nfs4_put_stateowner(sop); |
556 | } | 446 | } |
557 | 447 | ||
558 | static void | 448 | static void |
559 | release_stateid_lockowners(struct nfs4_ol_stateid *open_stp) | 449 | release_stateid_lockowners(struct nfs4_stateid *open_stp) |
560 | { | 450 | { |
561 | struct nfs4_lockowner *lo; | 451 | struct nfs4_stateowner *lock_sop; |
562 | 452 | ||
563 | while (!list_empty(&open_stp->st_lockowners)) { | 453 | while (!list_empty(&open_stp->st_lockowners)) { |
564 | lo = list_entry(open_stp->st_lockowners.next, | 454 | lock_sop = list_entry(open_stp->st_lockowners.next, |
565 | struct nfs4_lockowner, lo_perstateid); | 455 | struct nfs4_stateowner, so_perstateid); |
566 | release_lockowner(lo); | 456 | /* list_del(&open_stp->st_lockowners); */ |
457 | BUG_ON(lock_sop->so_is_open_owner); | ||
458 | release_lockowner(lock_sop); | ||
567 | } | 459 | } |
568 | } | 460 | } |
569 | 461 | ||
570 | static void unhash_open_stateid(struct nfs4_ol_stateid *stp) | 462 | static void release_open_stateid(struct nfs4_stateid *stp) |
571 | { | 463 | { |
572 | unhash_generic_stateid(stp); | 464 | unhash_generic_stateid(stp); |
573 | release_stateid_lockowners(stp); | 465 | release_stateid_lockowners(stp); |
574 | close_generic_stateid(stp); | ||
575 | } | ||
576 | |||
577 | static void release_open_stateid(struct nfs4_ol_stateid *stp) | ||
578 | { | ||
579 | unhash_open_stateid(stp); | ||
580 | unhash_stid(&stp->st_stid); | ||
581 | free_generic_stateid(stp); | 466 | free_generic_stateid(stp); |
582 | } | 467 | } |
583 | 468 | ||
584 | static void unhash_openowner(struct nfs4_openowner *oo) | 469 | static void unhash_openowner(struct nfs4_stateowner *sop) |
585 | { | 470 | { |
586 | struct nfs4_ol_stateid *stp; | 471 | struct nfs4_stateid *stp; |
587 | 472 | ||
588 | list_del(&oo->oo_owner.so_strhash); | 473 | list_del(&sop->so_idhash); |
589 | list_del(&oo->oo_perclient); | 474 | list_del(&sop->so_strhash); |
590 | while (!list_empty(&oo->oo_owner.so_stateids)) { | 475 | list_del(&sop->so_perclient); |
591 | stp = list_first_entry(&oo->oo_owner.so_stateids, | 476 | list_del(&sop->so_perstateid); /* XXX: necessary? */ |
592 | struct nfs4_ol_stateid, st_perstateowner); | 477 | while (!list_empty(&sop->so_stateids)) { |
478 | stp = list_first_entry(&sop->so_stateids, | ||
479 | struct nfs4_stateid, st_perstateowner); | ||
593 | release_open_stateid(stp); | 480 | release_open_stateid(stp); |
594 | } | 481 | } |
595 | } | 482 | } |
596 | 483 | ||
597 | static void release_last_closed_stateid(struct nfs4_openowner *oo) | 484 | static void release_openowner(struct nfs4_stateowner *sop) |
598 | { | 485 | { |
599 | struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; | 486 | unhash_openowner(sop); |
600 | 487 | list_del(&sop->so_close_lru); | |
601 | if (s) { | 488 | nfs4_put_stateowner(sop); |
602 | unhash_stid(&s->st_stid); | ||
603 | free_generic_stateid(s); | ||
604 | oo->oo_last_closed_stid = NULL; | ||
605 | } | ||
606 | } | 489 | } |
607 | 490 | ||
608 | static void release_openowner(struct nfs4_openowner *oo) | 491 | #define SESSION_HASH_SIZE 512 |
609 | { | 492 | static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; |
610 | unhash_openowner(oo); | ||
611 | list_del(&oo->oo_close_lru); | ||
612 | release_last_closed_stateid(oo); | ||
613 | nfs4_free_openowner(oo); | ||
614 | } | ||
615 | 493 | ||
616 | static inline int | 494 | static inline int |
617 | hash_sessionid(struct nfs4_sessionid *sessionid) | 495 | hash_sessionid(struct nfs4_sessionid *sessionid) |
@@ -621,20 +499,12 @@ hash_sessionid(struct nfs4_sessionid *sessionid) | |||
621 | return sid->sequence % SESSION_HASH_SIZE; | 499 | return sid->sequence % SESSION_HASH_SIZE; |
622 | } | 500 | } |
623 | 501 | ||
624 | #ifdef NFSD_DEBUG | ||
625 | static inline void | 502 | static inline void |
626 | dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) | 503 | dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) |
627 | { | 504 | { |
628 | u32 *ptr = (u32 *)(&sessionid->data[0]); | 505 | u32 *ptr = (u32 *)(&sessionid->data[0]); |
629 | dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); | 506 | dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); |
630 | } | 507 | } |
631 | #else | ||
632 | static inline void | ||
633 | dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) | ||
634 | { | ||
635 | } | ||
636 | #endif | ||
637 | |||
638 | 508 | ||
639 | static void | 509 | static void |
640 | gen_sessionid(struct nfsd4_session *ses) | 510 | gen_sessionid(struct nfsd4_session *ses) |
@@ -691,7 +561,7 @@ static int nfsd4_sanitize_slot_size(u32 size) | |||
691 | /* | 561 | /* |
692 | * XXX: If we run out of reserved DRC memory we could (up to a point) | 562 | * XXX: If we run out of reserved DRC memory we could (up to a point) |
693 | * re-negotiate active sessions and reduce their slot usage to make | 563 | * re-negotiate active sessions and reduce their slot usage to make |
694 | * room for new connections. For now we just fail the create session. | 564 | * rooom for new connections. For now we just fail the create session. |
695 | */ | 565 | */ |
696 | static int nfsd4_get_drc_mem(int slotsize, u32 num) | 566 | static int nfsd4_get_drc_mem(int slotsize, u32 num) |
697 | { | 567 | { |
@@ -716,7 +586,7 @@ static void nfsd4_put_drc_mem(int slotsize, int num) | |||
716 | spin_unlock(&nfsd_drc_lock); | 586 | spin_unlock(&nfsd_drc_lock); |
717 | } | 587 | } |
718 | 588 | ||
719 | static struct nfsd4_session *__alloc_session(int slotsize, int numslots) | 589 | static struct nfsd4_session *alloc_session(int slotsize, int numslots) |
720 | { | 590 | { |
721 | struct nfsd4_session *new; | 591 | struct nfsd4_session *new; |
722 | int mem, i; | 592 | int mem, i; |
@@ -743,12 +613,9 @@ out_free: | |||
743 | return NULL; | 613 | return NULL; |
744 | } | 614 | } |
745 | 615 | ||
746 | static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, | 616 | static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize) |
747 | struct nfsd4_channel_attrs *req, | ||
748 | int numslots, int slotsize, | ||
749 | struct nfsd_net *nn) | ||
750 | { | 617 | { |
751 | u32 maxrpc = nn->nfsd_serv->sv_max_mesg; | 618 | u32 maxrpc = nfsd_serv->sv_max_mesg; |
752 | 619 | ||
753 | new->maxreqs = numslots; | 620 | new->maxreqs = numslots; |
754 | new->maxresp_cached = min_t(u32, req->maxresp_cached, | 621 | new->maxresp_cached = min_t(u32, req->maxresp_cached, |
@@ -813,28 +680,30 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn) | |||
813 | return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); | 680 | return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user); |
814 | } | 681 | } |
815 | 682 | ||
816 | static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses) | 683 | static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir) |
817 | { | 684 | { |
685 | struct nfsd4_conn *conn; | ||
818 | int ret; | 686 | int ret; |
819 | 687 | ||
688 | conn = alloc_conn(rqstp, dir); | ||
689 | if (!conn) | ||
690 | return nfserr_jukebox; | ||
820 | nfsd4_hash_conn(conn, ses); | 691 | nfsd4_hash_conn(conn, ses); |
821 | ret = nfsd4_register_conn(conn); | 692 | ret = nfsd4_register_conn(conn); |
822 | if (ret) | 693 | if (ret) |
823 | /* oops; xprt is already down: */ | 694 | /* oops; xprt is already down: */ |
824 | nfsd4_conn_lost(&conn->cn_xpt_user); | 695 | nfsd4_conn_lost(&conn->cn_xpt_user); |
825 | if (conn->cn_flags & NFS4_CDFC4_BACK) { | 696 | return nfs_ok; |
826 | /* callback channel may be back up */ | ||
827 | nfsd4_probe_callback(ses->se_client); | ||
828 | } | ||
829 | } | 697 | } |
830 | 698 | ||
831 | static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses) | 699 | static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses) |
832 | { | 700 | { |
833 | u32 dir = NFS4_CDFC4_FORE; | 701 | u32 dir = NFS4_CDFC4_FORE; |
834 | 702 | ||
835 | if (cses->flags & SESSION4_BACK_CHAN) | 703 | if (ses->se_flags & SESSION4_BACK_CHAN) |
836 | dir |= NFS4_CDFC4_BACK; | 704 | dir |= NFS4_CDFC4_BACK; |
837 | return alloc_conn(rqstp, dir); | 705 | |
706 | return nfsd4_new_conn(rqstp, ses, dir); | ||
838 | } | 707 | } |
839 | 708 | ||
840 | /* must be called under client_lock */ | 709 | /* must be called under client_lock */ |
@@ -857,40 +726,29 @@ static void nfsd4_del_conns(struct nfsd4_session *s) | |||
857 | spin_unlock(&clp->cl_lock); | 726 | spin_unlock(&clp->cl_lock); |
858 | } | 727 | } |
859 | 728 | ||
860 | static void __free_session(struct nfsd4_session *ses) | 729 | void free_session(struct kref *kref) |
861 | { | ||
862 | nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs); | ||
863 | free_session_slots(ses); | ||
864 | kfree(ses); | ||
865 | } | ||
866 | |||
867 | static void free_session(struct kref *kref) | ||
868 | { | 730 | { |
869 | struct nfsd4_session *ses; | 731 | struct nfsd4_session *ses; |
870 | struct nfsd_net *nn; | 732 | int mem; |
871 | 733 | ||
872 | ses = container_of(kref, struct nfsd4_session, se_ref); | 734 | ses = container_of(kref, struct nfsd4_session, se_ref); |
873 | nn = net_generic(ses->se_client->net, nfsd_net_id); | ||
874 | |||
875 | lockdep_assert_held(&nn->client_lock); | ||
876 | nfsd4_del_conns(ses); | 735 | nfsd4_del_conns(ses); |
877 | __free_session(ses); | 736 | spin_lock(&nfsd_drc_lock); |
878 | } | 737 | mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel); |
879 | 738 | nfsd_drc_mem_used -= mem; | |
880 | void nfsd4_put_session(struct nfsd4_session *ses) | 739 | spin_unlock(&nfsd_drc_lock); |
881 | { | 740 | free_session_slots(ses); |
882 | struct nfsd_net *nn = net_generic(ses->se_client->net, nfsd_net_id); | 741 | kfree(ses); |
883 | |||
884 | spin_lock(&nn->client_lock); | ||
885 | nfsd4_put_session_locked(ses); | ||
886 | spin_unlock(&nn->client_lock); | ||
887 | } | 742 | } |
888 | 743 | ||
889 | static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan, | 744 | static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) |
890 | struct nfsd_net *nn) | ||
891 | { | 745 | { |
892 | struct nfsd4_session *new; | 746 | struct nfsd4_session *new; |
747 | struct nfsd4_channel_attrs *fchan = &cses->fore_channel; | ||
893 | int numslots, slotsize; | 748 | int numslots, slotsize; |
749 | int status; | ||
750 | int idx; | ||
751 | |||
894 | /* | 752 | /* |
895 | * Note decreasing slot size below client's request may | 753 | * Note decreasing slot size below client's request may |
896 | * make it difficult for client to function correctly, whereas | 754 | * make it difficult for client to function correctly, whereas |
@@ -903,19 +761,12 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan, | |||
903 | if (numslots < 1) | 761 | if (numslots < 1) |
904 | return NULL; | 762 | return NULL; |
905 | 763 | ||
906 | new = __alloc_session(slotsize, numslots); | 764 | new = alloc_session(slotsize, numslots); |
907 | if (!new) { | 765 | if (!new) { |
908 | nfsd4_put_drc_mem(slotsize, fchan->maxreqs); | 766 | nfsd4_put_drc_mem(slotsize, fchan->maxreqs); |
909 | return NULL; | 767 | return NULL; |
910 | } | 768 | } |
911 | init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize, nn); | 769 | init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize); |
912 | return new; | ||
913 | } | ||
914 | |||
915 | static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) | ||
916 | { | ||
917 | int idx; | ||
918 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
919 | 770 | ||
920 | new->se_client = clp; | 771 | new->se_client = clp; |
921 | gen_sessionid(new); | 772 | gen_sessionid(new); |
@@ -925,16 +776,21 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru | |||
925 | new->se_cb_seq_nr = 1; | 776 | new->se_cb_seq_nr = 1; |
926 | new->se_flags = cses->flags; | 777 | new->se_flags = cses->flags; |
927 | new->se_cb_prog = cses->callback_prog; | 778 | new->se_cb_prog = cses->callback_prog; |
928 | new->se_cb_sec = cses->cb_sec; | ||
929 | kref_init(&new->se_ref); | 779 | kref_init(&new->se_ref); |
930 | idx = hash_sessionid(&new->se_sessionid); | 780 | idx = hash_sessionid(&new->se_sessionid); |
931 | spin_lock(&nn->client_lock); | 781 | spin_lock(&client_lock); |
932 | list_add(&new->se_hash, &nn->sessionid_hashtbl[idx]); | 782 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); |
933 | spin_lock(&clp->cl_lock); | 783 | spin_lock(&clp->cl_lock); |
934 | list_add(&new->se_perclnt, &clp->cl_sessions); | 784 | list_add(&new->se_perclnt, &clp->cl_sessions); |
935 | spin_unlock(&clp->cl_lock); | 785 | spin_unlock(&clp->cl_lock); |
936 | spin_unlock(&nn->client_lock); | 786 | spin_unlock(&client_lock); |
937 | 787 | ||
788 | status = nfsd4_new_conn_from_crses(rqstp, new); | ||
789 | /* whoops: benny points out, status is ignored! (err, or bogus) */ | ||
790 | if (status) { | ||
791 | free_session(&new->se_ref); | ||
792 | return NULL; | ||
793 | } | ||
938 | if (cses->flags & SESSION4_BACK_CHAN) { | 794 | if (cses->flags & SESSION4_BACK_CHAN) { |
939 | struct sockaddr *sa = svc_addr(rqstp); | 795 | struct sockaddr *sa = svc_addr(rqstp); |
940 | /* | 796 | /* |
@@ -947,20 +803,21 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru | |||
947 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); | 803 | rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa); |
948 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); | 804 | clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa); |
949 | } | 805 | } |
806 | nfsd4_probe_callback(clp); | ||
807 | return new; | ||
950 | } | 808 | } |
951 | 809 | ||
952 | /* caller must hold client_lock */ | 810 | /* caller must hold client_lock */ |
953 | static struct nfsd4_session * | 811 | static struct nfsd4_session * |
954 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid, struct net *net) | 812 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) |
955 | { | 813 | { |
956 | struct nfsd4_session *elem; | 814 | struct nfsd4_session *elem; |
957 | int idx; | 815 | int idx; |
958 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
959 | 816 | ||
960 | dump_sessionid(__func__, sessionid); | 817 | dump_sessionid(__func__, sessionid); |
961 | idx = hash_sessionid(sessionid); | 818 | idx = hash_sessionid(sessionid); |
962 | /* Search in the appropriate list */ | 819 | /* Search in the appropriate list */ |
963 | list_for_each_entry(elem, &nn->sessionid_hashtbl[idx], se_hash) { | 820 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { |
964 | if (!memcmp(elem->se_sessionid.data, sessionid->data, | 821 | if (!memcmp(elem->se_sessionid.data, sessionid->data, |
965 | NFS4_MAX_SESSIONID_LEN)) { | 822 | NFS4_MAX_SESSIONID_LEN)) { |
966 | return elem; | 823 | return elem; |
@@ -985,42 +842,40 @@ unhash_session(struct nfsd4_session *ses) | |||
985 | static inline void | 842 | static inline void |
986 | renew_client_locked(struct nfs4_client *clp) | 843 | renew_client_locked(struct nfs4_client *clp) |
987 | { | 844 | { |
988 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
989 | |||
990 | if (is_client_expired(clp)) { | 845 | if (is_client_expired(clp)) { |
991 | WARN_ON(1); | 846 | dprintk("%s: client (clientid %08x/%08x) already expired\n", |
992 | printk("%s: client (clientid %08x/%08x) already expired\n", | ||
993 | __func__, | 847 | __func__, |
994 | clp->cl_clientid.cl_boot, | 848 | clp->cl_clientid.cl_boot, |
995 | clp->cl_clientid.cl_id); | 849 | clp->cl_clientid.cl_id); |
996 | return; | 850 | return; |
997 | } | 851 | } |
998 | 852 | ||
853 | /* | ||
854 | * Move client to the end to the LRU list. | ||
855 | */ | ||
999 | dprintk("renewing client (clientid %08x/%08x)\n", | 856 | dprintk("renewing client (clientid %08x/%08x)\n", |
1000 | clp->cl_clientid.cl_boot, | 857 | clp->cl_clientid.cl_boot, |
1001 | clp->cl_clientid.cl_id); | 858 | clp->cl_clientid.cl_id); |
1002 | list_move_tail(&clp->cl_lru, &nn->client_lru); | 859 | list_move_tail(&clp->cl_lru, &client_lru); |
1003 | clp->cl_time = get_seconds(); | 860 | clp->cl_time = get_seconds(); |
1004 | } | 861 | } |
1005 | 862 | ||
1006 | static inline void | 863 | static inline void |
1007 | renew_client(struct nfs4_client *clp) | 864 | renew_client(struct nfs4_client *clp) |
1008 | { | 865 | { |
1009 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | 866 | spin_lock(&client_lock); |
1010 | |||
1011 | spin_lock(&nn->client_lock); | ||
1012 | renew_client_locked(clp); | 867 | renew_client_locked(clp); |
1013 | spin_unlock(&nn->client_lock); | 868 | spin_unlock(&client_lock); |
1014 | } | 869 | } |
1015 | 870 | ||
1016 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ | 871 | /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */ |
1017 | static int | 872 | static int |
1018 | STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) | 873 | STALE_CLIENTID(clientid_t *clid) |
1019 | { | 874 | { |
1020 | if (clid->cl_boot == nn->boot_time) | 875 | if (clid->cl_boot == boot_time) |
1021 | return 0; | 876 | return 0; |
1022 | dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", | 877 | dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", |
1023 | clid->cl_boot, clid->cl_id, nn->boot_time); | 878 | clid->cl_boot, clid->cl_id, boot_time); |
1024 | return 1; | 879 | return 1; |
1025 | } | 880 | } |
1026 | 881 | ||
@@ -1036,11 +891,12 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
1036 | clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); | 891 | clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL); |
1037 | if (clp == NULL) | 892 | if (clp == NULL) |
1038 | return NULL; | 893 | return NULL; |
1039 | clp->cl_name.data = kmemdup(name.data, name.len, GFP_KERNEL); | 894 | clp->cl_name.data = kmalloc(name.len, GFP_KERNEL); |
1040 | if (clp->cl_name.data == NULL) { | 895 | if (clp->cl_name.data == NULL) { |
1041 | kfree(clp); | 896 | kfree(clp); |
1042 | return NULL; | 897 | return NULL; |
1043 | } | 898 | } |
899 | memcpy(clp->cl_name.data, name.data, name.len); | ||
1044 | clp->cl_name.len = name.len; | 900 | clp->cl_name.len = name.len; |
1045 | return clp; | 901 | return clp; |
1046 | } | 902 | } |
@@ -1048,17 +904,16 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) | |||
1048 | static inline void | 904 | static inline void |
1049 | free_client(struct nfs4_client *clp) | 905 | free_client(struct nfs4_client *clp) |
1050 | { | 906 | { |
1051 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
1052 | |||
1053 | lockdep_assert_held(&nn->client_lock); | ||
1054 | while (!list_empty(&clp->cl_sessions)) { | 907 | while (!list_empty(&clp->cl_sessions)) { |
1055 | struct nfsd4_session *ses; | 908 | struct nfsd4_session *ses; |
1056 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | 909 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, |
1057 | se_perclnt); | 910 | se_perclnt); |
1058 | list_del(&ses->se_perclnt); | 911 | list_del(&ses->se_perclnt); |
1059 | nfsd4_put_session_locked(ses); | 912 | nfsd4_put_session(ses); |
1060 | } | 913 | } |
1061 | free_svc_cred(&clp->cl_cred); | 914 | if (clp->cl_cred.cr_group_info) |
915 | put_group_info(clp->cl_cred.cr_group_info); | ||
916 | kfree(clp->cl_principal); | ||
1062 | kfree(clp->cl_name.data); | 917 | kfree(clp->cl_name.data); |
1063 | kfree(clp); | 918 | kfree(clp); |
1064 | } | 919 | } |
@@ -1067,16 +922,15 @@ void | |||
1067 | release_session_client(struct nfsd4_session *session) | 922 | release_session_client(struct nfsd4_session *session) |
1068 | { | 923 | { |
1069 | struct nfs4_client *clp = session->se_client; | 924 | struct nfs4_client *clp = session->se_client; |
1070 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
1071 | 925 | ||
1072 | if (!atomic_dec_and_lock(&clp->cl_refcount, &nn->client_lock)) | 926 | if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock)) |
1073 | return; | 927 | return; |
1074 | if (is_client_expired(clp)) { | 928 | if (is_client_expired(clp)) { |
1075 | free_client(clp); | 929 | free_client(clp); |
1076 | session->se_client = NULL; | 930 | session->se_client = NULL; |
1077 | } else | 931 | } else |
1078 | renew_client_locked(clp); | 932 | renew_client_locked(clp); |
1079 | spin_unlock(&nn->client_lock); | 933 | spin_unlock(&client_lock); |
1080 | } | 934 | } |
1081 | 935 | ||
1082 | /* must be called under the client_lock */ | 936 | /* must be called under the client_lock */ |
@@ -1094,12 +948,11 @@ unhash_client_locked(struct nfs4_client *clp) | |||
1094 | } | 948 | } |
1095 | 949 | ||
1096 | static void | 950 | static void |
1097 | destroy_client(struct nfs4_client *clp) | 951 | expire_client(struct nfs4_client *clp) |
1098 | { | 952 | { |
1099 | struct nfs4_openowner *oo; | 953 | struct nfs4_stateowner *sop; |
1100 | struct nfs4_delegation *dp; | 954 | struct nfs4_delegation *dp; |
1101 | struct list_head reaplist; | 955 | struct list_head reaplist; |
1102 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
1103 | 956 | ||
1104 | INIT_LIST_HEAD(&reaplist); | 957 | INIT_LIST_HEAD(&reaplist); |
1105 | spin_lock(&recall_lock); | 958 | spin_lock(&recall_lock); |
@@ -1111,31 +964,23 @@ destroy_client(struct nfs4_client *clp) | |||
1111 | spin_unlock(&recall_lock); | 964 | spin_unlock(&recall_lock); |
1112 | while (!list_empty(&reaplist)) { | 965 | while (!list_empty(&reaplist)) { |
1113 | dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); | 966 | dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); |
967 | list_del_init(&dp->dl_recall_lru); | ||
1114 | unhash_delegation(dp); | 968 | unhash_delegation(dp); |
1115 | } | 969 | } |
1116 | while (!list_empty(&clp->cl_openowners)) { | 970 | while (!list_empty(&clp->cl_openowners)) { |
1117 | oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); | 971 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); |
1118 | release_openowner(oo); | 972 | release_openowner(sop); |
1119 | } | 973 | } |
1120 | nfsd4_shutdown_callback(clp); | 974 | nfsd4_shutdown_callback(clp); |
1121 | if (clp->cl_cb_conn.cb_xprt) | 975 | if (clp->cl_cb_conn.cb_xprt) |
1122 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); | 976 | svc_xprt_put(clp->cl_cb_conn.cb_xprt); |
1123 | list_del(&clp->cl_idhash); | 977 | list_del(&clp->cl_idhash); |
1124 | if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) | 978 | list_del(&clp->cl_strhash); |
1125 | rb_erase(&clp->cl_namenode, &nn->conf_name_tree); | 979 | spin_lock(&client_lock); |
1126 | else | ||
1127 | rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); | ||
1128 | spin_lock(&nn->client_lock); | ||
1129 | unhash_client_locked(clp); | 980 | unhash_client_locked(clp); |
1130 | if (atomic_read(&clp->cl_refcount) == 0) | 981 | if (atomic_read(&clp->cl_refcount) == 0) |
1131 | free_client(clp); | 982 | free_client(clp); |
1132 | spin_unlock(&nn->client_lock); | 983 | spin_unlock(&client_lock); |
1133 | } | ||
1134 | |||
1135 | static void expire_client(struct nfs4_client *clp) | ||
1136 | { | ||
1137 | nfsd4_client_record_remove(clp); | ||
1138 | destroy_client(clp); | ||
1139 | } | 984 | } |
1140 | 985 | ||
1141 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) | 986 | static void copy_verf(struct nfs4_client *target, nfs4_verifier *source) |
@@ -1150,32 +995,12 @@ static void copy_clid(struct nfs4_client *target, struct nfs4_client *source) | |||
1150 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; | 995 | target->cl_clientid.cl_id = source->cl_clientid.cl_id; |
1151 | } | 996 | } |
1152 | 997 | ||
1153 | static int copy_cred(struct svc_cred *target, struct svc_cred *source) | 998 | static void copy_cred(struct svc_cred *target, struct svc_cred *source) |
1154 | { | 999 | { |
1155 | if (source->cr_principal) { | ||
1156 | target->cr_principal = | ||
1157 | kstrdup(source->cr_principal, GFP_KERNEL); | ||
1158 | if (target->cr_principal == NULL) | ||
1159 | return -ENOMEM; | ||
1160 | } else | ||
1161 | target->cr_principal = NULL; | ||
1162 | target->cr_flavor = source->cr_flavor; | ||
1163 | target->cr_uid = source->cr_uid; | 1000 | target->cr_uid = source->cr_uid; |
1164 | target->cr_gid = source->cr_gid; | 1001 | target->cr_gid = source->cr_gid; |
1165 | target->cr_group_info = source->cr_group_info; | 1002 | target->cr_group_info = source->cr_group_info; |
1166 | get_group_info(target->cr_group_info); | 1003 | get_group_info(target->cr_group_info); |
1167 | return 0; | ||
1168 | } | ||
1169 | |||
1170 | static long long | ||
1171 | compare_blob(const struct xdr_netobj *o1, const struct xdr_netobj *o2) | ||
1172 | { | ||
1173 | long long res; | ||
1174 | |||
1175 | res = o1->len - o2->len; | ||
1176 | if (res) | ||
1177 | return res; | ||
1178 | return (long long)memcmp(o1->data, o2->data, o1->len); | ||
1179 | } | 1004 | } |
1180 | 1005 | ||
1181 | static int same_name(const char *n1, const char *n2) | 1006 | static int same_name(const char *n1, const char *n2) |
@@ -1195,176 +1020,95 @@ same_clid(clientid_t *cl1, clientid_t *cl2) | |||
1195 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); | 1020 | return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id); |
1196 | } | 1021 | } |
1197 | 1022 | ||
1198 | static bool groups_equal(struct group_info *g1, struct group_info *g2) | 1023 | /* XXX what about NGROUP */ |
1199 | { | 1024 | static int |
1200 | int i; | ||
1201 | |||
1202 | if (g1->ngroups != g2->ngroups) | ||
1203 | return false; | ||
1204 | for (i=0; i<g1->ngroups; i++) | ||
1205 | if (GROUP_AT(g1, i) != GROUP_AT(g2, i)) | ||
1206 | return false; | ||
1207 | return true; | ||
1208 | } | ||
1209 | |||
1210 | /* | ||
1211 | * RFC 3530 language requires clid_inuse be returned when the | ||
1212 | * "principal" associated with a requests differs from that previously | ||
1213 | * used. We use uid, gid's, and gss principal string as our best | ||
1214 | * approximation. We also don't want to allow non-gss use of a client | ||
1215 | * established using gss: in theory cr_principal should catch that | ||
1216 | * change, but in practice cr_principal can be null even in the gss case | ||
1217 | * since gssd doesn't always pass down a principal string. | ||
1218 | */ | ||
1219 | static bool is_gss_cred(struct svc_cred *cr) | ||
1220 | { | ||
1221 | /* Is cr_flavor one of the gss "pseudoflavors"?: */ | ||
1222 | return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); | ||
1223 | } | ||
1224 | |||
1225 | |||
1226 | static bool | ||
1227 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) | 1025 | same_creds(struct svc_cred *cr1, struct svc_cred *cr2) |
1228 | { | 1026 | { |
1229 | if ((is_gss_cred(cr1) != is_gss_cred(cr2)) | 1027 | return cr1->cr_uid == cr2->cr_uid; |
1230 | || (cr1->cr_uid != cr2->cr_uid) | ||
1231 | || (cr1->cr_gid != cr2->cr_gid) | ||
1232 | || !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) | ||
1233 | return false; | ||
1234 | if (cr1->cr_principal == cr2->cr_principal) | ||
1235 | return true; | ||
1236 | if (!cr1->cr_principal || !cr2->cr_principal) | ||
1237 | return false; | ||
1238 | return 0 == strcmp(cr1->cr_principal, cr2->cr_principal); | ||
1239 | } | 1028 | } |
1240 | 1029 | ||
1241 | static void gen_clid(struct nfs4_client *clp, struct nfsd_net *nn) | 1030 | static void gen_clid(struct nfs4_client *clp) |
1242 | { | 1031 | { |
1243 | static u32 current_clientid = 1; | 1032 | static u32 current_clientid = 1; |
1244 | 1033 | ||
1245 | clp->cl_clientid.cl_boot = nn->boot_time; | 1034 | clp->cl_clientid.cl_boot = boot_time; |
1246 | clp->cl_clientid.cl_id = current_clientid++; | 1035 | clp->cl_clientid.cl_id = current_clientid++; |
1247 | } | 1036 | } |
1248 | 1037 | ||
1249 | static void gen_confirm(struct nfs4_client *clp) | 1038 | static void gen_confirm(struct nfs4_client *clp) |
1250 | { | 1039 | { |
1251 | __be32 verf[2]; | ||
1252 | static u32 i; | 1040 | static u32 i; |
1041 | u32 *p; | ||
1253 | 1042 | ||
1254 | verf[0] = (__be32)get_seconds(); | 1043 | p = (u32 *)clp->cl_confirm.data; |
1255 | verf[1] = (__be32)i++; | 1044 | *p++ = get_seconds(); |
1256 | memcpy(clp->cl_confirm.data, verf, sizeof(clp->cl_confirm.data)); | 1045 | *p++ = i++; |
1257 | } | ||
1258 | |||
1259 | static struct nfs4_stid *find_stateid(struct nfs4_client *cl, stateid_t *t) | ||
1260 | { | ||
1261 | return idr_find(&cl->cl_stateids, t->si_opaque.so_id); | ||
1262 | } | ||
1263 | |||
1264 | static struct nfs4_stid *find_stateid_by_type(struct nfs4_client *cl, stateid_t *t, char typemask) | ||
1265 | { | ||
1266 | struct nfs4_stid *s; | ||
1267 | |||
1268 | s = find_stateid(cl, t); | ||
1269 | if (!s) | ||
1270 | return NULL; | ||
1271 | if (typemask & s->sc_type) | ||
1272 | return s; | ||
1273 | return NULL; | ||
1274 | } | 1046 | } |
1275 | 1047 | ||
1276 | static struct nfs4_client *create_client(struct xdr_netobj name, | 1048 | static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir, |
1277 | struct svc_rqst *rqstp, nfs4_verifier *verf) | 1049 | struct svc_rqst *rqstp, nfs4_verifier *verf) |
1278 | { | 1050 | { |
1279 | struct nfs4_client *clp; | 1051 | struct nfs4_client *clp; |
1280 | struct sockaddr *sa = svc_addr(rqstp); | 1052 | struct sockaddr *sa = svc_addr(rqstp); |
1281 | int ret; | 1053 | char *princ; |
1282 | struct net *net = SVC_NET(rqstp); | ||
1283 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
1284 | 1054 | ||
1285 | clp = alloc_client(name); | 1055 | clp = alloc_client(name); |
1286 | if (clp == NULL) | 1056 | if (clp == NULL) |
1287 | return NULL; | 1057 | return NULL; |
1288 | 1058 | ||
1289 | INIT_LIST_HEAD(&clp->cl_sessions); | 1059 | INIT_LIST_HEAD(&clp->cl_sessions); |
1290 | ret = copy_cred(&clp->cl_cred, &rqstp->rq_cred); | 1060 | |
1291 | if (ret) { | 1061 | princ = svc_gss_principal(rqstp); |
1292 | spin_lock(&nn->client_lock); | 1062 | if (princ) { |
1293 | free_client(clp); | 1063 | clp->cl_principal = kstrdup(princ, GFP_KERNEL); |
1294 | spin_unlock(&nn->client_lock); | 1064 | if (clp->cl_principal == NULL) { |
1295 | return NULL; | 1065 | free_client(clp); |
1066 | return NULL; | ||
1067 | } | ||
1296 | } | 1068 | } |
1297 | idr_init(&clp->cl_stateids); | 1069 | |
1070 | memcpy(clp->cl_recdir, recdir, HEXDIR_LEN); | ||
1298 | atomic_set(&clp->cl_refcount, 0); | 1071 | atomic_set(&clp->cl_refcount, 0); |
1299 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; | 1072 | clp->cl_cb_state = NFSD4_CB_UNKNOWN; |
1300 | INIT_LIST_HEAD(&clp->cl_idhash); | 1073 | INIT_LIST_HEAD(&clp->cl_idhash); |
1074 | INIT_LIST_HEAD(&clp->cl_strhash); | ||
1301 | INIT_LIST_HEAD(&clp->cl_openowners); | 1075 | INIT_LIST_HEAD(&clp->cl_openowners); |
1302 | INIT_LIST_HEAD(&clp->cl_delegations); | 1076 | INIT_LIST_HEAD(&clp->cl_delegations); |
1303 | INIT_LIST_HEAD(&clp->cl_lru); | 1077 | INIT_LIST_HEAD(&clp->cl_lru); |
1304 | INIT_LIST_HEAD(&clp->cl_callbacks); | 1078 | INIT_LIST_HEAD(&clp->cl_callbacks); |
1305 | spin_lock_init(&clp->cl_lock); | 1079 | spin_lock_init(&clp->cl_lock); |
1306 | nfsd4_init_callback(&clp->cl_cb_null); | 1080 | INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); |
1307 | clp->cl_time = get_seconds(); | 1081 | clp->cl_time = get_seconds(); |
1308 | clear_bit(0, &clp->cl_cb_slot_busy); | 1082 | clear_bit(0, &clp->cl_cb_slot_busy); |
1309 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); | 1083 | rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table"); |
1310 | copy_verf(clp, verf); | 1084 | copy_verf(clp, verf); |
1311 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); | 1085 | rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa); |
1086 | clp->cl_flavor = rqstp->rq_flavor; | ||
1087 | copy_cred(&clp->cl_cred, &rqstp->rq_cred); | ||
1312 | gen_confirm(clp); | 1088 | gen_confirm(clp); |
1313 | clp->cl_cb_session = NULL; | 1089 | clp->cl_cb_session = NULL; |
1314 | clp->net = net; | ||
1315 | return clp; | 1090 | return clp; |
1316 | } | 1091 | } |
1317 | 1092 | ||
1318 | static void | 1093 | static int check_name(struct xdr_netobj name) |
1319 | add_clp_to_name_tree(struct nfs4_client *new_clp, struct rb_root *root) | ||
1320 | { | ||
1321 | struct rb_node **new = &(root->rb_node), *parent = NULL; | ||
1322 | struct nfs4_client *clp; | ||
1323 | |||
1324 | while (*new) { | ||
1325 | clp = rb_entry(*new, struct nfs4_client, cl_namenode); | ||
1326 | parent = *new; | ||
1327 | |||
1328 | if (compare_blob(&clp->cl_name, &new_clp->cl_name) > 0) | ||
1329 | new = &((*new)->rb_left); | ||
1330 | else | ||
1331 | new = &((*new)->rb_right); | ||
1332 | } | ||
1333 | |||
1334 | rb_link_node(&new_clp->cl_namenode, parent, new); | ||
1335 | rb_insert_color(&new_clp->cl_namenode, root); | ||
1336 | } | ||
1337 | |||
1338 | static struct nfs4_client * | ||
1339 | find_clp_in_name_tree(struct xdr_netobj *name, struct rb_root *root) | ||
1340 | { | 1094 | { |
1341 | long long cmp; | 1095 | if (name.len == 0) |
1342 | struct rb_node *node = root->rb_node; | 1096 | return 0; |
1343 | struct nfs4_client *clp; | 1097 | if (name.len > NFS4_OPAQUE_LIMIT) { |
1344 | 1098 | dprintk("NFSD: check_name: name too long(%d)!\n", name.len); | |
1345 | while (node) { | 1099 | return 0; |
1346 | clp = rb_entry(node, struct nfs4_client, cl_namenode); | ||
1347 | cmp = compare_blob(&clp->cl_name, name); | ||
1348 | if (cmp > 0) | ||
1349 | node = node->rb_left; | ||
1350 | else if (cmp < 0) | ||
1351 | node = node->rb_right; | ||
1352 | else | ||
1353 | return clp; | ||
1354 | } | 1100 | } |
1355 | return NULL; | 1101 | return 1; |
1356 | } | 1102 | } |
1357 | 1103 | ||
1358 | static void | 1104 | static void |
1359 | add_to_unconfirmed(struct nfs4_client *clp) | 1105 | add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval) |
1360 | { | 1106 | { |
1361 | unsigned int idhashval; | 1107 | unsigned int idhashval; |
1362 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
1363 | 1108 | ||
1364 | clear_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); | 1109 | list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]); |
1365 | add_clp_to_name_tree(clp, &nn->unconf_name_tree); | ||
1366 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 1110 | idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
1367 | list_add(&clp->cl_idhash, &nn->unconf_id_hashtbl[idhashval]); | 1111 | list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]); |
1368 | renew_client(clp); | 1112 | renew_client(clp); |
1369 | } | 1113 | } |
1370 | 1114 | ||
@@ -1372,45 +1116,37 @@ static void | |||
1372 | move_to_confirmed(struct nfs4_client *clp) | 1116 | move_to_confirmed(struct nfs4_client *clp) |
1373 | { | 1117 | { |
1374 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); | 1118 | unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id); |
1375 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | 1119 | unsigned int strhashval; |
1376 | 1120 | ||
1377 | dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); | 1121 | dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); |
1378 | list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); | 1122 | list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]); |
1379 | rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); | 1123 | strhashval = clientstr_hashval(clp->cl_recdir); |
1380 | add_clp_to_name_tree(clp, &nn->conf_name_tree); | 1124 | list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]); |
1381 | set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); | ||
1382 | renew_client(clp); | 1125 | renew_client(clp); |
1383 | } | 1126 | } |
1384 | 1127 | ||
1385 | static struct nfs4_client * | 1128 | static struct nfs4_client * |
1386 | find_confirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) | 1129 | find_confirmed_client(clientid_t *clid) |
1387 | { | 1130 | { |
1388 | struct nfs4_client *clp; | 1131 | struct nfs4_client *clp; |
1389 | unsigned int idhashval = clientid_hashval(clid->cl_id); | 1132 | unsigned int idhashval = clientid_hashval(clid->cl_id); |
1390 | 1133 | ||
1391 | list_for_each_entry(clp, &nn->conf_id_hashtbl[idhashval], cl_idhash) { | 1134 | list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) { |
1392 | if (same_clid(&clp->cl_clientid, clid)) { | 1135 | if (same_clid(&clp->cl_clientid, clid)) |
1393 | if ((bool)clp->cl_minorversion != sessions) | ||
1394 | return NULL; | ||
1395 | renew_client(clp); | ||
1396 | return clp; | 1136 | return clp; |
1397 | } | ||
1398 | } | 1137 | } |
1399 | return NULL; | 1138 | return NULL; |
1400 | } | 1139 | } |
1401 | 1140 | ||
1402 | static struct nfs4_client * | 1141 | static struct nfs4_client * |
1403 | find_unconfirmed_client(clientid_t *clid, bool sessions, struct nfsd_net *nn) | 1142 | find_unconfirmed_client(clientid_t *clid) |
1404 | { | 1143 | { |
1405 | struct nfs4_client *clp; | 1144 | struct nfs4_client *clp; |
1406 | unsigned int idhashval = clientid_hashval(clid->cl_id); | 1145 | unsigned int idhashval = clientid_hashval(clid->cl_id); |
1407 | 1146 | ||
1408 | list_for_each_entry(clp, &nn->unconf_id_hashtbl[idhashval], cl_idhash) { | 1147 | list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { |
1409 | if (same_clid(&clp->cl_clientid, clid)) { | 1148 | if (same_clid(&clp->cl_clientid, clid)) |
1410 | if ((bool)clp->cl_minorversion != sessions) | ||
1411 | return NULL; | ||
1412 | return clp; | 1149 | return clp; |
1413 | } | ||
1414 | } | 1150 | } |
1415 | return NULL; | 1151 | return NULL; |
1416 | } | 1152 | } |
@@ -1421,15 +1157,41 @@ static bool clp_used_exchangeid(struct nfs4_client *clp) | |||
1421 | } | 1157 | } |
1422 | 1158 | ||
1423 | static struct nfs4_client * | 1159 | static struct nfs4_client * |
1424 | find_confirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) | 1160 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) |
1425 | { | 1161 | { |
1426 | return find_clp_in_name_tree(name, &nn->conf_name_tree); | 1162 | struct nfs4_client *clp; |
1163 | |||
1164 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | ||
1165 | if (same_name(clp->cl_recdir, dname)) | ||
1166 | return clp; | ||
1167 | } | ||
1168 | return NULL; | ||
1427 | } | 1169 | } |
1428 | 1170 | ||
1429 | static struct nfs4_client * | 1171 | static struct nfs4_client * |
1430 | find_unconfirmed_client_by_name(struct xdr_netobj *name, struct nfsd_net *nn) | 1172 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) |
1431 | { | 1173 | { |
1432 | return find_clp_in_name_tree(name, &nn->unconf_name_tree); | 1174 | struct nfs4_client *clp; |
1175 | |||
1176 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | ||
1177 | if (same_name(clp->cl_recdir, dname)) | ||
1178 | return clp; | ||
1179 | } | ||
1180 | return NULL; | ||
1181 | } | ||
1182 | |||
1183 | static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr) | ||
1184 | { | ||
1185 | switch (family) { | ||
1186 | case AF_INET: | ||
1187 | ((struct sockaddr_in *)sa)->sin_family = AF_INET; | ||
1188 | ((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr; | ||
1189 | return; | ||
1190 | case AF_INET6: | ||
1191 | ((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6; | ||
1192 | ((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6; | ||
1193 | return; | ||
1194 | } | ||
1433 | } | 1195 | } |
1434 | 1196 | ||
1435 | static void | 1197 | static void |
@@ -1450,7 +1212,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r | |||
1450 | else | 1212 | else |
1451 | goto out_err; | 1213 | goto out_err; |
1452 | 1214 | ||
1453 | conn->cb_addrlen = rpc_uaddr2sockaddr(clp->net, se->se_callback_addr_val, | 1215 | conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val, |
1454 | se->se_callback_addr_len, | 1216 | se->se_callback_addr_len, |
1455 | (struct sockaddr *)&conn->cb_addr, | 1217 | (struct sockaddr *)&conn->cb_addr, |
1456 | sizeof(conn->cb_addr)); | 1218 | sizeof(conn->cb_addr)); |
@@ -1463,7 +1225,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r | |||
1463 | 1225 | ||
1464 | conn->cb_prog = se->se_callback_prog; | 1226 | conn->cb_prog = se->se_callback_prog; |
1465 | conn->cb_ident = se->se_callback_ident; | 1227 | conn->cb_ident = se->se_callback_ident; |
1466 | memcpy(&conn->cb_saddr, &rqstp->rq_daddr, rqstp->rq_daddrlen); | 1228 | rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr); |
1467 | return; | 1229 | return; |
1468 | out_err: | 1230 | out_err: |
1469 | conn->cb_addr.ss_family = AF_UNSPEC; | 1231 | conn->cb_addr.ss_family = AF_UNSPEC; |
@@ -1489,7 +1251,6 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) | |||
1489 | slot->sl_opcnt = resp->opcnt; | 1251 | slot->sl_opcnt = resp->opcnt; |
1490 | slot->sl_status = resp->cstate.status; | 1252 | slot->sl_status = resp->cstate.status; |
1491 | 1253 | ||
1492 | slot->sl_flags |= NFSD4_SLOT_INITIALIZED; | ||
1493 | if (nfsd4_not_cached(resp)) { | 1254 | if (nfsd4_not_cached(resp)) { |
1494 | slot->sl_datalen = 0; | 1255 | slot->sl_datalen = 0; |
1495 | return; | 1256 | return; |
@@ -1517,12 +1278,15 @@ nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args, | |||
1517 | struct nfsd4_op *op; | 1278 | struct nfsd4_op *op; |
1518 | struct nfsd4_slot *slot = resp->cstate.slot; | 1279 | struct nfsd4_slot *slot = resp->cstate.slot; |
1519 | 1280 | ||
1281 | dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__, | ||
1282 | resp->opcnt, resp->cstate.slot->sl_cachethis); | ||
1283 | |||
1520 | /* Encode the replayed sequence operation */ | 1284 | /* Encode the replayed sequence operation */ |
1521 | op = &args->ops[resp->opcnt - 1]; | 1285 | op = &args->ops[resp->opcnt - 1]; |
1522 | nfsd4_encode_operation(resp, op); | 1286 | nfsd4_encode_operation(resp, op); |
1523 | 1287 | ||
1524 | /* Return nfserr_retry_uncached_rep in next operation. */ | 1288 | /* Return nfserr_retry_uncached_rep in next operation. */ |
1525 | if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) { | 1289 | if (args->opcnt > 1 && slot->sl_cachethis == 0) { |
1526 | op = &args->ops[resp->opcnt++]; | 1290 | op = &args->ops[resp->opcnt++]; |
1527 | op->status = nfserr_retry_uncached_rep; | 1291 | op->status = nfserr_retry_uncached_rep; |
1528 | nfsd4_encode_operation(resp, op); | 1292 | nfsd4_encode_operation(resp, op); |
@@ -1574,31 +1338,18 @@ nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) | |||
1574 | clid->flags = new->cl_exchange_flags; | 1338 | clid->flags = new->cl_exchange_flags; |
1575 | } | 1339 | } |
1576 | 1340 | ||
1577 | static bool client_has_state(struct nfs4_client *clp) | ||
1578 | { | ||
1579 | /* | ||
1580 | * Note clp->cl_openowners check isn't quite right: there's no | ||
1581 | * need to count owners without stateid's. | ||
1582 | * | ||
1583 | * Also note we should probably be using this in 4.0 case too. | ||
1584 | */ | ||
1585 | return !list_empty(&clp->cl_openowners) | ||
1586 | || !list_empty(&clp->cl_delegations) | ||
1587 | || !list_empty(&clp->cl_sessions); | ||
1588 | } | ||
1589 | |||
1590 | __be32 | 1341 | __be32 |
1591 | nfsd4_exchange_id(struct svc_rqst *rqstp, | 1342 | nfsd4_exchange_id(struct svc_rqst *rqstp, |
1592 | struct nfsd4_compound_state *cstate, | 1343 | struct nfsd4_compound_state *cstate, |
1593 | struct nfsd4_exchange_id *exid) | 1344 | struct nfsd4_exchange_id *exid) |
1594 | { | 1345 | { |
1595 | struct nfs4_client *unconf, *conf, *new; | 1346 | struct nfs4_client *unconf, *conf, *new; |
1596 | __be32 status; | 1347 | int status; |
1348 | unsigned int strhashval; | ||
1349 | char dname[HEXDIR_LEN]; | ||
1597 | char addr_str[INET6_ADDRSTRLEN]; | 1350 | char addr_str[INET6_ADDRSTRLEN]; |
1598 | nfs4_verifier verf = exid->verifier; | 1351 | nfs4_verifier verf = exid->verifier; |
1599 | struct sockaddr *sa = svc_addr(rqstp); | 1352 | struct sockaddr *sa = svc_addr(rqstp); |
1600 | bool update = exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A; | ||
1601 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
1602 | 1353 | ||
1603 | rpc_ntop(sa, addr_str, sizeof(addr_str)); | 1354 | rpc_ntop(sa, addr_str, sizeof(addr_str)); |
1604 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | 1355 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " |
@@ -1606,87 +1357,102 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, | |||
1606 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, | 1357 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, |
1607 | addr_str, exid->flags, exid->spa_how); | 1358 | addr_str, exid->flags, exid->spa_how); |
1608 | 1359 | ||
1609 | if (exid->flags & ~EXCHGID4_FLAG_MASK_A) | 1360 | if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A)) |
1610 | return nfserr_inval; | 1361 | return nfserr_inval; |
1611 | 1362 | ||
1612 | /* Currently only support SP4_NONE */ | 1363 | /* Currently only support SP4_NONE */ |
1613 | switch (exid->spa_how) { | 1364 | switch (exid->spa_how) { |
1614 | case SP4_NONE: | 1365 | case SP4_NONE: |
1615 | break; | 1366 | break; |
1616 | default: /* checked by xdr code */ | ||
1617 | WARN_ON_ONCE(1); | ||
1618 | case SP4_SSV: | 1367 | case SP4_SSV: |
1368 | return nfserr_serverfault; | ||
1369 | default: | ||
1370 | BUG(); /* checked by xdr code */ | ||
1619 | case SP4_MACH_CRED: | 1371 | case SP4_MACH_CRED: |
1620 | return nfserr_serverfault; /* no excuse :-/ */ | 1372 | return nfserr_serverfault; /* no excuse :-/ */ |
1621 | } | 1373 | } |
1622 | 1374 | ||
1623 | /* Cases below refer to rfc 5661 section 18.35.4: */ | 1375 | status = nfs4_make_rec_clidname(dname, &exid->clname); |
1376 | |||
1377 | if (status) | ||
1378 | goto error; | ||
1379 | |||
1380 | strhashval = clientstr_hashval(dname); | ||
1381 | |||
1624 | nfs4_lock_state(); | 1382 | nfs4_lock_state(); |
1625 | conf = find_confirmed_client_by_name(&exid->clname, nn); | 1383 | status = nfs_ok; |
1626 | if (conf) { | ||
1627 | bool creds_match = same_creds(&conf->cl_cred, &rqstp->rq_cred); | ||
1628 | bool verfs_match = same_verf(&verf, &conf->cl_verifier); | ||
1629 | 1384 | ||
1630 | if (update) { | 1385 | conf = find_confirmed_client_by_str(dname, strhashval); |
1631 | if (!clp_used_exchangeid(conf)) { /* buggy client */ | 1386 | if (conf) { |
1632 | status = nfserr_inval; | 1387 | if (!clp_used_exchangeid(conf)) { |
1633 | goto out; | 1388 | status = nfserr_clid_inuse; /* XXX: ? */ |
1634 | } | 1389 | goto out; |
1635 | if (!creds_match) { /* case 9 */ | 1390 | } |
1636 | status = nfserr_perm; | 1391 | if (!same_verf(&verf, &conf->cl_verifier)) { |
1637 | goto out; | 1392 | /* 18.35.4 case 8 */ |
1638 | } | 1393 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
1639 | if (!verfs_match) { /* case 8 */ | ||
1640 | status = nfserr_not_same; | 1394 | status = nfserr_not_same; |
1641 | goto out; | 1395 | goto out; |
1642 | } | 1396 | } |
1643 | /* case 6 */ | 1397 | /* Client reboot: destroy old state */ |
1644 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; | 1398 | expire_client(conf); |
1645 | new = conf; | 1399 | goto out_new; |
1646 | goto out_copy; | ||
1647 | } | 1400 | } |
1648 | if (!creds_match) { /* case 3 */ | 1401 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { |
1649 | if (client_has_state(conf)) { | 1402 | /* 18.35.4 case 9 */ |
1650 | status = nfserr_clid_inuse; | 1403 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { |
1404 | status = nfserr_perm; | ||
1651 | goto out; | 1405 | goto out; |
1652 | } | 1406 | } |
1653 | expire_client(conf); | 1407 | expire_client(conf); |
1654 | goto out_new; | 1408 | goto out_new; |
1655 | } | 1409 | } |
1656 | if (verfs_match) { /* case 2 */ | 1410 | /* |
1657 | conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; | 1411 | * Set bit when the owner id and verifier map to an already |
1658 | new = conf; | 1412 | * confirmed client id (18.35.3). |
1659 | goto out_copy; | 1413 | */ |
1660 | } | 1414 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; |
1661 | /* case 5, client reboot */ | 1415 | |
1662 | goto out_new; | 1416 | /* |
1417 | * Falling into 18.35.4 case 2, possible router replay. | ||
1418 | * Leave confirmed record intact and return same result. | ||
1419 | */ | ||
1420 | copy_verf(conf, &verf); | ||
1421 | new = conf; | ||
1422 | goto out_copy; | ||
1663 | } | 1423 | } |
1664 | 1424 | ||
1665 | if (update) { /* case 7 */ | 1425 | /* 18.35.4 case 7 */ |
1426 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
1666 | status = nfserr_noent; | 1427 | status = nfserr_noent; |
1667 | goto out; | 1428 | goto out; |
1668 | } | 1429 | } |
1669 | 1430 | ||
1670 | unconf = find_unconfirmed_client_by_name(&exid->clname, nn); | 1431 | unconf = find_unconfirmed_client_by_str(dname, strhashval); |
1671 | if (unconf) /* case 4, possible retry or client restart */ | 1432 | if (unconf) { |
1433 | /* | ||
1434 | * Possible retry or client restart. Per 18.35.4 case 4, | ||
1435 | * a new unconfirmed record should be generated regardless | ||
1436 | * of whether any properties have changed. | ||
1437 | */ | ||
1672 | expire_client(unconf); | 1438 | expire_client(unconf); |
1439 | } | ||
1673 | 1440 | ||
1674 | /* case 1 (normal case) */ | ||
1675 | out_new: | 1441 | out_new: |
1676 | new = create_client(exid->clname, rqstp, &verf); | 1442 | /* Normal case */ |
1443 | new = create_client(exid->clname, dname, rqstp, &verf); | ||
1677 | if (new == NULL) { | 1444 | if (new == NULL) { |
1678 | status = nfserr_jukebox; | 1445 | status = nfserr_jukebox; |
1679 | goto out; | 1446 | goto out; |
1680 | } | 1447 | } |
1681 | new->cl_minorversion = 1; | ||
1682 | 1448 | ||
1683 | gen_clid(new, nn); | 1449 | gen_clid(new); |
1684 | add_to_unconfirmed(new); | 1450 | add_to_unconfirmed(new, strhashval); |
1685 | out_copy: | 1451 | out_copy: |
1686 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | 1452 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; |
1687 | exid->clientid.cl_id = new->cl_clientid.cl_id; | 1453 | exid->clientid.cl_id = new->cl_clientid.cl_id; |
1688 | 1454 | ||
1689 | exid->seqid = new->cl_cs_slot.sl_seqid + 1; | 1455 | exid->seqid = 1; |
1690 | nfsd4_set_ex_flags(new, exid); | 1456 | nfsd4_set_ex_flags(new, exid); |
1691 | 1457 | ||
1692 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", | 1458 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", |
@@ -1695,10 +1461,12 @@ out_copy: | |||
1695 | 1461 | ||
1696 | out: | 1462 | out: |
1697 | nfs4_unlock_state(); | 1463 | nfs4_unlock_state(); |
1464 | error: | ||
1465 | dprintk("nfsd4_exchange_id returns %d\n", ntohl(status)); | ||
1698 | return status; | 1466 | return status; |
1699 | } | 1467 | } |
1700 | 1468 | ||
1701 | static __be32 | 1469 | static int |
1702 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | 1470 | check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) |
1703 | { | 1471 | { |
1704 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, | 1472 | dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid, |
@@ -1711,11 +1479,16 @@ check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | |||
1711 | else | 1479 | else |
1712 | return nfserr_seq_misordered; | 1480 | return nfserr_seq_misordered; |
1713 | } | 1481 | } |
1714 | /* Note unsigned 32-bit arithmetic handles wraparound: */ | 1482 | /* Normal */ |
1715 | if (likely(seqid == slot_seqid + 1)) | 1483 | if (likely(seqid == slot_seqid + 1)) |
1716 | return nfs_ok; | 1484 | return nfs_ok; |
1485 | /* Replay */ | ||
1717 | if (seqid == slot_seqid) | 1486 | if (seqid == slot_seqid) |
1718 | return nfserr_replay_cache; | 1487 | return nfserr_replay_cache; |
1488 | /* Wraparound */ | ||
1489 | if (seqid == 1 && (slot_seqid + 1) == 0) | ||
1490 | return nfs_ok; | ||
1491 | /* Misordered replay or misordered new request */ | ||
1719 | return nfserr_seq_misordered; | 1492 | return nfserr_seq_misordered; |
1720 | } | 1493 | } |
1721 | 1494 | ||
@@ -1726,7 +1499,7 @@ check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse) | |||
1726 | */ | 1499 | */ |
1727 | static void | 1500 | static void |
1728 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, | 1501 | nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses, |
1729 | struct nfsd4_clid_slot *slot, __be32 nfserr) | 1502 | struct nfsd4_clid_slot *slot, int nfserr) |
1730 | { | 1503 | { |
1731 | slot->sl_status = nfserr; | 1504 | slot->sl_status = nfserr; |
1732 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); | 1505 | memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses)); |
@@ -1757,7 +1530,7 @@ nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses, | |||
1757 | /* seqid, slotID, slotID, slotID, status */ \ | 1530 | /* seqid, slotID, slotID, slotID, status */ \ |
1758 | 5 ) * sizeof(__be32)) | 1531 | 5 ) * sizeof(__be32)) |
1759 | 1532 | ||
1760 | static bool check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) | 1533 | static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel) |
1761 | { | 1534 | { |
1762 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ | 1535 | return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ |
1763 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; | 1536 | || fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ; |
@@ -1771,70 +1544,75 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1771 | struct sockaddr *sa = svc_addr(rqstp); | 1544 | struct sockaddr *sa = svc_addr(rqstp); |
1772 | struct nfs4_client *conf, *unconf; | 1545 | struct nfs4_client *conf, *unconf; |
1773 | struct nfsd4_session *new; | 1546 | struct nfsd4_session *new; |
1774 | struct nfsd4_conn *conn; | ||
1775 | struct nfsd4_clid_slot *cs_slot = NULL; | 1547 | struct nfsd4_clid_slot *cs_slot = NULL; |
1776 | __be32 status = 0; | 1548 | bool confirm_me = false; |
1777 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 1549 | int status = 0; |
1778 | 1550 | ||
1779 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) | 1551 | if (cr_ses->flags & ~SESSION4_FLAG_MASK_A) |
1780 | return nfserr_inval; | 1552 | return nfserr_inval; |
1781 | if (check_forechannel_attrs(cr_ses->fore_channel)) | ||
1782 | return nfserr_toosmall; | ||
1783 | new = alloc_session(&cr_ses->fore_channel, nn); | ||
1784 | if (!new) | ||
1785 | return nfserr_jukebox; | ||
1786 | status = nfserr_jukebox; | ||
1787 | conn = alloc_conn_from_crses(rqstp, cr_ses); | ||
1788 | if (!conn) | ||
1789 | goto out_free_session; | ||
1790 | 1553 | ||
1791 | nfs4_lock_state(); | 1554 | nfs4_lock_state(); |
1792 | unconf = find_unconfirmed_client(&cr_ses->clientid, true, nn); | 1555 | unconf = find_unconfirmed_client(&cr_ses->clientid); |
1793 | conf = find_confirmed_client(&cr_ses->clientid, true, nn); | 1556 | conf = find_confirmed_client(&cr_ses->clientid); |
1794 | 1557 | ||
1795 | if (conf) { | 1558 | if (conf) { |
1796 | cs_slot = &conf->cl_cs_slot; | 1559 | cs_slot = &conf->cl_cs_slot; |
1797 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1560 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1798 | if (status == nfserr_replay_cache) { | 1561 | if (status == nfserr_replay_cache) { |
1562 | dprintk("Got a create_session replay! seqid= %d\n", | ||
1563 | cs_slot->sl_seqid); | ||
1564 | /* Return the cached reply status */ | ||
1799 | status = nfsd4_replay_create_session(cr_ses, cs_slot); | 1565 | status = nfsd4_replay_create_session(cr_ses, cs_slot); |
1800 | goto out_free_conn; | 1566 | goto out; |
1801 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { | 1567 | } else if (cr_ses->seqid != cs_slot->sl_seqid + 1) { |
1802 | status = nfserr_seq_misordered; | 1568 | status = nfserr_seq_misordered; |
1803 | goto out_free_conn; | 1569 | dprintk("Sequence misordered!\n"); |
1570 | dprintk("Expected seqid= %d but got seqid= %d\n", | ||
1571 | cs_slot->sl_seqid, cr_ses->seqid); | ||
1572 | goto out; | ||
1804 | } | 1573 | } |
1805 | } else if (unconf) { | 1574 | } else if (unconf) { |
1806 | struct nfs4_client *old; | ||
1807 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || | 1575 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || |
1808 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { | 1576 | !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { |
1809 | status = nfserr_clid_inuse; | 1577 | status = nfserr_clid_inuse; |
1810 | goto out_free_conn; | 1578 | goto out; |
1811 | } | 1579 | } |
1580 | |||
1812 | cs_slot = &unconf->cl_cs_slot; | 1581 | cs_slot = &unconf->cl_cs_slot; |
1813 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); | 1582 | status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0); |
1814 | if (status) { | 1583 | if (status) { |
1815 | /* an unconfirmed replay returns misordered */ | 1584 | /* an unconfirmed replay returns misordered */ |
1816 | status = nfserr_seq_misordered; | 1585 | status = nfserr_seq_misordered; |
1817 | goto out_free_conn; | 1586 | goto out; |
1818 | } | 1587 | } |
1819 | old = find_confirmed_client_by_name(&unconf->cl_name, nn); | 1588 | |
1820 | if (old) | 1589 | confirm_me = true; |
1821 | expire_client(old); | ||
1822 | move_to_confirmed(unconf); | ||
1823 | conf = unconf; | 1590 | conf = unconf; |
1824 | } else { | 1591 | } else { |
1825 | status = nfserr_stale_clientid; | 1592 | status = nfserr_stale_clientid; |
1826 | goto out_free_conn; | 1593 | goto out; |
1827 | } | 1594 | } |
1828 | status = nfs_ok; | 1595 | |
1596 | /* | ||
1597 | * XXX: we should probably set this at creation time, and check | ||
1598 | * for consistent minorversion use throughout: | ||
1599 | */ | ||
1600 | conf->cl_minorversion = 1; | ||
1829 | /* | 1601 | /* |
1830 | * We do not support RDMA or persistent sessions | 1602 | * We do not support RDMA or persistent sessions |
1831 | */ | 1603 | */ |
1832 | cr_ses->flags &= ~SESSION4_PERSIST; | 1604 | cr_ses->flags &= ~SESSION4_PERSIST; |
1833 | cr_ses->flags &= ~SESSION4_RDMA; | 1605 | cr_ses->flags &= ~SESSION4_RDMA; |
1834 | 1606 | ||
1835 | init_session(rqstp, new, conf, cr_ses); | 1607 | status = nfserr_toosmall; |
1836 | nfsd4_init_conn(rqstp, conn, new); | 1608 | if (check_forechannel_attrs(cr_ses->fore_channel)) |
1609 | goto out; | ||
1837 | 1610 | ||
1611 | status = nfserr_jukebox; | ||
1612 | new = alloc_init_session(rqstp, conf, cr_ses); | ||
1613 | if (!new) | ||
1614 | goto out; | ||
1615 | status = nfs_ok; | ||
1838 | memcpy(cr_ses->sessionid.data, new->se_sessionid.data, | 1616 | memcpy(cr_ses->sessionid.data, new->se_sessionid.data, |
1839 | NFS4_MAX_SESSIONID_LEN); | 1617 | NFS4_MAX_SESSIONID_LEN); |
1840 | memcpy(&cr_ses->fore_channel, &new->se_fchannel, | 1618 | memcpy(&cr_ses->fore_channel, &new->se_fchannel, |
@@ -1844,15 +1622,20 @@ nfsd4_create_session(struct svc_rqst *rqstp, | |||
1844 | 1622 | ||
1845 | /* cache solo and embedded create sessions under the state lock */ | 1623 | /* cache solo and embedded create sessions under the state lock */ |
1846 | nfsd4_cache_create_session(cr_ses, cs_slot, status); | 1624 | nfsd4_cache_create_session(cr_ses, cs_slot, status); |
1625 | if (confirm_me) | ||
1626 | move_to_confirmed(conf); | ||
1847 | out: | 1627 | out: |
1848 | nfs4_unlock_state(); | 1628 | nfs4_unlock_state(); |
1849 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1629 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
1850 | return status; | 1630 | return status; |
1851 | out_free_conn: | 1631 | } |
1852 | free_conn(conn); | 1632 | |
1853 | out_free_session: | 1633 | static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) |
1854 | __free_session(new); | 1634 | { |
1855 | goto out; | 1635 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
1636 | struct nfsd4_compoundargs *argp = rqstp->rq_argp; | ||
1637 | |||
1638 | return argp->opcnt == resp->opcnt; | ||
1856 | } | 1639 | } |
1857 | 1640 | ||
1858 | static __be32 nfsd4_map_bcts_dir(u32 *dir) | 1641 | static __be32 nfsd4_map_bcts_dir(u32 *dir) |
@@ -1869,51 +1652,30 @@ static __be32 nfsd4_map_bcts_dir(u32 *dir) | |||
1869 | return nfserr_inval; | 1652 | return nfserr_inval; |
1870 | } | 1653 | } |
1871 | 1654 | ||
1872 | __be32 nfsd4_backchannel_ctl(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_backchannel_ctl *bc) | ||
1873 | { | ||
1874 | struct nfsd4_session *session = cstate->session; | ||
1875 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
1876 | |||
1877 | spin_lock(&nn->client_lock); | ||
1878 | session->se_cb_prog = bc->bc_cb_program; | ||
1879 | session->se_cb_sec = bc->bc_cb_sec; | ||
1880 | spin_unlock(&nn->client_lock); | ||
1881 | |||
1882 | nfsd4_probe_callback(session->se_client); | ||
1883 | |||
1884 | return nfs_ok; | ||
1885 | } | ||
1886 | |||
1887 | __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, | 1655 | __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp, |
1888 | struct nfsd4_compound_state *cstate, | 1656 | struct nfsd4_compound_state *cstate, |
1889 | struct nfsd4_bind_conn_to_session *bcts) | 1657 | struct nfsd4_bind_conn_to_session *bcts) |
1890 | { | 1658 | { |
1891 | __be32 status; | 1659 | __be32 status; |
1892 | struct nfsd4_conn *conn; | ||
1893 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
1894 | 1660 | ||
1895 | if (!nfsd4_last_compound_op(rqstp)) | 1661 | if (!nfsd4_last_compound_op(rqstp)) |
1896 | return nfserr_not_only_op; | 1662 | return nfserr_not_only_op; |
1897 | spin_lock(&nn->client_lock); | 1663 | spin_lock(&client_lock); |
1898 | cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid, SVC_NET(rqstp)); | 1664 | cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid); |
1899 | /* Sorta weird: we only need the refcnt'ing because new_conn acquires | 1665 | /* Sorta weird: we only need the refcnt'ing because new_conn acquires |
1900 | * client_lock iself: */ | 1666 | * client_lock iself: */ |
1901 | if (cstate->session) { | 1667 | if (cstate->session) { |
1902 | nfsd4_get_session(cstate->session); | 1668 | nfsd4_get_session(cstate->session); |
1903 | atomic_inc(&cstate->session->se_client->cl_refcount); | 1669 | atomic_inc(&cstate->session->se_client->cl_refcount); |
1904 | } | 1670 | } |
1905 | spin_unlock(&nn->client_lock); | 1671 | spin_unlock(&client_lock); |
1906 | if (!cstate->session) | 1672 | if (!cstate->session) |
1907 | return nfserr_badsession; | 1673 | return nfserr_badsession; |
1908 | 1674 | ||
1909 | status = nfsd4_map_bcts_dir(&bcts->dir); | 1675 | status = nfsd4_map_bcts_dir(&bcts->dir); |
1910 | if (status) | 1676 | if (!status) |
1911 | return status; | 1677 | nfsd4_new_conn(rqstp, cstate->session, bcts->dir); |
1912 | conn = alloc_conn(rqstp, bcts->dir); | 1678 | return status; |
1913 | if (!conn) | ||
1914 | return nfserr_jukebox; | ||
1915 | nfsd4_init_conn(rqstp, conn, cstate->session); | ||
1916 | return nfs_ok; | ||
1917 | } | 1679 | } |
1918 | 1680 | ||
1919 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) | 1681 | static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) |
@@ -1929,8 +1691,7 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1929 | struct nfsd4_destroy_session *sessionid) | 1691 | struct nfsd4_destroy_session *sessionid) |
1930 | { | 1692 | { |
1931 | struct nfsd4_session *ses; | 1693 | struct nfsd4_session *ses; |
1932 | __be32 status = nfserr_badsession; | 1694 | u32 status = nfserr_badsession; |
1933 | struct nfsd_net *nn = net_generic(SVC_NET(r), nfsd_net_id); | ||
1934 | 1695 | ||
1935 | /* Notes: | 1696 | /* Notes: |
1936 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid | 1697 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid |
@@ -1944,24 +1705,23 @@ nfsd4_destroy_session(struct svc_rqst *r, | |||
1944 | return nfserr_not_only_op; | 1705 | return nfserr_not_only_op; |
1945 | } | 1706 | } |
1946 | dump_sessionid(__func__, &sessionid->sessionid); | 1707 | dump_sessionid(__func__, &sessionid->sessionid); |
1947 | spin_lock(&nn->client_lock); | 1708 | spin_lock(&client_lock); |
1948 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid, SVC_NET(r)); | 1709 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid); |
1949 | if (!ses) { | 1710 | if (!ses) { |
1950 | spin_unlock(&nn->client_lock); | 1711 | spin_unlock(&client_lock); |
1951 | goto out; | 1712 | goto out; |
1952 | } | 1713 | } |
1953 | 1714 | ||
1954 | unhash_session(ses); | 1715 | unhash_session(ses); |
1955 | spin_unlock(&nn->client_lock); | 1716 | spin_unlock(&client_lock); |
1956 | 1717 | ||
1957 | nfs4_lock_state(); | 1718 | nfs4_lock_state(); |
1958 | nfsd4_probe_callback_sync(ses->se_client); | 1719 | nfsd4_probe_callback_sync(ses->se_client); |
1959 | nfs4_unlock_state(); | 1720 | nfs4_unlock_state(); |
1960 | 1721 | ||
1961 | spin_lock(&nn->client_lock); | ||
1962 | nfsd4_del_conns(ses); | 1722 | nfsd4_del_conns(ses); |
1963 | nfsd4_put_session_locked(ses); | 1723 | |
1964 | spin_unlock(&nn->client_lock); | 1724 | nfsd4_put_session(ses); |
1965 | status = nfs_ok; | 1725 | status = nfs_ok; |
1966 | out: | 1726 | out: |
1967 | dprintk("%s returns %d\n", __func__, ntohl(status)); | 1727 | dprintk("%s returns %d\n", __func__, ntohl(status)); |
@@ -2026,8 +1786,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2026 | struct nfsd4_session *session; | 1786 | struct nfsd4_session *session; |
2027 | struct nfsd4_slot *slot; | 1787 | struct nfsd4_slot *slot; |
2028 | struct nfsd4_conn *conn; | 1788 | struct nfsd4_conn *conn; |
2029 | __be32 status; | 1789 | int status; |
2030 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
2031 | 1790 | ||
2032 | if (resp->opcnt != 1) | 1791 | if (resp->opcnt != 1) |
2033 | return nfserr_sequence_pos; | 1792 | return nfserr_sequence_pos; |
@@ -2040,9 +1799,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2040 | if (!conn) | 1799 | if (!conn) |
2041 | return nfserr_jukebox; | 1800 | return nfserr_jukebox; |
2042 | 1801 | ||
2043 | spin_lock(&nn->client_lock); | 1802 | spin_lock(&client_lock); |
2044 | status = nfserr_badsession; | 1803 | status = nfserr_badsession; |
2045 | session = find_in_sessionid_hashtbl(&seq->sessionid, SVC_NET(rqstp)); | 1804 | session = find_in_sessionid_hashtbl(&seq->sessionid); |
2046 | if (!session) | 1805 | if (!session) |
2047 | goto out; | 1806 | goto out; |
2048 | 1807 | ||
@@ -2066,12 +1825,8 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2066 | * sr_highest_slotid and the sr_target_slot id to maxslots */ | 1825 | * sr_highest_slotid and the sr_target_slot id to maxslots */ |
2067 | seq->maxslots = session->se_fchannel.maxreqs; | 1826 | seq->maxslots = session->se_fchannel.maxreqs; |
2068 | 1827 | ||
2069 | status = check_slot_seqid(seq->seqid, slot->sl_seqid, | 1828 | status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse); |
2070 | slot->sl_flags & NFSD4_SLOT_INUSE); | ||
2071 | if (status == nfserr_replay_cache) { | 1829 | if (status == nfserr_replay_cache) { |
2072 | status = nfserr_seq_misordered; | ||
2073 | if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED)) | ||
2074 | goto out; | ||
2075 | cstate->slot = slot; | 1830 | cstate->slot = slot; |
2076 | cstate->session = session; | 1831 | cstate->session = session; |
2077 | /* Return the cached reply status and set cstate->status | 1832 | /* Return the cached reply status and set cstate->status |
@@ -2087,12 +1842,9 @@ nfsd4_sequence(struct svc_rqst *rqstp, | |||
2087 | conn = NULL; | 1842 | conn = NULL; |
2088 | 1843 | ||
2089 | /* Success! bump slot seqid */ | 1844 | /* Success! bump slot seqid */ |
1845 | slot->sl_inuse = true; | ||
2090 | slot->sl_seqid = seq->seqid; | 1846 | slot->sl_seqid = seq->seqid; |
2091 | slot->sl_flags |= NFSD4_SLOT_INUSE; | 1847 | slot->sl_cachethis = seq->cachethis; |
2092 | if (seq->cachethis) | ||
2093 | slot->sl_flags |= NFSD4_SLOT_CACHETHIS; | ||
2094 | else | ||
2095 | slot->sl_flags &= ~NFSD4_SLOT_CACHETHIS; | ||
2096 | 1848 | ||
2097 | cstate->slot = slot; | 1849 | cstate->slot = slot; |
2098 | cstate->session = session; | 1850 | cstate->session = session; |
@@ -2104,65 +1856,19 @@ out: | |||
2104 | 1856 | ||
2105 | nfsd4_get_session(cstate->session); | 1857 | nfsd4_get_session(cstate->session); |
2106 | atomic_inc(&clp->cl_refcount); | 1858 | atomic_inc(&clp->cl_refcount); |
2107 | switch (clp->cl_cb_state) { | 1859 | if (clp->cl_cb_state == NFSD4_CB_DOWN) |
2108 | case NFSD4_CB_DOWN: | 1860 | seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN; |
2109 | seq->status_flags = SEQ4_STATUS_CB_PATH_DOWN; | ||
2110 | break; | ||
2111 | case NFSD4_CB_FAULT: | ||
2112 | seq->status_flags = SEQ4_STATUS_BACKCHANNEL_FAULT; | ||
2113 | break; | ||
2114 | default: | ||
2115 | seq->status_flags = 0; | ||
2116 | } | ||
2117 | } | 1861 | } |
2118 | kfree(conn); | 1862 | kfree(conn); |
2119 | spin_unlock(&nn->client_lock); | 1863 | spin_unlock(&client_lock); |
2120 | dprintk("%s: return %d\n", __func__, ntohl(status)); | 1864 | dprintk("%s: return %d\n", __func__, ntohl(status)); |
2121 | return status; | 1865 | return status; |
2122 | } | 1866 | } |
2123 | 1867 | ||
2124 | __be32 | 1868 | __be32 |
2125 | nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_destroy_clientid *dc) | ||
2126 | { | ||
2127 | struct nfs4_client *conf, *unconf, *clp; | ||
2128 | __be32 status = 0; | ||
2129 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
2130 | |||
2131 | nfs4_lock_state(); | ||
2132 | unconf = find_unconfirmed_client(&dc->clientid, true, nn); | ||
2133 | conf = find_confirmed_client(&dc->clientid, true, nn); | ||
2134 | |||
2135 | if (conf) { | ||
2136 | clp = conf; | ||
2137 | |||
2138 | if (!is_client_expired(conf) && client_has_state(conf)) { | ||
2139 | status = nfserr_clientid_busy; | ||
2140 | goto out; | ||
2141 | } | ||
2142 | |||
2143 | /* rfc5661 18.50.3 */ | ||
2144 | if (cstate->session && conf == cstate->session->se_client) { | ||
2145 | status = nfserr_clientid_busy; | ||
2146 | goto out; | ||
2147 | } | ||
2148 | } else if (unconf) | ||
2149 | clp = unconf; | ||
2150 | else { | ||
2151 | status = nfserr_stale_clientid; | ||
2152 | goto out; | ||
2153 | } | ||
2154 | |||
2155 | expire_client(clp); | ||
2156 | out: | ||
2157 | nfs4_unlock_state(); | ||
2158 | dprintk("%s return %d\n", __func__, ntohl(status)); | ||
2159 | return status; | ||
2160 | } | ||
2161 | |||
2162 | __be32 | ||
2163 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) | 1869 | nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc) |
2164 | { | 1870 | { |
2165 | __be32 status = 0; | 1871 | int status = 0; |
2166 | 1872 | ||
2167 | if (rc->rca_one_fs) { | 1873 | if (rc->rca_one_fs) { |
2168 | if (!cstate->current_fh.fh_dentry) | 1874 | if (!cstate->current_fh.fh_dentry) |
@@ -2176,8 +1882,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2176 | 1882 | ||
2177 | nfs4_lock_state(); | 1883 | nfs4_lock_state(); |
2178 | status = nfserr_complete_already; | 1884 | status = nfserr_complete_already; |
2179 | if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, | 1885 | if (cstate->session->se_client->cl_firststate) |
2180 | &cstate->session->se_client->cl_flags)) | ||
2181 | goto out; | 1886 | goto out; |
2182 | 1887 | ||
2183 | status = nfserr_stale_clientid; | 1888 | status = nfserr_stale_clientid; |
@@ -2192,7 +1897,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta | |||
2192 | goto out; | 1897 | goto out; |
2193 | 1898 | ||
2194 | status = nfs_ok; | 1899 | status = nfs_ok; |
2195 | nfsd4_client_record_create(cstate->session->se_client); | 1900 | nfsd4_create_clid_dir(cstate->session->se_client); |
2196 | out: | 1901 | out: |
2197 | nfs4_unlock_state(); | 1902 | nfs4_unlock_state(); |
2198 | return status; | 1903 | return status; |
@@ -2202,17 +1907,34 @@ __be32 | |||
2202 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1907 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
2203 | struct nfsd4_setclientid *setclid) | 1908 | struct nfsd4_setclientid *setclid) |
2204 | { | 1909 | { |
2205 | struct xdr_netobj clname = setclid->se_name; | 1910 | struct xdr_netobj clname = { |
1911 | .len = setclid->se_namelen, | ||
1912 | .data = setclid->se_name, | ||
1913 | }; | ||
2206 | nfs4_verifier clverifier = setclid->se_verf; | 1914 | nfs4_verifier clverifier = setclid->se_verf; |
1915 | unsigned int strhashval; | ||
2207 | struct nfs4_client *conf, *unconf, *new; | 1916 | struct nfs4_client *conf, *unconf, *new; |
2208 | __be32 status; | 1917 | __be32 status; |
2209 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 1918 | char dname[HEXDIR_LEN]; |
1919 | |||
1920 | if (!check_name(clname)) | ||
1921 | return nfserr_inval; | ||
1922 | |||
1923 | status = nfs4_make_rec_clidname(dname, &clname); | ||
1924 | if (status) | ||
1925 | return status; | ||
1926 | |||
1927 | /* | ||
1928 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
1929 | * We get here on a DRC miss. | ||
1930 | */ | ||
1931 | |||
1932 | strhashval = clientstr_hashval(dname); | ||
2210 | 1933 | ||
2211 | /* Cases below refer to rfc 3530 section 14.2.33: */ | ||
2212 | nfs4_lock_state(); | 1934 | nfs4_lock_state(); |
2213 | conf = find_confirmed_client_by_name(&clname, nn); | 1935 | conf = find_confirmed_client_by_str(dname, strhashval); |
2214 | if (conf) { | 1936 | if (conf) { |
2215 | /* case 0: */ | 1937 | /* RFC 3530 14.2.33 CASE 0: */ |
2216 | status = nfserr_clid_inuse; | 1938 | status = nfserr_clid_inuse; |
2217 | if (clp_used_exchangeid(conf)) | 1939 | if (clp_used_exchangeid(conf)) |
2218 | goto out; | 1940 | goto out; |
@@ -2225,21 +1947,70 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2225 | goto out; | 1947 | goto out; |
2226 | } | 1948 | } |
2227 | } | 1949 | } |
2228 | unconf = find_unconfirmed_client_by_name(&clname, nn); | 1950 | /* |
2229 | if (unconf) | 1951 | * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION") |
2230 | expire_client(unconf); | 1952 | * has a description of SETCLIENTID request processing consisting |
1953 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | ||
1954 | */ | ||
1955 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | ||
2231 | status = nfserr_jukebox; | 1956 | status = nfserr_jukebox; |
2232 | new = create_client(clname, rqstp, &clverifier); | 1957 | if (!conf) { |
2233 | if (new == NULL) | 1958 | /* |
2234 | goto out; | 1959 | * RFC 3530 14.2.33 CASE 4: |
2235 | if (conf && same_verf(&conf->cl_verifier, &clverifier)) | 1960 | * placed first, because it is the normal case |
2236 | /* case 1: probable callback update */ | 1961 | */ |
1962 | if (unconf) | ||
1963 | expire_client(unconf); | ||
1964 | new = create_client(clname, dname, rqstp, &clverifier); | ||
1965 | if (new == NULL) | ||
1966 | goto out; | ||
1967 | gen_clid(new); | ||
1968 | } else if (same_verf(&conf->cl_verifier, &clverifier)) { | ||
1969 | /* | ||
1970 | * RFC 3530 14.2.33 CASE 1: | ||
1971 | * probable callback update | ||
1972 | */ | ||
1973 | if (unconf) { | ||
1974 | /* Note this is removing unconfirmed {*x***}, | ||
1975 | * which is stronger than RFC recommended {vxc**}. | ||
1976 | * This has the advantage that there is at most | ||
1977 | * one {*x***} in either list at any time. | ||
1978 | */ | ||
1979 | expire_client(unconf); | ||
1980 | } | ||
1981 | new = create_client(clname, dname, rqstp, &clverifier); | ||
1982 | if (new == NULL) | ||
1983 | goto out; | ||
2237 | copy_clid(new, conf); | 1984 | copy_clid(new, conf); |
2238 | else /* case 4 (new client) or cases 2, 3 (client reboot): */ | 1985 | } else if (!unconf) { |
2239 | gen_clid(new, nn); | 1986 | /* |
1987 | * RFC 3530 14.2.33 CASE 2: | ||
1988 | * probable client reboot; state will be removed if | ||
1989 | * confirmed. | ||
1990 | */ | ||
1991 | new = create_client(clname, dname, rqstp, &clverifier); | ||
1992 | if (new == NULL) | ||
1993 | goto out; | ||
1994 | gen_clid(new); | ||
1995 | } else { | ||
1996 | /* | ||
1997 | * RFC 3530 14.2.33 CASE 3: | ||
1998 | * probable client reboot; state will be removed if | ||
1999 | * confirmed. | ||
2000 | */ | ||
2001 | expire_client(unconf); | ||
2002 | new = create_client(clname, dname, rqstp, &clverifier); | ||
2003 | if (new == NULL) | ||
2004 | goto out; | ||
2005 | gen_clid(new); | ||
2006 | } | ||
2007 | /* | ||
2008 | * XXX: we should probably set this at creation time, and check | ||
2009 | * for consistent minorversion use throughout: | ||
2010 | */ | ||
2240 | new->cl_minorversion = 0; | 2011 | new->cl_minorversion = 0; |
2241 | gen_callback(new, setclid, rqstp); | 2012 | gen_callback(new, setclid, rqstp); |
2242 | add_to_unconfirmed(new); | 2013 | add_to_unconfirmed(new, strhashval); |
2243 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; | 2014 | setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot; |
2244 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; | 2015 | setclid->se_clientid.cl_id = new->cl_clientid.cl_id; |
2245 | memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); | 2016 | memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data)); |
@@ -2250,81 +2021,133 @@ out: | |||
2250 | } | 2021 | } |
2251 | 2022 | ||
2252 | 2023 | ||
2024 | /* | ||
2025 | * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has | ||
2026 | * a description of SETCLIENTID_CONFIRM request processing consisting of 4 | ||
2027 | * bullets, labeled as CASE1 - CASE4 below. | ||
2028 | */ | ||
2253 | __be32 | 2029 | __be32 |
2254 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | 2030 | nfsd4_setclientid_confirm(struct svc_rqst *rqstp, |
2255 | struct nfsd4_compound_state *cstate, | 2031 | struct nfsd4_compound_state *cstate, |
2256 | struct nfsd4_setclientid_confirm *setclientid_confirm) | 2032 | struct nfsd4_setclientid_confirm *setclientid_confirm) |
2257 | { | 2033 | { |
2034 | struct sockaddr *sa = svc_addr(rqstp); | ||
2258 | struct nfs4_client *conf, *unconf; | 2035 | struct nfs4_client *conf, *unconf; |
2259 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; | 2036 | nfs4_verifier confirm = setclientid_confirm->sc_confirm; |
2260 | clientid_t * clid = &setclientid_confirm->sc_clientid; | 2037 | clientid_t * clid = &setclientid_confirm->sc_clientid; |
2261 | __be32 status; | 2038 | __be32 status; |
2262 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
2263 | 2039 | ||
2264 | if (STALE_CLIENTID(clid, nn)) | 2040 | if (STALE_CLIENTID(clid)) |
2265 | return nfserr_stale_clientid; | 2041 | return nfserr_stale_clientid; |
2042 | /* | ||
2043 | * XXX The Duplicate Request Cache (DRC) has been checked (??) | ||
2044 | * We get here on a DRC miss. | ||
2045 | */ | ||
2046 | |||
2266 | nfs4_lock_state(); | 2047 | nfs4_lock_state(); |
2267 | 2048 | ||
2268 | conf = find_confirmed_client(clid, false, nn); | 2049 | conf = find_confirmed_client(clid); |
2269 | unconf = find_unconfirmed_client(clid, false, nn); | 2050 | unconf = find_unconfirmed_client(clid); |
2270 | /* | 2051 | |
2271 | * We try hard to give out unique clientid's, so if we get an | 2052 | status = nfserr_clid_inuse; |
2272 | * attempt to confirm the same clientid with a different cred, | 2053 | if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa)) |
2273 | * there's a bug somewhere. Let's charitably assume it's our | ||
2274 | * bug. | ||
2275 | */ | ||
2276 | status = nfserr_serverfault; | ||
2277 | if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) | ||
2278 | goto out; | 2054 | goto out; |
2279 | if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) | 2055 | if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa)) |
2280 | goto out; | 2056 | goto out; |
2281 | /* cases below refer to rfc 3530 section 14.2.34: */ | 2057 | |
2282 | if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { | 2058 | /* |
2283 | if (conf && !unconf) /* case 2: probable retransmit */ | 2059 | * section 14.2.34 of RFC 3530 has a description of |
2060 | * SETCLIENTID_CONFIRM request processing consisting | ||
2061 | * of 4 bullet points, labeled as CASE1 - CASE4 below. | ||
2062 | */ | ||
2063 | if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) { | ||
2064 | /* | ||
2065 | * RFC 3530 14.2.34 CASE 1: | ||
2066 | * callback update | ||
2067 | */ | ||
2068 | if (!same_creds(&conf->cl_cred, &unconf->cl_cred)) | ||
2069 | status = nfserr_clid_inuse; | ||
2070 | else { | ||
2071 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | ||
2072 | nfsd4_probe_callback(conf); | ||
2073 | expire_client(unconf); | ||
2284 | status = nfs_ok; | 2074 | status = nfs_ok; |
2285 | else /* case 4: client hasn't noticed we rebooted yet? */ | 2075 | |
2286 | status = nfserr_stale_clientid; | 2076 | } |
2287 | goto out; | 2077 | } else if (conf && !unconf) { |
2288 | } | 2078 | /* |
2289 | status = nfs_ok; | 2079 | * RFC 3530 14.2.34 CASE 2: |
2290 | if (conf) { /* case 1: callback update */ | 2080 | * probable retransmitted request; play it safe and |
2291 | nfsd4_change_callback(conf, &unconf->cl_cb_conn); | 2081 | * do nothing. |
2292 | nfsd4_probe_callback(conf); | 2082 | */ |
2293 | expire_client(unconf); | 2083 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) |
2294 | } else { /* case 3: normal case; new or rebooted client */ | 2084 | status = nfserr_clid_inuse; |
2295 | conf = find_confirmed_client_by_name(&unconf->cl_name, nn); | 2085 | else |
2296 | if (conf) | 2086 | status = nfs_ok; |
2297 | expire_client(conf); | 2087 | } else if (!conf && unconf |
2298 | move_to_confirmed(unconf); | 2088 | && same_verf(&unconf->cl_confirm, &confirm)) { |
2299 | nfsd4_probe_callback(unconf); | 2089 | /* |
2090 | * RFC 3530 14.2.34 CASE 3: | ||
2091 | * Normal case; new or rebooted client: | ||
2092 | */ | ||
2093 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { | ||
2094 | status = nfserr_clid_inuse; | ||
2095 | } else { | ||
2096 | unsigned int hash = | ||
2097 | clientstr_hashval(unconf->cl_recdir); | ||
2098 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | ||
2099 | hash); | ||
2100 | if (conf) { | ||
2101 | nfsd4_remove_clid_dir(conf); | ||
2102 | expire_client(conf); | ||
2103 | } | ||
2104 | move_to_confirmed(unconf); | ||
2105 | conf = unconf; | ||
2106 | nfsd4_probe_callback(conf); | ||
2107 | status = nfs_ok; | ||
2108 | } | ||
2109 | } else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm))) | ||
2110 | && (!unconf || (unconf && !same_verf(&unconf->cl_confirm, | ||
2111 | &confirm)))) { | ||
2112 | /* | ||
2113 | * RFC 3530 14.2.34 CASE 4: | ||
2114 | * Client probably hasn't noticed that we rebooted yet. | ||
2115 | */ | ||
2116 | status = nfserr_stale_clientid; | ||
2117 | } else { | ||
2118 | /* check that we have hit one of the cases...*/ | ||
2119 | status = nfserr_clid_inuse; | ||
2300 | } | 2120 | } |
2301 | out: | 2121 | out: |
2302 | nfs4_unlock_state(); | 2122 | nfs4_unlock_state(); |
2303 | return status; | 2123 | return status; |
2304 | } | 2124 | } |
2305 | 2125 | ||
2306 | static struct nfs4_file *nfsd4_alloc_file(void) | ||
2307 | { | ||
2308 | return kmem_cache_alloc(file_slab, GFP_KERNEL); | ||
2309 | } | ||
2310 | |||
2311 | /* OPEN Share state helper functions */ | 2126 | /* OPEN Share state helper functions */ |
2312 | static void nfsd4_init_file(struct nfs4_file *fp, struct inode *ino) | 2127 | static inline struct nfs4_file * |
2128 | alloc_init_file(struct inode *ino) | ||
2313 | { | 2129 | { |
2130 | struct nfs4_file *fp; | ||
2314 | unsigned int hashval = file_hashval(ino); | 2131 | unsigned int hashval = file_hashval(ino); |
2315 | 2132 | ||
2316 | atomic_set(&fp->fi_ref, 1); | 2133 | fp = kmem_cache_alloc(file_slab, GFP_KERNEL); |
2317 | INIT_LIST_HEAD(&fp->fi_hash); | 2134 | if (fp) { |
2318 | INIT_LIST_HEAD(&fp->fi_stateids); | 2135 | atomic_set(&fp->fi_ref, 1); |
2319 | INIT_LIST_HEAD(&fp->fi_delegations); | 2136 | INIT_LIST_HEAD(&fp->fi_hash); |
2320 | fp->fi_inode = igrab(ino); | 2137 | INIT_LIST_HEAD(&fp->fi_stateids); |
2321 | fp->fi_had_conflict = false; | 2138 | INIT_LIST_HEAD(&fp->fi_delegations); |
2322 | fp->fi_lease = NULL; | 2139 | fp->fi_inode = igrab(ino); |
2323 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); | 2140 | fp->fi_id = current_fileid++; |
2324 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); | 2141 | fp->fi_had_conflict = false; |
2325 | spin_lock(&recall_lock); | 2142 | fp->fi_lease = NULL; |
2326 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | 2143 | memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); |
2327 | spin_unlock(&recall_lock); | 2144 | memset(fp->fi_access, 0, sizeof(fp->fi_access)); |
2145 | spin_lock(&recall_lock); | ||
2146 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | ||
2147 | spin_unlock(&recall_lock); | ||
2148 | return fp; | ||
2149 | } | ||
2150 | return NULL; | ||
2328 | } | 2151 | } |
2329 | 2152 | ||
2330 | static void | 2153 | static void |
@@ -2339,30 +2162,25 @@ nfsd4_free_slab(struct kmem_cache **slab) | |||
2339 | void | 2162 | void |
2340 | nfsd4_free_slabs(void) | 2163 | nfsd4_free_slabs(void) |
2341 | { | 2164 | { |
2342 | nfsd4_free_slab(&openowner_slab); | 2165 | nfsd4_free_slab(&stateowner_slab); |
2343 | nfsd4_free_slab(&lockowner_slab); | ||
2344 | nfsd4_free_slab(&file_slab); | 2166 | nfsd4_free_slab(&file_slab); |
2345 | nfsd4_free_slab(&stateid_slab); | 2167 | nfsd4_free_slab(&stateid_slab); |
2346 | nfsd4_free_slab(&deleg_slab); | 2168 | nfsd4_free_slab(&deleg_slab); |
2347 | } | 2169 | } |
2348 | 2170 | ||
2349 | int | 2171 | static int |
2350 | nfsd4_init_slabs(void) | 2172 | nfsd4_init_slabs(void) |
2351 | { | 2173 | { |
2352 | openowner_slab = kmem_cache_create("nfsd4_openowners", | 2174 | stateowner_slab = kmem_cache_create("nfsd4_stateowners", |
2353 | sizeof(struct nfs4_openowner), 0, 0, NULL); | 2175 | sizeof(struct nfs4_stateowner), 0, 0, NULL); |
2354 | if (openowner_slab == NULL) | 2176 | if (stateowner_slab == NULL) |
2355 | goto out_nomem; | ||
2356 | lockowner_slab = kmem_cache_create("nfsd4_lockowners", | ||
2357 | sizeof(struct nfs4_lockowner), 0, 0, NULL); | ||
2358 | if (lockowner_slab == NULL) | ||
2359 | goto out_nomem; | 2177 | goto out_nomem; |
2360 | file_slab = kmem_cache_create("nfsd4_files", | 2178 | file_slab = kmem_cache_create("nfsd4_files", |
2361 | sizeof(struct nfs4_file), 0, 0, NULL); | 2179 | sizeof(struct nfs4_file), 0, 0, NULL); |
2362 | if (file_slab == NULL) | 2180 | if (file_slab == NULL) |
2363 | goto out_nomem; | 2181 | goto out_nomem; |
2364 | stateid_slab = kmem_cache_create("nfsd4_stateids", | 2182 | stateid_slab = kmem_cache_create("nfsd4_stateids", |
2365 | sizeof(struct nfs4_ol_stateid), 0, 0, NULL); | 2183 | sizeof(struct nfs4_stateid), 0, 0, NULL); |
2366 | if (stateid_slab == NULL) | 2184 | if (stateid_slab == NULL) |
2367 | goto out_nomem; | 2185 | goto out_nomem; |
2368 | deleg_slab = kmem_cache_create("nfsd4_delegations", | 2186 | deleg_slab = kmem_cache_create("nfsd4_delegations", |
@@ -2376,98 +2194,97 @@ out_nomem: | |||
2376 | return -ENOMEM; | 2194 | return -ENOMEM; |
2377 | } | 2195 | } |
2378 | 2196 | ||
2379 | void nfs4_free_openowner(struct nfs4_openowner *oo) | 2197 | void |
2198 | nfs4_free_stateowner(struct kref *kref) | ||
2380 | { | 2199 | { |
2381 | kfree(oo->oo_owner.so_owner.data); | 2200 | struct nfs4_stateowner *sop = |
2382 | kmem_cache_free(openowner_slab, oo); | 2201 | container_of(kref, struct nfs4_stateowner, so_ref); |
2202 | kfree(sop->so_owner.data); | ||
2203 | kmem_cache_free(stateowner_slab, sop); | ||
2383 | } | 2204 | } |
2384 | 2205 | ||
2385 | void nfs4_free_lockowner(struct nfs4_lockowner *lo) | 2206 | static inline struct nfs4_stateowner * |
2207 | alloc_stateowner(struct xdr_netobj *owner) | ||
2386 | { | 2208 | { |
2387 | kfree(lo->lo_owner.so_owner.data); | 2209 | struct nfs4_stateowner *sop; |
2388 | kmem_cache_free(lockowner_slab, lo); | ||
2389 | } | ||
2390 | 2210 | ||
2391 | static void init_nfs4_replay(struct nfs4_replay *rp) | 2211 | if ((sop = kmem_cache_alloc(stateowner_slab, GFP_KERNEL))) { |
2392 | { | 2212 | if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) { |
2393 | rp->rp_status = nfserr_serverfault; | 2213 | memcpy(sop->so_owner.data, owner->data, owner->len); |
2394 | rp->rp_buflen = 0; | 2214 | sop->so_owner.len = owner->len; |
2395 | rp->rp_buf = rp->rp_ibuf; | 2215 | kref_init(&sop->so_ref); |
2216 | return sop; | ||
2217 | } | ||
2218 | kmem_cache_free(stateowner_slab, sop); | ||
2219 | } | ||
2220 | return NULL; | ||
2396 | } | 2221 | } |
2397 | 2222 | ||
2398 | static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp) | 2223 | static struct nfs4_stateowner * |
2399 | { | 2224 | alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) { |
2400 | struct nfs4_stateowner *sop; | 2225 | struct nfs4_stateowner *sop; |
2226 | struct nfs4_replay *rp; | ||
2227 | unsigned int idhashval; | ||
2401 | 2228 | ||
2402 | sop = kmem_cache_alloc(slab, GFP_KERNEL); | 2229 | if (!(sop = alloc_stateowner(&open->op_owner))) |
2403 | if (!sop) | ||
2404 | return NULL; | ||
2405 | |||
2406 | sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL); | ||
2407 | if (!sop->so_owner.data) { | ||
2408 | kmem_cache_free(slab, sop); | ||
2409 | return NULL; | 2230 | return NULL; |
2410 | } | 2231 | idhashval = ownerid_hashval(current_ownerid); |
2411 | sop->so_owner.len = owner->len; | 2232 | INIT_LIST_HEAD(&sop->so_idhash); |
2412 | 2233 | INIT_LIST_HEAD(&sop->so_strhash); | |
2234 | INIT_LIST_HEAD(&sop->so_perclient); | ||
2413 | INIT_LIST_HEAD(&sop->so_stateids); | 2235 | INIT_LIST_HEAD(&sop->so_stateids); |
2236 | INIT_LIST_HEAD(&sop->so_perstateid); /* not used */ | ||
2237 | INIT_LIST_HEAD(&sop->so_close_lru); | ||
2238 | sop->so_time = 0; | ||
2239 | list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]); | ||
2240 | list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]); | ||
2241 | list_add(&sop->so_perclient, &clp->cl_openowners); | ||
2242 | sop->so_is_open_owner = 1; | ||
2243 | sop->so_id = current_ownerid++; | ||
2414 | sop->so_client = clp; | 2244 | sop->so_client = clp; |
2415 | init_nfs4_replay(&sop->so_replay); | 2245 | sop->so_seqid = open->op_seqid; |
2246 | sop->so_confirmed = 0; | ||
2247 | rp = &sop->so_replay; | ||
2248 | rp->rp_status = nfserr_serverfault; | ||
2249 | rp->rp_buflen = 0; | ||
2250 | rp->rp_buf = rp->rp_ibuf; | ||
2416 | return sop; | 2251 | return sop; |
2417 | } | 2252 | } |
2418 | 2253 | ||
2419 | static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval) | 2254 | static inline void |
2420 | { | 2255 | init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { |
2421 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | 2256 | struct nfs4_stateowner *sop = open->op_stateowner; |
2422 | 2257 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); | |
2423 | list_add(&oo->oo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); | ||
2424 | list_add(&oo->oo_perclient, &clp->cl_openowners); | ||
2425 | } | ||
2426 | |||
2427 | static struct nfs4_openowner * | ||
2428 | alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) { | ||
2429 | struct nfs4_openowner *oo; | ||
2430 | |||
2431 | oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); | ||
2432 | if (!oo) | ||
2433 | return NULL; | ||
2434 | oo->oo_owner.so_is_open_owner = 1; | ||
2435 | oo->oo_owner.so_seqid = open->op_seqid; | ||
2436 | oo->oo_flags = NFS4_OO_NEW; | ||
2437 | oo->oo_time = 0; | ||
2438 | oo->oo_last_closed_stid = NULL; | ||
2439 | INIT_LIST_HEAD(&oo->oo_close_lru); | ||
2440 | hash_openowner(oo, clp, strhashval); | ||
2441 | return oo; | ||
2442 | } | ||
2443 | |||
2444 | static void init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { | ||
2445 | struct nfs4_openowner *oo = open->op_openowner; | ||
2446 | struct nfs4_client *clp = oo->oo_owner.so_client; | ||
2447 | 2258 | ||
2448 | init_stid(&stp->st_stid, clp, NFS4_OPEN_STID); | 2259 | INIT_LIST_HEAD(&stp->st_hash); |
2260 | INIT_LIST_HEAD(&stp->st_perstateowner); | ||
2449 | INIT_LIST_HEAD(&stp->st_lockowners); | 2261 | INIT_LIST_HEAD(&stp->st_lockowners); |
2450 | list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); | 2262 | INIT_LIST_HEAD(&stp->st_perfile); |
2263 | list_add(&stp->st_hash, &stateid_hashtbl[hashval]); | ||
2264 | list_add(&stp->st_perstateowner, &sop->so_stateids); | ||
2451 | list_add(&stp->st_perfile, &fp->fi_stateids); | 2265 | list_add(&stp->st_perfile, &fp->fi_stateids); |
2452 | stp->st_stateowner = &oo->oo_owner; | 2266 | stp->st_stateowner = sop; |
2453 | get_nfs4_file(fp); | 2267 | get_nfs4_file(fp); |
2454 | stp->st_file = fp; | 2268 | stp->st_file = fp; |
2269 | stp->st_stateid.si_boot = boot_time; | ||
2270 | stp->st_stateid.si_stateownerid = sop->so_id; | ||
2271 | stp->st_stateid.si_fileid = fp->fi_id; | ||
2272 | stp->st_stateid.si_generation = 0; | ||
2455 | stp->st_access_bmap = 0; | 2273 | stp->st_access_bmap = 0; |
2456 | stp->st_deny_bmap = 0; | 2274 | stp->st_deny_bmap = 0; |
2457 | set_access(open->op_share_access, stp); | 2275 | __set_bit(open->op_share_access & ~NFS4_SHARE_WANT_MASK, |
2458 | set_deny(open->op_share_deny, stp); | 2276 | &stp->st_access_bmap); |
2277 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | ||
2459 | stp->st_openstp = NULL; | 2278 | stp->st_openstp = NULL; |
2460 | } | 2279 | } |
2461 | 2280 | ||
2462 | static void | 2281 | static void |
2463 | move_to_close_lru(struct nfs4_openowner *oo, struct net *net) | 2282 | move_to_close_lru(struct nfs4_stateowner *sop) |
2464 | { | 2283 | { |
2465 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 2284 | dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); |
2466 | 2285 | ||
2467 | dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo); | 2286 | list_move_tail(&sop->so_close_lru, &close_lru); |
2468 | 2287 | sop->so_time = get_seconds(); | |
2469 | list_move_tail(&oo->oo_close_lru, &nn->close_lru); | ||
2470 | oo->oo_time = get_seconds(); | ||
2471 | } | 2288 | } |
2472 | 2289 | ||
2473 | static int | 2290 | static int |
@@ -2479,25 +2296,14 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, | |||
2479 | (sop->so_client->cl_clientid.cl_id == clid->cl_id); | 2296 | (sop->so_client->cl_clientid.cl_id == clid->cl_id); |
2480 | } | 2297 | } |
2481 | 2298 | ||
2482 | static struct nfs4_openowner * | 2299 | static struct nfs4_stateowner * |
2483 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, | 2300 | find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) |
2484 | bool sessions, struct nfsd_net *nn) | ||
2485 | { | 2301 | { |
2486 | struct nfs4_stateowner *so; | 2302 | struct nfs4_stateowner *so = NULL; |
2487 | struct nfs4_openowner *oo; | ||
2488 | struct nfs4_client *clp; | ||
2489 | 2303 | ||
2490 | list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) { | 2304 | list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) { |
2491 | if (!so->so_is_open_owner) | 2305 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) |
2492 | continue; | 2306 | return so; |
2493 | if (same_owner_str(so, &open->op_owner, &open->op_clientid)) { | ||
2494 | oo = openowner(so); | ||
2495 | clp = oo->oo_owner.so_client; | ||
2496 | if ((bool)clp->cl_minorversion != sessions) | ||
2497 | return NULL; | ||
2498 | renew_client(oo->oo_owner.so_client); | ||
2499 | return oo; | ||
2500 | } | ||
2501 | } | 2307 | } |
2502 | return NULL; | 2308 | return NULL; |
2503 | } | 2309 | } |
@@ -2521,6 +2327,31 @@ find_file(struct inode *ino) | |||
2521 | return NULL; | 2327 | return NULL; |
2522 | } | 2328 | } |
2523 | 2329 | ||
2330 | static inline int access_valid(u32 x, u32 minorversion) | ||
2331 | { | ||
2332 | if ((x & NFS4_SHARE_ACCESS_MASK) < NFS4_SHARE_ACCESS_READ) | ||
2333 | return 0; | ||
2334 | if ((x & NFS4_SHARE_ACCESS_MASK) > NFS4_SHARE_ACCESS_BOTH) | ||
2335 | return 0; | ||
2336 | x &= ~NFS4_SHARE_ACCESS_MASK; | ||
2337 | if (minorversion && x) { | ||
2338 | if ((x & NFS4_SHARE_WANT_MASK) > NFS4_SHARE_WANT_CANCEL) | ||
2339 | return 0; | ||
2340 | if ((x & NFS4_SHARE_WHEN_MASK) > NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED) | ||
2341 | return 0; | ||
2342 | x &= ~(NFS4_SHARE_WANT_MASK | NFS4_SHARE_WHEN_MASK); | ||
2343 | } | ||
2344 | if (x) | ||
2345 | return 0; | ||
2346 | return 1; | ||
2347 | } | ||
2348 | |||
2349 | static inline int deny_valid(u32 x) | ||
2350 | { | ||
2351 | /* Note: unlike access bits, deny bits may be zero. */ | ||
2352 | return x <= NFS4_SHARE_DENY_BOTH; | ||
2353 | } | ||
2354 | |||
2524 | /* | 2355 | /* |
2525 | * Called to check deny when READ with all zero stateid or | 2356 | * Called to check deny when READ with all zero stateid or |
2526 | * WRITE with all zero or all one stateid | 2357 | * WRITE with all zero or all one stateid |
@@ -2530,7 +2361,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | |||
2530 | { | 2361 | { |
2531 | struct inode *ino = current_fh->fh_dentry->d_inode; | 2362 | struct inode *ino = current_fh->fh_dentry->d_inode; |
2532 | struct nfs4_file *fp; | 2363 | struct nfs4_file *fp; |
2533 | struct nfs4_ol_stateid *stp; | 2364 | struct nfs4_stateid *stp; |
2534 | __be32 ret; | 2365 | __be32 ret; |
2535 | 2366 | ||
2536 | dprintk("NFSD: nfs4_share_conflict\n"); | 2367 | dprintk("NFSD: nfs4_share_conflict\n"); |
@@ -2541,8 +2372,8 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | |||
2541 | ret = nfserr_locked; | 2372 | ret = nfserr_locked; |
2542 | /* Search for conflicting share reservations */ | 2373 | /* Search for conflicting share reservations */ |
2543 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { | 2374 | list_for_each_entry(stp, &fp->fi_stateids, st_perfile) { |
2544 | if (test_deny(deny_type, stp) || | 2375 | if (test_bit(deny_type, &stp->st_deny_bmap) || |
2545 | test_deny(NFS4_SHARE_DENY_BOTH, stp)) | 2376 | test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap)) |
2546 | goto out; | 2377 | goto out; |
2547 | } | 2378 | } |
2548 | ret = nfs_ok; | 2379 | ret = nfs_ok; |
@@ -2574,14 +2405,9 @@ static void nfsd_break_deleg_cb(struct file_lock *fl) | |||
2574 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; | 2405 | struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner; |
2575 | struct nfs4_delegation *dp; | 2406 | struct nfs4_delegation *dp; |
2576 | 2407 | ||
2577 | if (!fp) { | 2408 | BUG_ON(!fp); |
2578 | WARN(1, "(%p)->fl_owner NULL\n", fl); | 2409 | /* We assume break_lease is only called once per lease: */ |
2579 | return; | 2410 | BUG_ON(fp->fi_had_conflict); |
2580 | } | ||
2581 | if (fp->fi_had_conflict) { | ||
2582 | WARN(1, "duplicate break on %p\n", fp); | ||
2583 | return; | ||
2584 | } | ||
2585 | /* | 2411 | /* |
2586 | * We don't want the locks code to timeout the lease for us; | 2412 | * We don't want the locks code to timeout the lease for us; |
2587 | * we'll remove it ourself if a delegation isn't returned | 2413 | * we'll remove it ourself if a delegation isn't returned |
@@ -2610,68 +2436,65 @@ static const struct lock_manager_operations nfsd_lease_mng_ops = { | |||
2610 | .lm_change = nfsd_change_deleg_cb, | 2436 | .lm_change = nfsd_change_deleg_cb, |
2611 | }; | 2437 | }; |
2612 | 2438 | ||
2613 | static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid) | ||
2614 | { | ||
2615 | if (nfsd4_has_session(cstate)) | ||
2616 | return nfs_ok; | ||
2617 | if (seqid == so->so_seqid - 1) | ||
2618 | return nfserr_replay_me; | ||
2619 | if (seqid == so->so_seqid) | ||
2620 | return nfs_ok; | ||
2621 | return nfserr_bad_seqid; | ||
2622 | } | ||
2623 | 2439 | ||
2624 | __be32 | 2440 | __be32 |
2625 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, | 2441 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, |
2626 | struct nfsd4_open *open, struct nfsd_net *nn) | 2442 | struct nfsd4_open *open) |
2627 | { | 2443 | { |
2628 | clientid_t *clientid = &open->op_clientid; | 2444 | clientid_t *clientid = &open->op_clientid; |
2629 | struct nfs4_client *clp = NULL; | 2445 | struct nfs4_client *clp = NULL; |
2630 | unsigned int strhashval; | 2446 | unsigned int strhashval; |
2631 | struct nfs4_openowner *oo = NULL; | 2447 | struct nfs4_stateowner *sop = NULL; |
2632 | __be32 status; | ||
2633 | 2448 | ||
2634 | if (STALE_CLIENTID(&open->op_clientid, nn)) | 2449 | if (!check_name(open->op_owner)) |
2450 | return nfserr_inval; | ||
2451 | |||
2452 | if (STALE_CLIENTID(&open->op_clientid)) | ||
2635 | return nfserr_stale_clientid; | 2453 | return nfserr_stale_clientid; |
2636 | /* | ||
2637 | * In case we need it later, after we've already created the | ||
2638 | * file and don't want to risk a further failure: | ||
2639 | */ | ||
2640 | open->op_file = nfsd4_alloc_file(); | ||
2641 | if (open->op_file == NULL) | ||
2642 | return nfserr_jukebox; | ||
2643 | 2454 | ||
2644 | strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); | 2455 | strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner); |
2645 | oo = find_openstateowner_str(strhashval, open, cstate->minorversion, nn); | 2456 | sop = find_openstateowner_str(strhashval, open); |
2646 | open->op_openowner = oo; | 2457 | open->op_stateowner = sop; |
2647 | if (!oo) { | 2458 | if (!sop) { |
2648 | clp = find_confirmed_client(clientid, cstate->minorversion, | 2459 | /* Make sure the client's lease hasn't expired. */ |
2649 | nn); | 2460 | clp = find_confirmed_client(clientid); |
2650 | if (clp == NULL) | 2461 | if (clp == NULL) |
2651 | return nfserr_expired; | 2462 | return nfserr_expired; |
2652 | goto new_owner; | 2463 | goto renew; |
2653 | } | 2464 | } |
2654 | if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { | 2465 | /* When sessions are used, skip open sequenceid processing */ |
2466 | if (nfsd4_has_session(cstate)) | ||
2467 | goto renew; | ||
2468 | if (!sop->so_confirmed) { | ||
2655 | /* Replace unconfirmed owners without checking for replay. */ | 2469 | /* Replace unconfirmed owners without checking for replay. */ |
2656 | clp = oo->oo_owner.so_client; | 2470 | clp = sop->so_client; |
2657 | release_openowner(oo); | 2471 | release_openowner(sop); |
2658 | open->op_openowner = NULL; | 2472 | open->op_stateowner = NULL; |
2659 | goto new_owner; | 2473 | goto renew; |
2660 | } | 2474 | } |
2661 | status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid); | 2475 | if (open->op_seqid == sop->so_seqid - 1) { |
2662 | if (status) | 2476 | if (sop->so_replay.rp_buflen) |
2663 | return status; | 2477 | return nfserr_replay_me; |
2664 | clp = oo->oo_owner.so_client; | 2478 | /* The original OPEN failed so spectacularly |
2665 | goto alloc_stateid; | 2479 | * that we don't even have replay data saved! |
2666 | new_owner: | 2480 | * Therefore, we have no choice but to continue |
2667 | oo = alloc_init_open_stateowner(strhashval, clp, open); | 2481 | * processing this OPEN; presumably, we'll |
2668 | if (oo == NULL) | 2482 | * fail again for the same reason. |
2669 | return nfserr_jukebox; | 2483 | */ |
2670 | open->op_openowner = oo; | 2484 | dprintk("nfsd4_process_open1: replay with no replay cache\n"); |
2671 | alloc_stateid: | 2485 | goto renew; |
2672 | open->op_stp = nfs4_alloc_stateid(clp); | 2486 | } |
2673 | if (!open->op_stp) | 2487 | if (open->op_seqid != sop->so_seqid) |
2674 | return nfserr_jukebox; | 2488 | return nfserr_bad_seqid; |
2489 | renew: | ||
2490 | if (open->op_stateowner == NULL) { | ||
2491 | sop = alloc_init_open_stateowner(strhashval, clp, open); | ||
2492 | if (sop == NULL) | ||
2493 | return nfserr_jukebox; | ||
2494 | open->op_stateowner = sop; | ||
2495 | } | ||
2496 | list_del_init(&sop->so_close_lru); | ||
2497 | renew_client(sop->so_client); | ||
2675 | return nfs_ok; | 2498 | return nfs_ok; |
2676 | } | 2499 | } |
2677 | 2500 | ||
@@ -2684,35 +2507,36 @@ nfs4_check_delegmode(struct nfs4_delegation *dp, int flags) | |||
2684 | return nfs_ok; | 2507 | return nfs_ok; |
2685 | } | 2508 | } |
2686 | 2509 | ||
2687 | static int share_access_to_flags(u32 share_access) | 2510 | static struct nfs4_delegation * |
2688 | { | 2511 | find_delegation_file(struct nfs4_file *fp, stateid_t *stid) |
2689 | return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; | ||
2690 | } | ||
2691 | |||
2692 | static struct nfs4_delegation *find_deleg_stateid(struct nfs4_client *cl, stateid_t *s) | ||
2693 | { | 2512 | { |
2694 | struct nfs4_stid *ret; | 2513 | struct nfs4_delegation *dp; |
2695 | 2514 | ||
2696 | ret = find_stateid_by_type(cl, s, NFS4_DELEG_STID); | 2515 | spin_lock(&recall_lock); |
2697 | if (!ret) | 2516 | list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) |
2698 | return NULL; | 2517 | if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid) { |
2699 | return delegstateid(ret); | 2518 | spin_unlock(&recall_lock); |
2519 | return dp; | ||
2520 | } | ||
2521 | spin_unlock(&recall_lock); | ||
2522 | return NULL; | ||
2700 | } | 2523 | } |
2701 | 2524 | ||
2702 | static bool nfsd4_is_deleg_cur(struct nfsd4_open *open) | 2525 | static int share_access_to_flags(u32 share_access) |
2703 | { | 2526 | { |
2704 | return open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR || | 2527 | share_access &= ~NFS4_SHARE_WANT_MASK; |
2705 | open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH; | 2528 | |
2529 | return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE; | ||
2706 | } | 2530 | } |
2707 | 2531 | ||
2708 | static __be32 | 2532 | static __be32 |
2709 | nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open *open, | 2533 | nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open, |
2710 | struct nfs4_delegation **dp) | 2534 | struct nfs4_delegation **dp) |
2711 | { | 2535 | { |
2712 | int flags; | 2536 | int flags; |
2713 | __be32 status = nfserr_bad_stateid; | 2537 | __be32 status = nfserr_bad_stateid; |
2714 | 2538 | ||
2715 | *dp = find_deleg_stateid(cl, &open->op_delegate_stateid); | 2539 | *dp = find_delegation_file(fp, &open->op_delegate_stateid); |
2716 | if (*dp == NULL) | 2540 | if (*dp == NULL) |
2717 | goto out; | 2541 | goto out; |
2718 | flags = share_access_to_flags(open->op_share_access); | 2542 | flags = share_access_to_flags(open->op_share_access); |
@@ -2720,32 +2544,41 @@ nfs4_check_deleg(struct nfs4_client *cl, struct nfs4_file *fp, struct nfsd4_open | |||
2720 | if (status) | 2544 | if (status) |
2721 | *dp = NULL; | 2545 | *dp = NULL; |
2722 | out: | 2546 | out: |
2723 | if (!nfsd4_is_deleg_cur(open)) | 2547 | if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR) |
2724 | return nfs_ok; | 2548 | return nfs_ok; |
2725 | if (status) | 2549 | if (status) |
2726 | return status; | 2550 | return status; |
2727 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | 2551 | open->op_stateowner->so_confirmed = 1; |
2728 | return nfs_ok; | 2552 | return nfs_ok; |
2729 | } | 2553 | } |
2730 | 2554 | ||
2731 | static __be32 | 2555 | static __be32 |
2732 | nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp) | 2556 | nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp) |
2733 | { | 2557 | { |
2734 | struct nfs4_ol_stateid *local; | 2558 | struct nfs4_stateid *local; |
2735 | struct nfs4_openowner *oo = open->op_openowner; | 2559 | __be32 status = nfserr_share_denied; |
2560 | struct nfs4_stateowner *sop = open->op_stateowner; | ||
2736 | 2561 | ||
2737 | list_for_each_entry(local, &fp->fi_stateids, st_perfile) { | 2562 | list_for_each_entry(local, &fp->fi_stateids, st_perfile) { |
2738 | /* ignore lock owners */ | 2563 | /* ignore lock owners */ |
2739 | if (local->st_stateowner->so_is_open_owner == 0) | 2564 | if (local->st_stateowner->so_is_open_owner == 0) |
2740 | continue; | 2565 | continue; |
2741 | /* remember if we have seen this open owner */ | 2566 | /* remember if we have seen this open owner */ |
2742 | if (local->st_stateowner == &oo->oo_owner) | 2567 | if (local->st_stateowner == sop) |
2743 | *stpp = local; | 2568 | *stpp = local; |
2744 | /* check for conflicting share reservations */ | 2569 | /* check for conflicting share reservations */ |
2745 | if (!test_share(local, open)) | 2570 | if (!test_share(local, open)) |
2746 | return nfserr_share_denied; | 2571 | goto out; |
2747 | } | 2572 | } |
2748 | return nfs_ok; | 2573 | status = 0; |
2574 | out: | ||
2575 | return status; | ||
2576 | } | ||
2577 | |||
2578 | static inline struct nfs4_stateid * | ||
2579 | nfs4_alloc_stateid(void) | ||
2580 | { | ||
2581 | return kmem_cache_alloc(stateid_slab, GFP_KERNEL); | ||
2749 | } | 2582 | } |
2750 | 2583 | ||
2751 | static inline int nfs4_access_to_access(u32 nfs4_access) | 2584 | static inline int nfs4_access_to_access(u32 nfs4_access) |
@@ -2766,6 +2599,12 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, | |||
2766 | int oflag = nfs4_access_to_omode(open->op_share_access); | 2599 | int oflag = nfs4_access_to_omode(open->op_share_access); |
2767 | int access = nfs4_access_to_access(open->op_share_access); | 2600 | int access = nfs4_access_to_access(open->op_share_access); |
2768 | 2601 | ||
2602 | /* CLAIM_DELEGATE_CUR is used in response to a broken lease; | ||
2603 | * allowing it to break the lease and return EAGAIN leaves the | ||
2604 | * client unable to make progress in returning the delegation */ | ||
2605 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) | ||
2606 | access |= NFSD_MAY_NOT_BREAK_LEASE; | ||
2607 | |||
2769 | if (!fp->fi_fds[oflag]) { | 2608 | if (!fp->fi_fds[oflag]) { |
2770 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, | 2609 | status = nfsd_open(rqstp, cur_fh, S_IFREG, access, |
2771 | &fp->fi_fds[oflag]); | 2610 | &fp->fi_fds[oflag]); |
@@ -2777,6 +2616,27 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, | |||
2777 | return nfs_ok; | 2616 | return nfs_ok; |
2778 | } | 2617 | } |
2779 | 2618 | ||
2619 | static __be32 | ||
2620 | nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp, | ||
2621 | struct nfs4_file *fp, struct svc_fh *cur_fh, | ||
2622 | struct nfsd4_open *open) | ||
2623 | { | ||
2624 | struct nfs4_stateid *stp; | ||
2625 | __be32 status; | ||
2626 | |||
2627 | stp = nfs4_alloc_stateid(); | ||
2628 | if (stp == NULL) | ||
2629 | return nfserr_jukebox; | ||
2630 | |||
2631 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); | ||
2632 | if (status) { | ||
2633 | kmem_cache_free(stateid_slab, stp); | ||
2634 | return status; | ||
2635 | } | ||
2636 | *stpp = stp; | ||
2637 | return 0; | ||
2638 | } | ||
2639 | |||
2780 | static inline __be32 | 2640 | static inline __be32 |
2781 | nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | 2641 | nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, |
2782 | struct nfsd4_open *open) | 2642 | struct nfsd4_open *open) |
@@ -2793,13 +2653,13 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, | |||
2793 | } | 2653 | } |
2794 | 2654 | ||
2795 | static __be32 | 2655 | static __be32 |
2796 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open) | 2656 | nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open) |
2797 | { | 2657 | { |
2798 | u32 op_share_access = open->op_share_access; | 2658 | u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK; |
2799 | bool new_access; | 2659 | bool new_access; |
2800 | __be32 status; | 2660 | __be32 status; |
2801 | 2661 | ||
2802 | new_access = !test_access(op_share_access, stp); | 2662 | new_access = !test_bit(op_share_access, &stp->st_access_bmap); |
2803 | if (new_access) { | 2663 | if (new_access) { |
2804 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); | 2664 | status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open); |
2805 | if (status) | 2665 | if (status) |
@@ -2814,17 +2674,18 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *c | |||
2814 | return status; | 2674 | return status; |
2815 | } | 2675 | } |
2816 | /* remember the open */ | 2676 | /* remember the open */ |
2817 | set_access(op_share_access, stp); | 2677 | __set_bit(op_share_access, &stp->st_access_bmap); |
2818 | set_deny(open->op_share_deny, stp); | 2678 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
2819 | 2679 | ||
2820 | return nfs_ok; | 2680 | return nfs_ok; |
2821 | } | 2681 | } |
2822 | 2682 | ||
2823 | 2683 | ||
2824 | static void | 2684 | static void |
2825 | nfs4_set_claim_prev(struct nfsd4_open *open, bool has_session) | 2685 | nfs4_set_claim_prev(struct nfsd4_open *open) |
2826 | { | 2686 | { |
2827 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | 2687 | open->op_stateowner->so_confirmed = 1; |
2688 | open->op_stateowner->so_client->cl_firststate = 1; | ||
2828 | } | 2689 | } |
2829 | 2690 | ||
2830 | /* Should we give out recallable state?: */ | 2691 | /* Should we give out recallable state?: */ |
@@ -2867,7 +2728,7 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | |||
2867 | if (!fl) | 2728 | if (!fl) |
2868 | return -ENOMEM; | 2729 | return -ENOMEM; |
2869 | fl->fl_file = find_readable_file(fp); | 2730 | fl->fl_file = find_readable_file(fp); |
2870 | list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); | 2731 | list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); |
2871 | status = vfs_setlease(fl->fl_file, fl->fl_type, &fl); | 2732 | status = vfs_setlease(fl->fl_file, fl->fl_type, &fl); |
2872 | if (status) { | 2733 | if (status) { |
2873 | list_del_init(&dp->dl_perclnt); | 2734 | list_del_init(&dp->dl_perclnt); |
@@ -2875,7 +2736,8 @@ static int nfs4_setlease(struct nfs4_delegation *dp, int flag) | |||
2875 | return -ENOMEM; | 2736 | return -ENOMEM; |
2876 | } | 2737 | } |
2877 | fp->fi_lease = fl; | 2738 | fp->fi_lease = fl; |
2878 | fp->fi_deleg_file = get_file(fl->fl_file); | 2739 | fp->fi_deleg_file = fl->fl_file; |
2740 | get_file(fp->fi_deleg_file); | ||
2879 | atomic_set(&fp->fi_delegees, 1); | 2741 | atomic_set(&fp->fi_delegees, 1); |
2880 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 2742 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
2881 | return 0; | 2743 | return 0; |
@@ -2895,44 +2757,22 @@ static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag) | |||
2895 | atomic_inc(&fp->fi_delegees); | 2757 | atomic_inc(&fp->fi_delegees); |
2896 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 2758 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
2897 | spin_unlock(&recall_lock); | 2759 | spin_unlock(&recall_lock); |
2898 | list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); | 2760 | list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations); |
2899 | return 0; | 2761 | return 0; |
2900 | } | 2762 | } |
2901 | 2763 | ||
2902 | static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) | ||
2903 | { | ||
2904 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; | ||
2905 | if (status == -EAGAIN) | ||
2906 | open->op_why_no_deleg = WND4_CONTENTION; | ||
2907 | else { | ||
2908 | open->op_why_no_deleg = WND4_RESOURCE; | ||
2909 | switch (open->op_deleg_want) { | ||
2910 | case NFS4_SHARE_WANT_READ_DELEG: | ||
2911 | case NFS4_SHARE_WANT_WRITE_DELEG: | ||
2912 | case NFS4_SHARE_WANT_ANY_DELEG: | ||
2913 | break; | ||
2914 | case NFS4_SHARE_WANT_CANCEL: | ||
2915 | open->op_why_no_deleg = WND4_CANCELLED; | ||
2916 | break; | ||
2917 | case NFS4_SHARE_WANT_NO_DELEG: | ||
2918 | WARN_ON_ONCE(1); | ||
2919 | } | ||
2920 | } | ||
2921 | } | ||
2922 | |||
2923 | /* | 2764 | /* |
2924 | * Attempt to hand out a delegation. | 2765 | * Attempt to hand out a delegation. |
2925 | */ | 2766 | */ |
2926 | static void | 2767 | static void |
2927 | nfs4_open_delegation(struct net *net, struct svc_fh *fh, | 2768 | nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_stateid *stp) |
2928 | struct nfsd4_open *open, struct nfs4_ol_stateid *stp) | ||
2929 | { | 2769 | { |
2930 | struct nfs4_delegation *dp; | 2770 | struct nfs4_delegation *dp; |
2931 | struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner); | 2771 | struct nfs4_stateowner *sop = stp->st_stateowner; |
2932 | int cb_up; | 2772 | int cb_up; |
2933 | int status = 0, flag = 0; | 2773 | int status, flag = 0; |
2934 | 2774 | ||
2935 | cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client); | 2775 | cb_up = nfsd4_cb_channel_good(sop->so_client); |
2936 | flag = NFS4_OPEN_DELEGATE_NONE; | 2776 | flag = NFS4_OPEN_DELEGATE_NONE; |
2937 | open->op_recall = 0; | 2777 | open->op_recall = 0; |
2938 | switch (open->op_claim_type) { | 2778 | switch (open->op_claim_type) { |
@@ -2946,9 +2786,9 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
2946 | case NFS4_OPEN_CLAIM_NULL: | 2786 | case NFS4_OPEN_CLAIM_NULL: |
2947 | /* Let's not give out any delegations till everyone's | 2787 | /* Let's not give out any delegations till everyone's |
2948 | * had the chance to reclaim theirs.... */ | 2788 | * had the chance to reclaim theirs.... */ |
2949 | if (locks_in_grace(net)) | 2789 | if (locks_in_grace()) |
2950 | goto out; | 2790 | goto out; |
2951 | if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) | 2791 | if (!cb_up || !sop->so_confirmed) |
2952 | goto out; | 2792 | goto out; |
2953 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) | 2793 | if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) |
2954 | flag = NFS4_OPEN_DELEGATE_WRITE; | 2794 | flag = NFS4_OPEN_DELEGATE_WRITE; |
@@ -2959,55 +2799,31 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, | |||
2959 | goto out; | 2799 | goto out; |
2960 | } | 2800 | } |
2961 | 2801 | ||
2962 | dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag); | 2802 | dp = alloc_init_deleg(sop->so_client, stp, fh, flag); |
2963 | if (dp == NULL) | 2803 | if (dp == NULL) |
2964 | goto out_no_deleg; | 2804 | goto out_no_deleg; |
2965 | status = nfs4_set_delegation(dp, flag); | 2805 | status = nfs4_set_delegation(dp, flag); |
2966 | if (status) | 2806 | if (status) |
2967 | goto out_free; | 2807 | goto out_free; |
2968 | 2808 | ||
2969 | memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); | 2809 | memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); |
2970 | 2810 | ||
2971 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", | 2811 | dprintk("NFSD: delegation stateid=" STATEID_FMT "\n", |
2972 | STATEID_VAL(&dp->dl_stid.sc_stateid)); | 2812 | STATEID_VAL(&dp->dl_stateid)); |
2973 | out: | 2813 | out: |
2814 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS | ||
2815 | && flag == NFS4_OPEN_DELEGATE_NONE | ||
2816 | && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | ||
2817 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
2974 | open->op_delegate_type = flag; | 2818 | open->op_delegate_type = flag; |
2975 | if (flag == NFS4_OPEN_DELEGATE_NONE) { | ||
2976 | if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS && | ||
2977 | open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE) | ||
2978 | dprintk("NFSD: WARNING: refusing delegation reclaim\n"); | ||
2979 | |||
2980 | /* 4.1 client asking for a delegation? */ | ||
2981 | if (open->op_deleg_want) | ||
2982 | nfsd4_open_deleg_none_ext(open, status); | ||
2983 | } | ||
2984 | return; | 2819 | return; |
2985 | out_free: | 2820 | out_free: |
2986 | unhash_stid(&dp->dl_stid); | ||
2987 | nfs4_put_delegation(dp); | 2821 | nfs4_put_delegation(dp); |
2988 | out_no_deleg: | 2822 | out_no_deleg: |
2989 | flag = NFS4_OPEN_DELEGATE_NONE; | 2823 | flag = NFS4_OPEN_DELEGATE_NONE; |
2990 | goto out; | 2824 | goto out; |
2991 | } | 2825 | } |
2992 | 2826 | ||
2993 | static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, | ||
2994 | struct nfs4_delegation *dp) | ||
2995 | { | ||
2996 | if (open->op_deleg_want == NFS4_SHARE_WANT_READ_DELEG && | ||
2997 | dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { | ||
2998 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; | ||
2999 | open->op_why_no_deleg = WND4_NOT_SUPP_DOWNGRADE; | ||
3000 | } else if (open->op_deleg_want == NFS4_SHARE_WANT_WRITE_DELEG && | ||
3001 | dp->dl_type == NFS4_OPEN_DELEGATE_WRITE) { | ||
3002 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; | ||
3003 | open->op_why_no_deleg = WND4_NOT_SUPP_UPGRADE; | ||
3004 | } | ||
3005 | /* Otherwise the client must be confused wanting a delegation | ||
3006 | * it already has, therefore we don't return | ||
3007 | * NFS4_OPEN_DELEGATE_NONE_EXT and reason. | ||
3008 | */ | ||
3009 | } | ||
3010 | |||
3011 | /* | 2827 | /* |
3012 | * called with nfs4_lock_state() held. | 2828 | * called with nfs4_lock_state() held. |
3013 | */ | 2829 | */ |
@@ -3015,13 +2831,16 @@ __be32 | |||
3015 | nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 2831 | nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
3016 | { | 2832 | { |
3017 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 2833 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
3018 | struct nfs4_client *cl = open->op_openowner->oo_owner.so_client; | ||
3019 | struct nfs4_file *fp = NULL; | 2834 | struct nfs4_file *fp = NULL; |
3020 | struct inode *ino = current_fh->fh_dentry->d_inode; | 2835 | struct inode *ino = current_fh->fh_dentry->d_inode; |
3021 | struct nfs4_ol_stateid *stp = NULL; | 2836 | struct nfs4_stateid *stp = NULL; |
3022 | struct nfs4_delegation *dp = NULL; | 2837 | struct nfs4_delegation *dp = NULL; |
3023 | __be32 status; | 2838 | __be32 status; |
3024 | 2839 | ||
2840 | status = nfserr_inval; | ||
2841 | if (!access_valid(open->op_share_access, resp->cstate.minorversion) | ||
2842 | || !deny_valid(open->op_share_deny)) | ||
2843 | goto out; | ||
3025 | /* | 2844 | /* |
3026 | * Lookup file; if found, lookup stateid and check open request, | 2845 | * Lookup file; if found, lookup stateid and check open request, |
3027 | * and check for delegations in the process of being recalled. | 2846 | * and check for delegations in the process of being recalled. |
@@ -3031,17 +2850,17 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
3031 | if (fp) { | 2850 | if (fp) { |
3032 | if ((status = nfs4_check_open(fp, open, &stp))) | 2851 | if ((status = nfs4_check_open(fp, open, &stp))) |
3033 | goto out; | 2852 | goto out; |
3034 | status = nfs4_check_deleg(cl, fp, open, &dp); | 2853 | status = nfs4_check_deleg(fp, open, &dp); |
3035 | if (status) | 2854 | if (status) |
3036 | goto out; | 2855 | goto out; |
3037 | } else { | 2856 | } else { |
3038 | status = nfserr_bad_stateid; | 2857 | status = nfserr_bad_stateid; |
3039 | if (nfsd4_is_deleg_cur(open)) | 2858 | if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR) |
3040 | goto out; | 2859 | goto out; |
3041 | status = nfserr_jukebox; | 2860 | status = nfserr_jukebox; |
3042 | fp = open->op_file; | 2861 | fp = alloc_init_file(ino); |
3043 | open->op_file = NULL; | 2862 | if (fp == NULL) |
3044 | nfsd4_init_file(fp, ino); | 2863 | goto out; |
3045 | } | 2864 | } |
3046 | 2865 | ||
3047 | /* | 2866 | /* |
@@ -3053,108 +2872,72 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
3053 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); | 2872 | status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); |
3054 | if (status) | 2873 | if (status) |
3055 | goto out; | 2874 | goto out; |
2875 | update_stateid(&stp->st_stateid); | ||
3056 | } else { | 2876 | } else { |
3057 | status = nfs4_get_vfs_file(rqstp, fp, current_fh, open); | 2877 | status = nfs4_new_open(rqstp, &stp, fp, current_fh, open); |
3058 | if (status) | 2878 | if (status) |
3059 | goto out; | 2879 | goto out; |
2880 | init_stateid(stp, fp, open); | ||
3060 | status = nfsd4_truncate(rqstp, current_fh, open); | 2881 | status = nfsd4_truncate(rqstp, current_fh, open); |
3061 | if (status) | 2882 | if (status) { |
2883 | release_open_stateid(stp); | ||
3062 | goto out; | 2884 | goto out; |
3063 | stp = open->op_stp; | ||
3064 | open->op_stp = NULL; | ||
3065 | init_open_stateid(stp, fp, open); | ||
3066 | } | ||
3067 | update_stateid(&stp->st_stid.sc_stateid); | ||
3068 | memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | ||
3069 | |||
3070 | if (nfsd4_has_session(&resp->cstate)) { | ||
3071 | open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; | ||
3072 | |||
3073 | if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { | ||
3074 | open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE_EXT; | ||
3075 | open->op_why_no_deleg = WND4_NOT_WANTED; | ||
3076 | goto nodeleg; | ||
3077 | } | 2885 | } |
2886 | if (nfsd4_has_session(&resp->cstate)) | ||
2887 | update_stateid(&stp->st_stateid); | ||
3078 | } | 2888 | } |
2889 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); | ||
2890 | |||
2891 | if (nfsd4_has_session(&resp->cstate)) | ||
2892 | open->op_stateowner->so_confirmed = 1; | ||
3079 | 2893 | ||
3080 | /* | 2894 | /* |
3081 | * Attempt to hand out a delegation. No error return, because the | 2895 | * Attempt to hand out a delegation. No error return, because the |
3082 | * OPEN succeeds even if we fail. | 2896 | * OPEN succeeds even if we fail. |
3083 | */ | 2897 | */ |
3084 | nfs4_open_delegation(SVC_NET(rqstp), current_fh, open, stp); | 2898 | nfs4_open_delegation(current_fh, open, stp); |
3085 | nodeleg: | 2899 | |
3086 | status = nfs_ok; | 2900 | status = nfs_ok; |
3087 | 2901 | ||
3088 | dprintk("%s: stateid=" STATEID_FMT "\n", __func__, | 2902 | dprintk("%s: stateid=" STATEID_FMT "\n", __func__, |
3089 | STATEID_VAL(&stp->st_stid.sc_stateid)); | 2903 | STATEID_VAL(&stp->st_stateid)); |
3090 | out: | 2904 | out: |
3091 | /* 4.1 client trying to upgrade/downgrade delegation? */ | ||
3092 | if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && | ||
3093 | open->op_deleg_want) | ||
3094 | nfsd4_deleg_xgrade_none_ext(open, dp); | ||
3095 | |||
3096 | if (fp) | 2905 | if (fp) |
3097 | put_nfs4_file(fp); | 2906 | put_nfs4_file(fp); |
3098 | if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) | 2907 | if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) |
3099 | nfs4_set_claim_prev(open, nfsd4_has_session(&resp->cstate)); | 2908 | nfs4_set_claim_prev(open); |
3100 | /* | 2909 | /* |
3101 | * To finish the open response, we just need to set the rflags. | 2910 | * To finish the open response, we just need to set the rflags. |
3102 | */ | 2911 | */ |
3103 | open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; | 2912 | open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; |
3104 | if (!(open->op_openowner->oo_flags & NFS4_OO_CONFIRMED) && | 2913 | if (!open->op_stateowner->so_confirmed && |
3105 | !nfsd4_has_session(&resp->cstate)) | 2914 | !nfsd4_has_session(&resp->cstate)) |
3106 | open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; | 2915 | open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; |
3107 | 2916 | ||
3108 | return status; | 2917 | return status; |
3109 | } | 2918 | } |
3110 | 2919 | ||
3111 | void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status) | ||
3112 | { | ||
3113 | if (open->op_openowner) { | ||
3114 | struct nfs4_openowner *oo = open->op_openowner; | ||
3115 | |||
3116 | if (!list_empty(&oo->oo_owner.so_stateids)) | ||
3117 | list_del_init(&oo->oo_close_lru); | ||
3118 | if (oo->oo_flags & NFS4_OO_NEW) { | ||
3119 | if (status) { | ||
3120 | release_openowner(oo); | ||
3121 | open->op_openowner = NULL; | ||
3122 | } else | ||
3123 | oo->oo_flags &= ~NFS4_OO_NEW; | ||
3124 | } | ||
3125 | } | ||
3126 | if (open->op_file) | ||
3127 | nfsd4_free_file(open->op_file); | ||
3128 | if (open->op_stp) | ||
3129 | free_generic_stateid(open->op_stp); | ||
3130 | } | ||
3131 | |||
3132 | static __be32 lookup_clientid(clientid_t *clid, bool session, struct nfsd_net *nn, struct nfs4_client **clp) | ||
3133 | { | ||
3134 | struct nfs4_client *found; | ||
3135 | |||
3136 | if (STALE_CLIENTID(clid, nn)) | ||
3137 | return nfserr_stale_clientid; | ||
3138 | found = find_confirmed_client(clid, session, nn); | ||
3139 | if (clp) | ||
3140 | *clp = found; | ||
3141 | return found ? nfs_ok : nfserr_expired; | ||
3142 | } | ||
3143 | |||
3144 | __be32 | 2920 | __be32 |
3145 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 2921 | nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
3146 | clientid_t *clid) | 2922 | clientid_t *clid) |
3147 | { | 2923 | { |
3148 | struct nfs4_client *clp; | 2924 | struct nfs4_client *clp; |
3149 | __be32 status; | 2925 | __be32 status; |
3150 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
3151 | 2926 | ||
3152 | nfs4_lock_state(); | 2927 | nfs4_lock_state(); |
3153 | dprintk("process_renew(%08x/%08x): starting\n", | 2928 | dprintk("process_renew(%08x/%08x): starting\n", |
3154 | clid->cl_boot, clid->cl_id); | 2929 | clid->cl_boot, clid->cl_id); |
3155 | status = lookup_clientid(clid, cstate->minorversion, nn, &clp); | 2930 | status = nfserr_stale_clientid; |
3156 | if (status) | 2931 | if (STALE_CLIENTID(clid)) |
2932 | goto out; | ||
2933 | clp = find_confirmed_client(clid); | ||
2934 | status = nfserr_expired; | ||
2935 | if (clp == NULL) { | ||
2936 | /* We assume the client took too long to RENEW. */ | ||
2937 | dprintk("nfsd4_renew: clientid not found!\n"); | ||
3157 | goto out; | 2938 | goto out; |
2939 | } | ||
2940 | renew_client(clp); | ||
3158 | status = nfserr_cb_path_down; | 2941 | status = nfserr_cb_path_down; |
3159 | if (!list_empty(&clp->cl_delegations) | 2942 | if (!list_empty(&clp->cl_delegations) |
3160 | && clp->cl_cb_state != NFSD4_CB_UP) | 2943 | && clp->cl_cb_state != NFSD4_CB_UP) |
@@ -3165,43 +2948,42 @@ out: | |||
3165 | return status; | 2948 | return status; |
3166 | } | 2949 | } |
3167 | 2950 | ||
2951 | static struct lock_manager nfsd4_manager = { | ||
2952 | }; | ||
2953 | |||
3168 | static void | 2954 | static void |
3169 | nfsd4_end_grace(struct nfsd_net *nn) | 2955 | nfsd4_end_grace(void) |
3170 | { | 2956 | { |
3171 | /* do nothing if grace period already ended */ | ||
3172 | if (nn->grace_ended) | ||
3173 | return; | ||
3174 | |||
3175 | dprintk("NFSD: end of grace period\n"); | 2957 | dprintk("NFSD: end of grace period\n"); |
3176 | nn->grace_ended = true; | 2958 | nfsd4_recdir_purge_old(); |
3177 | nfsd4_record_grace_done(nn, nn->boot_time); | 2959 | locks_end_grace(&nfsd4_manager); |
3178 | locks_end_grace(&nn->nfsd4_manager); | ||
3179 | /* | 2960 | /* |
3180 | * Now that every NFSv4 client has had the chance to recover and | 2961 | * Now that every NFSv4 client has had the chance to recover and |
3181 | * to see the (possibly new, possibly shorter) lease time, we | 2962 | * to see the (possibly new, possibly shorter) lease time, we |
3182 | * can safely set the next grace time to the current lease time: | 2963 | * can safely set the next grace time to the current lease time: |
3183 | */ | 2964 | */ |
3184 | nn->nfsd4_grace = nn->nfsd4_lease; | 2965 | nfsd4_grace = nfsd4_lease; |
3185 | } | 2966 | } |
3186 | 2967 | ||
3187 | static time_t | 2968 | static time_t |
3188 | nfs4_laundromat(struct nfsd_net *nn) | 2969 | nfs4_laundromat(void) |
3189 | { | 2970 | { |
3190 | struct nfs4_client *clp; | 2971 | struct nfs4_client *clp; |
3191 | struct nfs4_openowner *oo; | 2972 | struct nfs4_stateowner *sop; |
3192 | struct nfs4_delegation *dp; | 2973 | struct nfs4_delegation *dp; |
3193 | struct list_head *pos, *next, reaplist; | 2974 | struct list_head *pos, *next, reaplist; |
3194 | time_t cutoff = get_seconds() - nn->nfsd4_lease; | 2975 | time_t cutoff = get_seconds() - nfsd4_lease; |
3195 | time_t t, clientid_val = nn->nfsd4_lease; | 2976 | time_t t, clientid_val = nfsd4_lease; |
3196 | time_t u, test_val = nn->nfsd4_lease; | 2977 | time_t u, test_val = nfsd4_lease; |
3197 | 2978 | ||
3198 | nfs4_lock_state(); | 2979 | nfs4_lock_state(); |
3199 | 2980 | ||
3200 | dprintk("NFSD: laundromat service - starting\n"); | 2981 | dprintk("NFSD: laundromat service - starting\n"); |
3201 | nfsd4_end_grace(nn); | 2982 | if (locks_in_grace()) |
2983 | nfsd4_end_grace(); | ||
3202 | INIT_LIST_HEAD(&reaplist); | 2984 | INIT_LIST_HEAD(&reaplist); |
3203 | spin_lock(&nn->client_lock); | 2985 | spin_lock(&client_lock); |
3204 | list_for_each_safe(pos, next, &nn->client_lru) { | 2986 | list_for_each_safe(pos, next, &client_lru) { |
3205 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 2987 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
3206 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { | 2988 | if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) { |
3207 | t = clp->cl_time - cutoff; | 2989 | t = clp->cl_time - cutoff; |
@@ -3217,18 +2999,17 @@ nfs4_laundromat(struct nfsd_net *nn) | |||
3217 | unhash_client_locked(clp); | 2999 | unhash_client_locked(clp); |
3218 | list_add(&clp->cl_lru, &reaplist); | 3000 | list_add(&clp->cl_lru, &reaplist); |
3219 | } | 3001 | } |
3220 | spin_unlock(&nn->client_lock); | 3002 | spin_unlock(&client_lock); |
3221 | list_for_each_safe(pos, next, &reaplist) { | 3003 | list_for_each_safe(pos, next, &reaplist) { |
3222 | clp = list_entry(pos, struct nfs4_client, cl_lru); | 3004 | clp = list_entry(pos, struct nfs4_client, cl_lru); |
3223 | dprintk("NFSD: purging unused client (clientid %08x)\n", | 3005 | dprintk("NFSD: purging unused client (clientid %08x)\n", |
3224 | clp->cl_clientid.cl_id); | 3006 | clp->cl_clientid.cl_id); |
3007 | nfsd4_remove_clid_dir(clp); | ||
3225 | expire_client(clp); | 3008 | expire_client(clp); |
3226 | } | 3009 | } |
3227 | spin_lock(&recall_lock); | 3010 | spin_lock(&recall_lock); |
3228 | list_for_each_safe(pos, next, &del_recall_lru) { | 3011 | list_for_each_safe(pos, next, &del_recall_lru) { |
3229 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 3012 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
3230 | if (net_generic(dp->dl_stid.sc_client->net, nfsd_net_id) != nn) | ||
3231 | continue; | ||
3232 | if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { | 3013 | if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) { |
3233 | u = dp->dl_time - cutoff; | 3014 | u = dp->dl_time - cutoff; |
3234 | if (test_val > u) | 3015 | if (test_val > u) |
@@ -3240,18 +3021,21 @@ nfs4_laundromat(struct nfsd_net *nn) | |||
3240 | spin_unlock(&recall_lock); | 3021 | spin_unlock(&recall_lock); |
3241 | list_for_each_safe(pos, next, &reaplist) { | 3022 | list_for_each_safe(pos, next, &reaplist) { |
3242 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 3023 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
3024 | list_del_init(&dp->dl_recall_lru); | ||
3243 | unhash_delegation(dp); | 3025 | unhash_delegation(dp); |
3244 | } | 3026 | } |
3245 | test_val = nn->nfsd4_lease; | 3027 | test_val = nfsd4_lease; |
3246 | list_for_each_safe(pos, next, &nn->close_lru) { | 3028 | list_for_each_safe(pos, next, &close_lru) { |
3247 | oo = container_of(pos, struct nfs4_openowner, oo_close_lru); | 3029 | sop = list_entry(pos, struct nfs4_stateowner, so_close_lru); |
3248 | if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) { | 3030 | if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) { |
3249 | u = oo->oo_time - cutoff; | 3031 | u = sop->so_time - cutoff; |
3250 | if (test_val > u) | 3032 | if (test_val > u) |
3251 | test_val = u; | 3033 | test_val = u; |
3252 | break; | 3034 | break; |
3253 | } | 3035 | } |
3254 | release_openowner(oo); | 3036 | dprintk("NFSD: purging unused open stateowner (so_id %d)\n", |
3037 | sop->so_id); | ||
3038 | release_openowner(sop); | ||
3255 | } | 3039 | } |
3256 | if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) | 3040 | if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) |
3257 | clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; | 3041 | clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; |
@@ -3261,32 +3045,42 @@ nfs4_laundromat(struct nfsd_net *nn) | |||
3261 | 3045 | ||
3262 | static struct workqueue_struct *laundry_wq; | 3046 | static struct workqueue_struct *laundry_wq; |
3263 | static void laundromat_main(struct work_struct *); | 3047 | static void laundromat_main(struct work_struct *); |
3048 | static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main); | ||
3264 | 3049 | ||
3265 | static void | 3050 | static void |
3266 | laundromat_main(struct work_struct *laundry) | 3051 | laundromat_main(struct work_struct *not_used) |
3267 | { | 3052 | { |
3268 | time_t t; | 3053 | time_t t; |
3269 | struct delayed_work *dwork = container_of(laundry, struct delayed_work, | ||
3270 | work); | ||
3271 | struct nfsd_net *nn = container_of(dwork, struct nfsd_net, | ||
3272 | laundromat_work); | ||
3273 | 3054 | ||
3274 | t = nfs4_laundromat(nn); | 3055 | t = nfs4_laundromat(); |
3275 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); | 3056 | dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t); |
3276 | queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); | 3057 | queue_delayed_work(laundry_wq, &laundromat_work, t*HZ); |
3277 | } | 3058 | } |
3278 | 3059 | ||
3279 | static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp) | 3060 | static struct nfs4_stateowner * |
3061 | search_close_lru(u32 st_id, int flags) | ||
3280 | { | 3062 | { |
3281 | if (fhp->fh_dentry->d_inode != stp->st_file->fi_inode) | 3063 | struct nfs4_stateowner *local = NULL; |
3282 | return nfserr_bad_stateid; | 3064 | |
3283 | return nfs_ok; | 3065 | if (flags & CLOSE_STATE) { |
3066 | list_for_each_entry(local, &close_lru, so_close_lru) { | ||
3067 | if (local->so_id == st_id) | ||
3068 | return local; | ||
3069 | } | ||
3070 | } | ||
3071 | return NULL; | ||
3072 | } | ||
3073 | |||
3074 | static inline int | ||
3075 | nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp) | ||
3076 | { | ||
3077 | return fhp->fh_dentry->d_inode != stp->st_file->fi_inode; | ||
3284 | } | 3078 | } |
3285 | 3079 | ||
3286 | static int | 3080 | static int |
3287 | STALE_STATEID(stateid_t *stateid, struct nfsd_net *nn) | 3081 | STALE_STATEID(stateid_t *stateid) |
3288 | { | 3082 | { |
3289 | if (stateid->si_opaque.so_clid.cl_boot == nn->boot_time) | 3083 | if (stateid->si_boot == boot_time) |
3290 | return 0; | 3084 | return 0; |
3291 | dprintk("NFSD: stale stateid " STATEID_FMT "!\n", | 3085 | dprintk("NFSD: stale stateid " STATEID_FMT "!\n", |
3292 | STATEID_VAL(stateid)); | 3086 | STATEID_VAL(stateid)); |
@@ -3294,31 +3088,31 @@ STALE_STATEID(stateid_t *stateid, struct nfsd_net *nn) | |||
3294 | } | 3088 | } |
3295 | 3089 | ||
3296 | static inline int | 3090 | static inline int |
3297 | access_permit_read(struct nfs4_ol_stateid *stp) | 3091 | access_permit_read(unsigned long access_bmap) |
3298 | { | 3092 | { |
3299 | return test_access(NFS4_SHARE_ACCESS_READ, stp) || | 3093 | return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) || |
3300 | test_access(NFS4_SHARE_ACCESS_BOTH, stp) || | 3094 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) || |
3301 | test_access(NFS4_SHARE_ACCESS_WRITE, stp); | 3095 | test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap); |
3302 | } | 3096 | } |
3303 | 3097 | ||
3304 | static inline int | 3098 | static inline int |
3305 | access_permit_write(struct nfs4_ol_stateid *stp) | 3099 | access_permit_write(unsigned long access_bmap) |
3306 | { | 3100 | { |
3307 | return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || | 3101 | return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) || |
3308 | test_access(NFS4_SHARE_ACCESS_BOTH, stp); | 3102 | test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap); |
3309 | } | 3103 | } |
3310 | 3104 | ||
3311 | static | 3105 | static |
3312 | __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) | 3106 | __be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags) |
3313 | { | 3107 | { |
3314 | __be32 status = nfserr_openmode; | 3108 | __be32 status = nfserr_openmode; |
3315 | 3109 | ||
3316 | /* For lock stateid's, we test the parent open, not the lock: */ | 3110 | /* For lock stateid's, we test the parent open, not the lock: */ |
3317 | if (stp->st_openstp) | 3111 | if (stp->st_openstp) |
3318 | stp = stp->st_openstp; | 3112 | stp = stp->st_openstp; |
3319 | if ((flags & WR_STATE) && !access_permit_write(stp)) | 3113 | if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap))) |
3320 | goto out; | 3114 | goto out; |
3321 | if ((flags & RD_STATE) && !access_permit_read(stp)) | 3115 | if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap))) |
3322 | goto out; | 3116 | goto out; |
3323 | status = nfs_ok; | 3117 | status = nfs_ok; |
3324 | out: | 3118 | out: |
@@ -3326,11 +3120,11 @@ out: | |||
3326 | } | 3120 | } |
3327 | 3121 | ||
3328 | static inline __be32 | 3122 | static inline __be32 |
3329 | check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, int flags) | 3123 | check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) |
3330 | { | 3124 | { |
3331 | if (ONE_STATEID(stateid) && (flags & RD_STATE)) | 3125 | if (ONE_STATEID(stateid) && (flags & RD_STATE)) |
3332 | return nfs_ok; | 3126 | return nfs_ok; |
3333 | else if (locks_in_grace(net)) { | 3127 | else if (locks_in_grace()) { |
3334 | /* Answer in remaining cases depends on existence of | 3128 | /* Answer in remaining cases depends on existence of |
3335 | * conflicting state; so we must wait out the grace period. */ | 3129 | * conflicting state; so we must wait out the grace period. */ |
3336 | return nfserr_grace; | 3130 | return nfserr_grace; |
@@ -3347,164 +3141,148 @@ check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid, | |||
3347 | * that are not able to provide mandatory locking. | 3141 | * that are not able to provide mandatory locking. |
3348 | */ | 3142 | */ |
3349 | static inline int | 3143 | static inline int |
3350 | grace_disallows_io(struct net *net, struct inode *inode) | 3144 | grace_disallows_io(struct inode *inode) |
3351 | { | ||
3352 | return locks_in_grace(net) && mandatory_lock(inode); | ||
3353 | } | ||
3354 | |||
3355 | /* Returns true iff a is later than b: */ | ||
3356 | static bool stateid_generation_after(stateid_t *a, stateid_t *b) | ||
3357 | { | 3145 | { |
3358 | return (s32)a->si_generation - (s32)b->si_generation > 0; | 3146 | return locks_in_grace() && mandatory_lock(inode); |
3359 | } | 3147 | } |
3360 | 3148 | ||
3361 | static __be32 check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) | 3149 | static int check_stateid_generation(stateid_t *in, stateid_t *ref, int flags) |
3362 | { | 3150 | { |
3363 | /* | 3151 | /* |
3364 | * When sessions are used the stateid generation number is ignored | 3152 | * When sessions are used the stateid generation number is ignored |
3365 | * when it is zero. | 3153 | * when it is zero. |
3366 | */ | 3154 | */ |
3367 | if (has_session && in->si_generation == 0) | 3155 | if ((flags & HAS_SESSION) && in->si_generation == 0) |
3368 | return nfs_ok; | 3156 | goto out; |
3369 | |||
3370 | if (in->si_generation == ref->si_generation) | ||
3371 | return nfs_ok; | ||
3372 | 3157 | ||
3373 | /* If the client sends us a stateid from the future, it's buggy: */ | 3158 | /* If the client sends us a stateid from the future, it's buggy: */ |
3374 | if (stateid_generation_after(in, ref)) | 3159 | if (in->si_generation > ref->si_generation) |
3375 | return nfserr_bad_stateid; | 3160 | return nfserr_bad_stateid; |
3376 | /* | 3161 | /* |
3377 | * However, we could see a stateid from the past, even from a | 3162 | * The following, however, can happen. For example, if the |
3378 | * non-buggy client. For example, if the client sends a lock | 3163 | * client sends an open and some IO at the same time, the open |
3379 | * while some IO is outstanding, the lock may bump si_generation | 3164 | * may bump si_generation while the IO is still in flight. |
3380 | * while the IO is still in flight. The client could avoid that | 3165 | * Thanks to hard links and renames, the client never knows what |
3381 | * situation by waiting for responses on all the IO requests, | 3166 | * file an open will affect. So it could avoid that situation |
3382 | * but better performance may result in retrying IO that | 3167 | * only by serializing all opens and IO from the same open |
3383 | * receives an old_stateid error if requests are rarely | 3168 | * owner. To recover from the old_stateid error, the client |
3384 | * reordered in flight: | 3169 | * will just have to retry the IO: |
3385 | */ | 3170 | */ |
3386 | return nfserr_old_stateid; | 3171 | if (in->si_generation < ref->si_generation) |
3172 | return nfserr_old_stateid; | ||
3173 | out: | ||
3174 | return nfs_ok; | ||
3387 | } | 3175 | } |
3388 | 3176 | ||
3389 | static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid) | 3177 | static int is_delegation_stateid(stateid_t *stateid) |
3390 | { | 3178 | { |
3391 | struct nfs4_stid *s; | 3179 | return stateid->si_fileid == 0; |
3392 | struct nfs4_ol_stateid *ols; | 3180 | } |
3393 | __be32 status; | ||
3394 | 3181 | ||
3395 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3182 | static int is_open_stateid(struct nfs4_stateid *stateid) |
3396 | return nfserr_bad_stateid; | 3183 | { |
3397 | /* Client debugging aid. */ | 3184 | return stateid->st_openstp == NULL; |
3398 | if (!same_clid(&stateid->si_opaque.so_clid, &cl->cl_clientid)) { | ||
3399 | char addr_str[INET6_ADDRSTRLEN]; | ||
3400 | rpc_ntop((struct sockaddr *)&cl->cl_addr, addr_str, | ||
3401 | sizeof(addr_str)); | ||
3402 | pr_warn_ratelimited("NFSD: client %s testing state ID " | ||
3403 | "with incorrect client ID\n", addr_str); | ||
3404 | return nfserr_bad_stateid; | ||
3405 | } | ||
3406 | s = find_stateid(cl, stateid); | ||
3407 | if (!s) | ||
3408 | return nfserr_bad_stateid; | ||
3409 | status = check_stateid_generation(stateid, &s->sc_stateid, 1); | ||
3410 | if (status) | ||
3411 | return status; | ||
3412 | if (!(s->sc_type & (NFS4_OPEN_STID | NFS4_LOCK_STID))) | ||
3413 | return nfs_ok; | ||
3414 | ols = openlockstateid(s); | ||
3415 | if (ols->st_stateowner->so_is_open_owner | ||
3416 | && !(openowner(ols->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) | ||
3417 | return nfserr_bad_stateid; | ||
3418 | return nfs_ok; | ||
3419 | } | 3185 | } |
3420 | 3186 | ||
3421 | static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, | 3187 | __be32 nfs4_validate_stateid(stateid_t *stateid, int flags) |
3422 | struct nfs4_stid **s, bool sessions, | ||
3423 | struct nfsd_net *nn) | ||
3424 | { | 3188 | { |
3425 | struct nfs4_client *cl; | 3189 | struct nfs4_stateid *stp = NULL; |
3190 | __be32 status = nfserr_stale_stateid; | ||
3426 | 3191 | ||
3427 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3192 | if (STALE_STATEID(stateid)) |
3428 | return nfserr_bad_stateid; | 3193 | goto out; |
3429 | if (STALE_STATEID(stateid, nn)) | ||
3430 | return nfserr_stale_stateid; | ||
3431 | cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions, nn); | ||
3432 | if (!cl) | ||
3433 | return nfserr_expired; | ||
3434 | *s = find_stateid_by_type(cl, stateid, typemask); | ||
3435 | if (!*s) | ||
3436 | return nfserr_bad_stateid; | ||
3437 | return nfs_ok; | ||
3438 | 3194 | ||
3195 | status = nfserr_expired; | ||
3196 | stp = search_for_stateid(stateid); | ||
3197 | if (!stp) | ||
3198 | goto out; | ||
3199 | status = nfserr_bad_stateid; | ||
3200 | |||
3201 | if (!stp->st_stateowner->so_confirmed) | ||
3202 | goto out; | ||
3203 | |||
3204 | status = check_stateid_generation(stateid, &stp->st_stateid, flags); | ||
3205 | if (status) | ||
3206 | goto out; | ||
3207 | |||
3208 | status = nfs_ok; | ||
3209 | out: | ||
3210 | return status; | ||
3439 | } | 3211 | } |
3440 | 3212 | ||
3441 | /* | 3213 | /* |
3442 | * Checks for stateid operations | 3214 | * Checks for stateid operations |
3443 | */ | 3215 | */ |
3444 | __be32 | 3216 | __be32 |
3445 | nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate, | 3217 | nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, |
3446 | stateid_t *stateid, int flags, struct file **filpp) | 3218 | stateid_t *stateid, int flags, struct file **filpp) |
3447 | { | 3219 | { |
3448 | struct nfs4_stid *s; | 3220 | struct nfs4_stateid *stp = NULL; |
3449 | struct nfs4_ol_stateid *stp = NULL; | ||
3450 | struct nfs4_delegation *dp = NULL; | 3221 | struct nfs4_delegation *dp = NULL; |
3451 | struct svc_fh *current_fh = &cstate->current_fh; | 3222 | struct svc_fh *current_fh = &cstate->current_fh; |
3452 | struct inode *ino = current_fh->fh_dentry->d_inode; | 3223 | struct inode *ino = current_fh->fh_dentry->d_inode; |
3453 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
3454 | __be32 status; | 3224 | __be32 status; |
3455 | 3225 | ||
3456 | if (filpp) | 3226 | if (filpp) |
3457 | *filpp = NULL; | 3227 | *filpp = NULL; |
3458 | 3228 | ||
3459 | if (grace_disallows_io(net, ino)) | 3229 | if (grace_disallows_io(ino)) |
3460 | return nfserr_grace; | 3230 | return nfserr_grace; |
3461 | 3231 | ||
3232 | if (nfsd4_has_session(cstate)) | ||
3233 | flags |= HAS_SESSION; | ||
3234 | |||
3462 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 3235 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
3463 | return check_special_stateids(net, current_fh, stateid, flags); | 3236 | return check_special_stateids(current_fh, stateid, flags); |
3464 | 3237 | ||
3465 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, | 3238 | status = nfserr_stale_stateid; |
3466 | &s, cstate->minorversion, nn); | 3239 | if (STALE_STATEID(stateid)) |
3467 | if (status) | ||
3468 | return status; | ||
3469 | status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); | ||
3470 | if (status) | ||
3471 | goto out; | 3240 | goto out; |
3472 | switch (s->sc_type) { | 3241 | |
3473 | case NFS4_DELEG_STID: | 3242 | /* |
3474 | dp = delegstateid(s); | 3243 | * We assume that any stateid that has the current boot time, |
3244 | * but that we can't find, is expired: | ||
3245 | */ | ||
3246 | status = nfserr_expired; | ||
3247 | if (is_delegation_stateid(stateid)) { | ||
3248 | dp = find_delegation_stateid(ino, stateid); | ||
3249 | if (!dp) | ||
3250 | goto out; | ||
3251 | status = check_stateid_generation(stateid, &dp->dl_stateid, | ||
3252 | flags); | ||
3253 | if (status) | ||
3254 | goto out; | ||
3475 | status = nfs4_check_delegmode(dp, flags); | 3255 | status = nfs4_check_delegmode(dp, flags); |
3476 | if (status) | 3256 | if (status) |
3477 | goto out; | 3257 | goto out; |
3258 | renew_client(dp->dl_client); | ||
3478 | if (filpp) { | 3259 | if (filpp) { |
3479 | *filpp = dp->dl_file->fi_deleg_file; | 3260 | *filpp = dp->dl_file->fi_deleg_file; |
3480 | if (!*filpp) { | 3261 | BUG_ON(!*filpp); |
3481 | WARN_ON_ONCE(1); | ||
3482 | status = nfserr_serverfault; | ||
3483 | goto out; | ||
3484 | } | ||
3485 | } | 3262 | } |
3486 | break; | 3263 | } else { /* open or lock stateid */ |
3487 | case NFS4_OPEN_STID: | 3264 | stp = find_stateid(stateid, flags); |
3488 | case NFS4_LOCK_STID: | 3265 | if (!stp) |
3489 | stp = openlockstateid(s); | ||
3490 | status = nfs4_check_fh(current_fh, stp); | ||
3491 | if (status) | ||
3492 | goto out; | 3266 | goto out; |
3493 | if (stp->st_stateowner->so_is_open_owner | 3267 | status = nfserr_bad_stateid; |
3494 | && !(openowner(stp->st_stateowner)->oo_flags & NFS4_OO_CONFIRMED)) | 3268 | if (nfs4_check_fh(current_fh, stp)) |
3269 | goto out; | ||
3270 | if (!stp->st_stateowner->so_confirmed) | ||
3271 | goto out; | ||
3272 | status = check_stateid_generation(stateid, &stp->st_stateid, | ||
3273 | flags); | ||
3274 | if (status) | ||
3495 | goto out; | 3275 | goto out; |
3496 | status = nfs4_check_openmode(stp, flags); | 3276 | status = nfs4_check_openmode(stp, flags); |
3497 | if (status) | 3277 | if (status) |
3498 | goto out; | 3278 | goto out; |
3279 | renew_client(stp->st_stateowner->so_client); | ||
3499 | if (filpp) { | 3280 | if (filpp) { |
3500 | if (flags & RD_STATE) | 3281 | if (flags & RD_STATE) |
3501 | *filpp = find_readable_file(stp->st_file); | 3282 | *filpp = find_readable_file(stp->st_file); |
3502 | else | 3283 | else |
3503 | *filpp = find_writeable_file(stp->st_file); | 3284 | *filpp = find_writeable_file(stp->st_file); |
3504 | } | 3285 | } |
3505 | break; | ||
3506 | default: | ||
3507 | return nfserr_bad_stateid; | ||
3508 | } | 3286 | } |
3509 | status = nfs_ok; | 3287 | status = nfs_ok; |
3510 | out: | 3288 | out: |
@@ -3512,9 +3290,18 @@ out: | |||
3512 | } | 3290 | } |
3513 | 3291 | ||
3514 | static __be32 | 3292 | static __be32 |
3515 | nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp) | 3293 | nfsd4_free_delegation_stateid(stateid_t *stateid) |
3294 | { | ||
3295 | struct nfs4_delegation *dp = search_for_delegation(stateid); | ||
3296 | if (dp) | ||
3297 | return nfserr_locks_held; | ||
3298 | return nfserr_bad_stateid; | ||
3299 | } | ||
3300 | |||
3301 | static __be32 | ||
3302 | nfsd4_free_lock_stateid(struct nfs4_stateid *stp) | ||
3516 | { | 3303 | { |
3517 | if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner))) | 3304 | if (check_for_locks(stp->st_file, stp->st_stateowner)) |
3518 | return nfserr_locks_held; | 3305 | return nfserr_locks_held; |
3519 | release_lock_stateid(stp); | 3306 | release_lock_stateid(stp); |
3520 | return nfs_ok; | 3307 | return nfs_ok; |
@@ -3527,48 +3314,51 @@ __be32 | |||
3527 | nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3314 | nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
3528 | struct nfsd4_test_stateid *test_stateid) | 3315 | struct nfsd4_test_stateid *test_stateid) |
3529 | { | 3316 | { |
3530 | struct nfsd4_test_stateid_id *stateid; | 3317 | test_stateid->ts_has_session = nfsd4_has_session(cstate); |
3531 | struct nfs4_client *cl = cstate->session->se_client; | ||
3532 | |||
3533 | nfs4_lock_state(); | ||
3534 | list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) | ||
3535 | stateid->ts_id_status = | ||
3536 | nfsd4_validate_stateid(cl, &stateid->ts_id_stateid); | ||
3537 | nfs4_unlock_state(); | ||
3538 | |||
3539 | return nfs_ok; | 3318 | return nfs_ok; |
3540 | } | 3319 | } |
3541 | 3320 | ||
3321 | /* | ||
3322 | * Free a state id | ||
3323 | */ | ||
3542 | __be32 | 3324 | __be32 |
3543 | nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3325 | nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
3544 | struct nfsd4_free_stateid *free_stateid) | 3326 | struct nfsd4_free_stateid *free_stateid) |
3545 | { | 3327 | { |
3546 | stateid_t *stateid = &free_stateid->fr_stateid; | 3328 | stateid_t *stateid = &free_stateid->fr_stateid; |
3547 | struct nfs4_stid *s; | 3329 | struct nfs4_stateid *stp; |
3548 | struct nfs4_client *cl = cstate->session->se_client; | 3330 | __be32 ret; |
3549 | __be32 ret = nfserr_bad_stateid; | ||
3550 | 3331 | ||
3551 | nfs4_lock_state(); | 3332 | nfs4_lock_state(); |
3552 | s = find_stateid(cl, stateid); | 3333 | if (is_delegation_stateid(stateid)) { |
3553 | if (!s) | 3334 | ret = nfsd4_free_delegation_stateid(stateid); |
3554 | goto out; | 3335 | goto out; |
3555 | switch (s->sc_type) { | 3336 | } |
3556 | case NFS4_DELEG_STID: | 3337 | |
3557 | ret = nfserr_locks_held; | 3338 | stp = search_for_stateid(stateid); |
3339 | if (!stp) { | ||
3340 | ret = nfserr_bad_stateid; | ||
3558 | goto out; | 3341 | goto out; |
3559 | case NFS4_OPEN_STID: | 3342 | } |
3560 | case NFS4_LOCK_STID: | 3343 | if (stateid->si_generation != 0) { |
3561 | ret = check_stateid_generation(stateid, &s->sc_stateid, 1); | 3344 | if (stateid->si_generation < stp->st_stateid.si_generation) { |
3562 | if (ret) | 3345 | ret = nfserr_old_stateid; |
3563 | goto out; | 3346 | goto out; |
3564 | if (s->sc_type == NFS4_LOCK_STID) | 3347 | } |
3565 | ret = nfsd4_free_lock_stateid(openlockstateid(s)); | 3348 | if (stateid->si_generation > stp->st_stateid.si_generation) { |
3566 | else | 3349 | ret = nfserr_bad_stateid; |
3567 | ret = nfserr_locks_held; | 3350 | goto out; |
3568 | break; | 3351 | } |
3569 | default: | ||
3570 | ret = nfserr_bad_stateid; | ||
3571 | } | 3352 | } |
3353 | |||
3354 | if (is_open_stateid(stp)) { | ||
3355 | ret = nfserr_locks_held; | ||
3356 | goto out; | ||
3357 | } else { | ||
3358 | ret = nfsd4_free_lock_stateid(stp); | ||
3359 | goto out; | ||
3360 | } | ||
3361 | |||
3572 | out: | 3362 | out: |
3573 | nfs4_unlock_state(); | 3363 | nfs4_unlock_state(); |
3574 | return ret; | 3364 | return ret; |
@@ -3581,67 +3371,124 @@ setlkflg (int type) | |||
3581 | RD_STATE : WR_STATE; | 3371 | RD_STATE : WR_STATE; |
3582 | } | 3372 | } |
3583 | 3373 | ||
3584 | static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp) | ||
3585 | { | ||
3586 | struct svc_fh *current_fh = &cstate->current_fh; | ||
3587 | struct nfs4_stateowner *sop = stp->st_stateowner; | ||
3588 | __be32 status; | ||
3589 | |||
3590 | status = nfsd4_check_seqid(cstate, sop, seqid); | ||
3591 | if (status) | ||
3592 | return status; | ||
3593 | if (stp->st_stid.sc_type == NFS4_CLOSED_STID) | ||
3594 | /* | ||
3595 | * "Closed" stateid's exist *only* to return | ||
3596 | * nfserr_replay_me from the previous step. | ||
3597 | */ | ||
3598 | return nfserr_bad_stateid; | ||
3599 | status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); | ||
3600 | if (status) | ||
3601 | return status; | ||
3602 | return nfs4_check_fh(current_fh, stp); | ||
3603 | } | ||
3604 | |||
3605 | /* | 3374 | /* |
3606 | * Checks for sequence id mutating operations. | 3375 | * Checks for sequence id mutating operations. |
3607 | */ | 3376 | */ |
3608 | static __be32 | 3377 | static __be32 |
3609 | nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | 3378 | nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, |
3610 | stateid_t *stateid, char typemask, | 3379 | stateid_t *stateid, int flags, |
3611 | struct nfs4_ol_stateid **stpp, | 3380 | struct nfs4_stateowner **sopp, |
3612 | struct nfsd_net *nn) | 3381 | struct nfs4_stateid **stpp, struct nfsd4_lock *lock) |
3613 | { | 3382 | { |
3383 | struct nfs4_stateid *stp; | ||
3384 | struct nfs4_stateowner *sop; | ||
3385 | struct svc_fh *current_fh = &cstate->current_fh; | ||
3614 | __be32 status; | 3386 | __be32 status; |
3615 | struct nfs4_stid *s; | ||
3616 | 3387 | ||
3617 | dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, | 3388 | dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__, |
3618 | seqid, STATEID_VAL(stateid)); | 3389 | seqid, STATEID_VAL(stateid)); |
3619 | 3390 | ||
3620 | *stpp = NULL; | 3391 | *stpp = NULL; |
3621 | status = nfsd4_lookup_stateid(stateid, typemask, &s, | 3392 | *sopp = NULL; |
3622 | cstate->minorversion, nn); | ||
3623 | if (status) | ||
3624 | return status; | ||
3625 | *stpp = openlockstateid(s); | ||
3626 | cstate->replay_owner = (*stpp)->st_stateowner; | ||
3627 | 3393 | ||
3628 | return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp); | 3394 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { |
3629 | } | 3395 | dprintk("NFSD: preprocess_seqid_op: magic stateid!\n"); |
3396 | return nfserr_bad_stateid; | ||
3397 | } | ||
3630 | 3398 | ||
3631 | static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, | 3399 | if (STALE_STATEID(stateid)) |
3632 | stateid_t *stateid, struct nfs4_ol_stateid **stpp, struct nfsd_net *nn) | 3400 | return nfserr_stale_stateid; |
3633 | { | 3401 | |
3634 | __be32 status; | 3402 | if (nfsd4_has_session(cstate)) |
3635 | struct nfs4_openowner *oo; | 3403 | flags |= HAS_SESSION; |
3404 | |||
3405 | /* | ||
3406 | * We return BAD_STATEID if filehandle doesn't match stateid, | ||
3407 | * the confirmed flag is incorrecly set, or the generation | ||
3408 | * number is incorrect. | ||
3409 | */ | ||
3410 | stp = find_stateid(stateid, flags); | ||
3411 | if (stp == NULL) { | ||
3412 | /* | ||
3413 | * Also, we should make sure this isn't just the result of | ||
3414 | * a replayed close: | ||
3415 | */ | ||
3416 | sop = search_close_lru(stateid->si_stateownerid, flags); | ||
3417 | /* It's not stale; let's assume it's expired: */ | ||
3418 | if (sop == NULL) | ||
3419 | return nfserr_expired; | ||
3420 | *sopp = sop; | ||
3421 | goto check_replay; | ||
3422 | } | ||
3423 | |||
3424 | *stpp = stp; | ||
3425 | *sopp = sop = stp->st_stateowner; | ||
3426 | |||
3427 | if (lock) { | ||
3428 | clientid_t *lockclid = &lock->v.new.clientid; | ||
3429 | struct nfs4_client *clp = sop->so_client; | ||
3430 | int lkflg = 0; | ||
3431 | __be32 status; | ||
3432 | |||
3433 | lkflg = setlkflg(lock->lk_type); | ||
3434 | |||
3435 | if (lock->lk_is_new) { | ||
3436 | if (!sop->so_is_open_owner) | ||
3437 | return nfserr_bad_stateid; | ||
3438 | if (!(flags & HAS_SESSION) && | ||
3439 | !same_clid(&clp->cl_clientid, lockclid)) | ||
3440 | return nfserr_bad_stateid; | ||
3441 | /* stp is the open stateid */ | ||
3442 | status = nfs4_check_openmode(stp, lkflg); | ||
3443 | if (status) | ||
3444 | return status; | ||
3445 | } else { | ||
3446 | /* stp is the lock stateid */ | ||
3447 | status = nfs4_check_openmode(stp->st_openstp, lkflg); | ||
3448 | if (status) | ||
3449 | return status; | ||
3450 | } | ||
3451 | } | ||
3452 | |||
3453 | if (nfs4_check_fh(current_fh, stp)) { | ||
3454 | dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n"); | ||
3455 | return nfserr_bad_stateid; | ||
3456 | } | ||
3457 | |||
3458 | /* | ||
3459 | * We now validate the seqid and stateid generation numbers. | ||
3460 | * For the moment, we ignore the possibility of | ||
3461 | * generation number wraparound. | ||
3462 | */ | ||
3463 | if (!(flags & HAS_SESSION) && seqid != sop->so_seqid) | ||
3464 | goto check_replay; | ||
3636 | 3465 | ||
3637 | status = nfs4_preprocess_seqid_op(cstate, seqid, stateid, | 3466 | if (sop->so_confirmed && flags & CONFIRM) { |
3638 | NFS4_OPEN_STID, stpp, nn); | 3467 | dprintk("NFSD: preprocess_seqid_op: expected" |
3468 | " unconfirmed stateowner!\n"); | ||
3469 | return nfserr_bad_stateid; | ||
3470 | } | ||
3471 | if (!sop->so_confirmed && !(flags & CONFIRM)) { | ||
3472 | dprintk("NFSD: preprocess_seqid_op: stateowner not" | ||
3473 | " confirmed yet!\n"); | ||
3474 | return nfserr_bad_stateid; | ||
3475 | } | ||
3476 | status = check_stateid_generation(stateid, &stp->st_stateid, flags); | ||
3639 | if (status) | 3477 | if (status) |
3640 | return status; | 3478 | return status; |
3641 | oo = openowner((*stpp)->st_stateowner); | 3479 | renew_client(sop->so_client); |
3642 | if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) | ||
3643 | return nfserr_bad_stateid; | ||
3644 | return nfs_ok; | 3480 | return nfs_ok; |
3481 | |||
3482 | check_replay: | ||
3483 | if (seqid == sop->so_seqid - 1) { | ||
3484 | dprintk("NFSD: preprocess_seqid_op: retransmission?\n"); | ||
3485 | /* indicate replay to calling function */ | ||
3486 | return nfserr_replay_me; | ||
3487 | } | ||
3488 | dprintk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n", | ||
3489 | sop->so_seqid, seqid); | ||
3490 | *sopp = NULL; | ||
3491 | return nfserr_bad_seqid; | ||
3645 | } | 3492 | } |
3646 | 3493 | ||
3647 | __be32 | 3494 | __be32 |
@@ -3649,9 +3496,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3649 | struct nfsd4_open_confirm *oc) | 3496 | struct nfsd4_open_confirm *oc) |
3650 | { | 3497 | { |
3651 | __be32 status; | 3498 | __be32 status; |
3652 | struct nfs4_openowner *oo; | 3499 | struct nfs4_stateowner *sop; |
3653 | struct nfs4_ol_stateid *stp; | 3500 | struct nfs4_stateid *stp; |
3654 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
3655 | 3501 | ||
3656 | dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", | 3502 | dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", |
3657 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3503 | (int)cstate->current_fh.fh_dentry->d_name.len, |
@@ -3663,62 +3509,49 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3663 | 3509 | ||
3664 | nfs4_lock_state(); | 3510 | nfs4_lock_state(); |
3665 | 3511 | ||
3666 | status = nfs4_preprocess_seqid_op(cstate, | 3512 | if ((status = nfs4_preprocess_seqid_op(cstate, |
3667 | oc->oc_seqid, &oc->oc_req_stateid, | 3513 | oc->oc_seqid, &oc->oc_req_stateid, |
3668 | NFS4_OPEN_STID, &stp, nn); | 3514 | CONFIRM | OPEN_STATE, |
3669 | if (status) | 3515 | &oc->oc_stateowner, &stp, NULL))) |
3670 | goto out; | 3516 | goto out; |
3671 | oo = openowner(stp->st_stateowner); | 3517 | |
3672 | status = nfserr_bad_stateid; | 3518 | sop = oc->oc_stateowner; |
3673 | if (oo->oo_flags & NFS4_OO_CONFIRMED) | 3519 | sop->so_confirmed = 1; |
3674 | goto out; | 3520 | update_stateid(&stp->st_stateid); |
3675 | oo->oo_flags |= NFS4_OO_CONFIRMED; | 3521 | memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t)); |
3676 | update_stateid(&stp->st_stid.sc_stateid); | ||
3677 | memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | ||
3678 | dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", | 3522 | dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", |
3679 | __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); | 3523 | __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stateid)); |
3680 | 3524 | ||
3681 | nfsd4_client_record_create(oo->oo_owner.so_client); | 3525 | nfsd4_create_clid_dir(sop->so_client); |
3682 | status = nfs_ok; | ||
3683 | out: | 3526 | out: |
3684 | if (!cstate->replay_owner) | 3527 | if (oc->oc_stateowner) { |
3685 | nfs4_unlock_state(); | 3528 | nfs4_get_stateowner(oc->oc_stateowner); |
3529 | cstate->replay_owner = oc->oc_stateowner; | ||
3530 | } | ||
3531 | nfs4_unlock_state(); | ||
3686 | return status; | 3532 | return status; |
3687 | } | 3533 | } |
3688 | 3534 | ||
3689 | static inline void nfs4_stateid_downgrade_bit(struct nfs4_ol_stateid *stp, u32 access) | 3535 | static inline void nfs4_file_downgrade(struct nfs4_stateid *stp, unsigned int to_access) |
3690 | { | 3536 | { |
3691 | if (!test_access(access, stp)) | 3537 | int i; |
3692 | return; | ||
3693 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(access)); | ||
3694 | clear_access(access, stp); | ||
3695 | } | ||
3696 | 3538 | ||
3697 | static inline void nfs4_stateid_downgrade(struct nfs4_ol_stateid *stp, u32 to_access) | 3539 | for (i = 1; i < 4; i++) { |
3698 | { | 3540 | if (test_bit(i, &stp->st_access_bmap) |
3699 | switch (to_access) { | 3541 | && ((i & to_access) != i)) { |
3700 | case NFS4_SHARE_ACCESS_READ: | 3542 | nfs4_file_put_access(stp->st_file, nfs4_access_to_omode(i)); |
3701 | nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_WRITE); | 3543 | __clear_bit(i, &stp->st_access_bmap); |
3702 | nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); | 3544 | } |
3703 | break; | ||
3704 | case NFS4_SHARE_ACCESS_WRITE: | ||
3705 | nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_READ); | ||
3706 | nfs4_stateid_downgrade_bit(stp, NFS4_SHARE_ACCESS_BOTH); | ||
3707 | break; | ||
3708 | case NFS4_SHARE_ACCESS_BOTH: | ||
3709 | break; | ||
3710 | default: | ||
3711 | WARN_ON_ONCE(1); | ||
3712 | } | 3545 | } |
3713 | } | 3546 | } |
3714 | 3547 | ||
3715 | static void | 3548 | static void |
3716 | reset_union_bmap_deny(unsigned long deny, struct nfs4_ol_stateid *stp) | 3549 | reset_union_bmap_deny(unsigned long deny, unsigned long *bmap) |
3717 | { | 3550 | { |
3718 | int i; | 3551 | int i; |
3719 | for (i = 0; i < 4; i++) { | 3552 | for (i = 0; i < 4; i++) { |
3720 | if ((i & deny) != i) | 3553 | if ((i & deny) != i) |
3721 | clear_deny(i, stp); | 3554 | __clear_bit(i, bmap); |
3722 | } | 3555 | } |
3723 | } | 3556 | } |
3724 | 3557 | ||
@@ -3728,71 +3561,51 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
3728 | struct nfsd4_open_downgrade *od) | 3561 | struct nfsd4_open_downgrade *od) |
3729 | { | 3562 | { |
3730 | __be32 status; | 3563 | __be32 status; |
3731 | struct nfs4_ol_stateid *stp; | 3564 | struct nfs4_stateid *stp; |
3732 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
3733 | 3565 | ||
3734 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", | 3566 | dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", |
3735 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3567 | (int)cstate->current_fh.fh_dentry->d_name.len, |
3736 | cstate->current_fh.fh_dentry->d_name.name); | 3568 | cstate->current_fh.fh_dentry->d_name.name); |
3737 | 3569 | ||
3570 | if (!access_valid(od->od_share_access, cstate->minorversion) | ||
3571 | || !deny_valid(od->od_share_deny)) | ||
3572 | return nfserr_inval; | ||
3738 | /* We don't yet support WANT bits: */ | 3573 | /* We don't yet support WANT bits: */ |
3739 | if (od->od_deleg_want) | 3574 | od->od_share_access &= NFS4_SHARE_ACCESS_MASK; |
3740 | dprintk("NFSD: %s: od_deleg_want=0x%x ignored\n", __func__, | ||
3741 | od->od_deleg_want); | ||
3742 | 3575 | ||
3743 | nfs4_lock_state(); | 3576 | nfs4_lock_state(); |
3744 | status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid, | 3577 | if ((status = nfs4_preprocess_seqid_op(cstate, |
3745 | &od->od_stateid, &stp, nn); | 3578 | od->od_seqid, |
3746 | if (status) | 3579 | &od->od_stateid, |
3580 | OPEN_STATE, | ||
3581 | &od->od_stateowner, &stp, NULL))) | ||
3747 | goto out; | 3582 | goto out; |
3583 | |||
3748 | status = nfserr_inval; | 3584 | status = nfserr_inval; |
3749 | if (!test_access(od->od_share_access, stp)) { | 3585 | if (!test_bit(od->od_share_access, &stp->st_access_bmap)) { |
3750 | dprintk("NFSD: access not a subset current bitmap: 0x%lx, input access=%08x\n", | 3586 | dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", |
3751 | stp->st_access_bmap, od->od_share_access); | 3587 | stp->st_access_bmap, od->od_share_access); |
3752 | goto out; | 3588 | goto out; |
3753 | } | 3589 | } |
3754 | if (!test_deny(od->od_share_deny, stp)) { | 3590 | if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) { |
3755 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", | 3591 | dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", |
3756 | stp->st_deny_bmap, od->od_share_deny); | 3592 | stp->st_deny_bmap, od->od_share_deny); |
3757 | goto out; | 3593 | goto out; |
3758 | } | 3594 | } |
3759 | nfs4_stateid_downgrade(stp, od->od_share_access); | 3595 | nfs4_file_downgrade(stp, od->od_share_access); |
3760 | 3596 | ||
3761 | reset_union_bmap_deny(od->od_share_deny, stp); | 3597 | reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap); |
3762 | 3598 | ||
3763 | update_stateid(&stp->st_stid.sc_stateid); | 3599 | update_stateid(&stp->st_stateid); |
3764 | memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3600 | memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t)); |
3765 | status = nfs_ok; | 3601 | status = nfs_ok; |
3766 | out: | 3602 | out: |
3767 | if (!cstate->replay_owner) | 3603 | if (od->od_stateowner) { |
3768 | nfs4_unlock_state(); | 3604 | nfs4_get_stateowner(od->od_stateowner); |
3769 | return status; | 3605 | cstate->replay_owner = od->od_stateowner; |
3770 | } | ||
3771 | |||
3772 | void nfsd4_purge_closed_stateid(struct nfs4_stateowner *so) | ||
3773 | { | ||
3774 | struct nfs4_openowner *oo; | ||
3775 | struct nfs4_ol_stateid *s; | ||
3776 | |||
3777 | if (!so->so_is_open_owner) | ||
3778 | return; | ||
3779 | oo = openowner(so); | ||
3780 | s = oo->oo_last_closed_stid; | ||
3781 | if (!s) | ||
3782 | return; | ||
3783 | if (!(oo->oo_flags & NFS4_OO_PURGE_CLOSE)) { | ||
3784 | /* Release the last_closed_stid on the next seqid bump: */ | ||
3785 | oo->oo_flags |= NFS4_OO_PURGE_CLOSE; | ||
3786 | return; | ||
3787 | } | 3606 | } |
3788 | oo->oo_flags &= ~NFS4_OO_PURGE_CLOSE; | 3607 | nfs4_unlock_state(); |
3789 | release_last_closed_stateid(oo); | 3608 | return status; |
3790 | } | ||
3791 | |||
3792 | static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) | ||
3793 | { | ||
3794 | unhash_open_stateid(s); | ||
3795 | s->st_stid.sc_type = NFS4_CLOSED_STID; | ||
3796 | } | 3609 | } |
3797 | 3610 | ||
3798 | /* | 3611 | /* |
@@ -3803,47 +3616,39 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3803 | struct nfsd4_close *close) | 3616 | struct nfsd4_close *close) |
3804 | { | 3617 | { |
3805 | __be32 status; | 3618 | __be32 status; |
3806 | struct nfs4_openowner *oo; | 3619 | struct nfs4_stateid *stp; |
3807 | struct nfs4_ol_stateid *stp; | ||
3808 | struct net *net = SVC_NET(rqstp); | ||
3809 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
3810 | 3620 | ||
3811 | dprintk("NFSD: nfsd4_close on file %.*s\n", | 3621 | dprintk("NFSD: nfsd4_close on file %.*s\n", |
3812 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3622 | (int)cstate->current_fh.fh_dentry->d_name.len, |
3813 | cstate->current_fh.fh_dentry->d_name.name); | 3623 | cstate->current_fh.fh_dentry->d_name.name); |
3814 | 3624 | ||
3815 | nfs4_lock_state(); | 3625 | nfs4_lock_state(); |
3816 | status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, | 3626 | /* check close_lru for replay */ |
3817 | &close->cl_stateid, | 3627 | if ((status = nfs4_preprocess_seqid_op(cstate, |
3818 | NFS4_OPEN_STID|NFS4_CLOSED_STID, | 3628 | close->cl_seqid, |
3819 | &stp, nn); | 3629 | &close->cl_stateid, |
3820 | if (status) | 3630 | OPEN_STATE | CLOSE_STATE, |
3631 | &close->cl_stateowner, &stp, NULL))) | ||
3821 | goto out; | 3632 | goto out; |
3822 | oo = openowner(stp->st_stateowner); | ||
3823 | status = nfs_ok; | 3633 | status = nfs_ok; |
3824 | update_stateid(&stp->st_stid.sc_stateid); | 3634 | update_stateid(&stp->st_stateid); |
3825 | memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 3635 | memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); |
3826 | 3636 | ||
3827 | nfsd4_close_open_stateid(stp); | 3637 | /* release_stateid() calls nfsd_close() if needed */ |
3828 | release_last_closed_stateid(oo); | 3638 | release_open_stateid(stp); |
3829 | oo->oo_last_closed_stid = stp; | ||
3830 | 3639 | ||
3831 | if (list_empty(&oo->oo_owner.so_stateids)) { | 3640 | /* place unused nfs4_stateowners on so_close_lru list to be |
3832 | if (cstate->minorversion) { | 3641 | * released by the laundromat service after the lease period |
3833 | release_openowner(oo); | 3642 | * to enable us to handle CLOSE replay |
3834 | cstate->replay_owner = NULL; | 3643 | */ |
3835 | } else { | 3644 | if (list_empty(&close->cl_stateowner->so_stateids)) |
3836 | /* | 3645 | move_to_close_lru(close->cl_stateowner); |
3837 | * In the 4.0 case we need to keep the owners around a | ||
3838 | * little while to handle CLOSE replay. | ||
3839 | */ | ||
3840 | if (list_empty(&oo->oo_owner.so_stateids)) | ||
3841 | move_to_close_lru(oo, SVC_NET(rqstp)); | ||
3842 | } | ||
3843 | } | ||
3844 | out: | 3646 | out: |
3845 | if (!cstate->replay_owner) | 3647 | if (close->cl_stateowner) { |
3846 | nfs4_unlock_state(); | 3648 | nfs4_get_stateowner(close->cl_stateowner); |
3649 | cstate->replay_owner = close->cl_stateowner; | ||
3650 | } | ||
3651 | nfs4_unlock_state(); | ||
3847 | return status; | 3652 | return status; |
3848 | } | 3653 | } |
3849 | 3654 | ||
@@ -3853,22 +3658,34 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
3853 | { | 3658 | { |
3854 | struct nfs4_delegation *dp; | 3659 | struct nfs4_delegation *dp; |
3855 | stateid_t *stateid = &dr->dr_stateid; | 3660 | stateid_t *stateid = &dr->dr_stateid; |
3856 | struct nfs4_stid *s; | 3661 | struct inode *inode; |
3857 | __be32 status; | 3662 | __be32 status; |
3858 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 3663 | int flags = 0; |
3859 | 3664 | ||
3860 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | 3665 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
3861 | return status; | 3666 | return status; |
3667 | inode = cstate->current_fh.fh_dentry->d_inode; | ||
3862 | 3668 | ||
3669 | if (nfsd4_has_session(cstate)) | ||
3670 | flags |= HAS_SESSION; | ||
3863 | nfs4_lock_state(); | 3671 | nfs4_lock_state(); |
3864 | status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, | 3672 | status = nfserr_bad_stateid; |
3865 | cstate->minorversion, nn); | 3673 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
3866 | if (status) | 3674 | goto out; |
3675 | status = nfserr_stale_stateid; | ||
3676 | if (STALE_STATEID(stateid)) | ||
3677 | goto out; | ||
3678 | status = nfserr_bad_stateid; | ||
3679 | if (!is_delegation_stateid(stateid)) | ||
3680 | goto out; | ||
3681 | status = nfserr_expired; | ||
3682 | dp = find_delegation_stateid(inode, stateid); | ||
3683 | if (!dp) | ||
3867 | goto out; | 3684 | goto out; |
3868 | dp = delegstateid(s); | 3685 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); |
3869 | status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate)); | ||
3870 | if (status) | 3686 | if (status) |
3871 | goto out; | 3687 | goto out; |
3688 | renew_client(dp->dl_client); | ||
3872 | 3689 | ||
3873 | unhash_delegation(dp); | 3690 | unhash_delegation(dp); |
3874 | out: | 3691 | out: |
@@ -3878,9 +3695,13 @@ out: | |||
3878 | } | 3695 | } |
3879 | 3696 | ||
3880 | 3697 | ||
3698 | /* | ||
3699 | * Lock owner state (byte-range locks) | ||
3700 | */ | ||
3881 | #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) | 3701 | #define LOFF_OVERFLOW(start, len) ((u64)(len) > ~(u64)(start)) |
3882 | 3702 | #define LOCK_HASH_BITS 8 | |
3883 | #define LOCKOWNER_INO_HASH_MASK (LOCKOWNER_INO_HASH_SIZE - 1) | 3703 | #define LOCK_HASH_SIZE (1 << LOCK_HASH_BITS) |
3704 | #define LOCK_HASH_MASK (LOCK_HASH_SIZE - 1) | ||
3884 | 3705 | ||
3885 | static inline u64 | 3706 | static inline u64 |
3886 | end_offset(u64 start, u64 len) | 3707 | end_offset(u64 start, u64 len) |
@@ -3897,16 +3718,117 @@ last_byte_offset(u64 start, u64 len) | |||
3897 | { | 3718 | { |
3898 | u64 end; | 3719 | u64 end; |
3899 | 3720 | ||
3900 | WARN_ON_ONCE(!len); | 3721 | BUG_ON(!len); |
3901 | end = start + len; | 3722 | end = start + len; |
3902 | return end > start ? end - 1: NFS4_MAX_UINT64; | 3723 | return end > start ? end - 1: NFS4_MAX_UINT64; |
3903 | } | 3724 | } |
3904 | 3725 | ||
3905 | static unsigned int lockowner_ino_hashval(struct inode *inode, u32 cl_id, struct xdr_netobj *ownername) | 3726 | #define lockownerid_hashval(id) \ |
3727 | ((id) & LOCK_HASH_MASK) | ||
3728 | |||
3729 | static inline unsigned int | ||
3730 | lock_ownerstr_hashval(struct inode *inode, u32 cl_id, | ||
3731 | struct xdr_netobj *ownername) | ||
3906 | { | 3732 | { |
3907 | return (file_hashval(inode) + cl_id | 3733 | return (file_hashval(inode) + cl_id |
3908 | + opaque_hashval(ownername->data, ownername->len)) | 3734 | + opaque_hashval(ownername->data, ownername->len)) |
3909 | & LOCKOWNER_INO_HASH_MASK; | 3735 | & LOCK_HASH_MASK; |
3736 | } | ||
3737 | |||
3738 | static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE]; | ||
3739 | static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE]; | ||
3740 | static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE]; | ||
3741 | |||
3742 | static int | ||
3743 | same_stateid(stateid_t *id_one, stateid_t *id_two) | ||
3744 | { | ||
3745 | if (id_one->si_stateownerid != id_two->si_stateownerid) | ||
3746 | return 0; | ||
3747 | return id_one->si_fileid == id_two->si_fileid; | ||
3748 | } | ||
3749 | |||
3750 | static struct nfs4_stateid * | ||
3751 | find_stateid(stateid_t *stid, int flags) | ||
3752 | { | ||
3753 | struct nfs4_stateid *local; | ||
3754 | u32 st_id = stid->si_stateownerid; | ||
3755 | u32 f_id = stid->si_fileid; | ||
3756 | unsigned int hashval; | ||
3757 | |||
3758 | dprintk("NFSD: find_stateid flags 0x%x\n",flags); | ||
3759 | if (flags & (LOCK_STATE | RD_STATE | WR_STATE)) { | ||
3760 | hashval = stateid_hashval(st_id, f_id); | ||
3761 | list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { | ||
3762 | if ((local->st_stateid.si_stateownerid == st_id) && | ||
3763 | (local->st_stateid.si_fileid == f_id)) | ||
3764 | return local; | ||
3765 | } | ||
3766 | } | ||
3767 | |||
3768 | if (flags & (OPEN_STATE | RD_STATE | WR_STATE)) { | ||
3769 | hashval = stateid_hashval(st_id, f_id); | ||
3770 | list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { | ||
3771 | if ((local->st_stateid.si_stateownerid == st_id) && | ||
3772 | (local->st_stateid.si_fileid == f_id)) | ||
3773 | return local; | ||
3774 | } | ||
3775 | } | ||
3776 | return NULL; | ||
3777 | } | ||
3778 | |||
3779 | static struct nfs4_stateid * | ||
3780 | search_for_stateid(stateid_t *stid) | ||
3781 | { | ||
3782 | struct nfs4_stateid *local; | ||
3783 | unsigned int hashval = stateid_hashval(stid->si_stateownerid, stid->si_fileid); | ||
3784 | |||
3785 | list_for_each_entry(local, &lockstateid_hashtbl[hashval], st_hash) { | ||
3786 | if (same_stateid(&local->st_stateid, stid)) | ||
3787 | return local; | ||
3788 | } | ||
3789 | |||
3790 | list_for_each_entry(local, &stateid_hashtbl[hashval], st_hash) { | ||
3791 | if (same_stateid(&local->st_stateid, stid)) | ||
3792 | return local; | ||
3793 | } | ||
3794 | return NULL; | ||
3795 | } | ||
3796 | |||
3797 | static struct nfs4_delegation * | ||
3798 | search_for_delegation(stateid_t *stid) | ||
3799 | { | ||
3800 | struct nfs4_file *fp; | ||
3801 | struct nfs4_delegation *dp; | ||
3802 | struct list_head *pos; | ||
3803 | int i; | ||
3804 | |||
3805 | for (i = 0; i < FILE_HASH_SIZE; i++) { | ||
3806 | list_for_each_entry(fp, &file_hashtbl[i], fi_hash) { | ||
3807 | list_for_each(pos, &fp->fi_delegations) { | ||
3808 | dp = list_entry(pos, struct nfs4_delegation, dl_perfile); | ||
3809 | if (same_stateid(&dp->dl_stateid, stid)) | ||
3810 | return dp; | ||
3811 | } | ||
3812 | } | ||
3813 | } | ||
3814 | return NULL; | ||
3815 | } | ||
3816 | |||
3817 | static struct nfs4_delegation * | ||
3818 | find_delegation_stateid(struct inode *ino, stateid_t *stid) | ||
3819 | { | ||
3820 | struct nfs4_file *fp; | ||
3821 | struct nfs4_delegation *dl; | ||
3822 | |||
3823 | dprintk("NFSD: %s: stateid=" STATEID_FMT "\n", __func__, | ||
3824 | STATEID_VAL(stid)); | ||
3825 | |||
3826 | fp = find_file(ino); | ||
3827 | if (!fp) | ||
3828 | return NULL; | ||
3829 | dl = find_delegation_file(fp, stid); | ||
3830 | put_nfs4_file(fp); | ||
3831 | return dl; | ||
3910 | } | 3832 | } |
3911 | 3833 | ||
3912 | /* | 3834 | /* |
@@ -3934,21 +3856,15 @@ static const struct lock_manager_operations nfsd_posix_mng_ops = { | |||
3934 | static inline void | 3856 | static inline void |
3935 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) | 3857 | nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny) |
3936 | { | 3858 | { |
3937 | struct nfs4_lockowner *lo; | 3859 | struct nfs4_stateowner *sop; |
3938 | 3860 | ||
3939 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { | 3861 | if (fl->fl_lmops == &nfsd_posix_mng_ops) { |
3940 | lo = (struct nfs4_lockowner *) fl->fl_owner; | 3862 | sop = (struct nfs4_stateowner *) fl->fl_owner; |
3941 | deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data, | 3863 | kref_get(&sop->so_ref); |
3942 | lo->lo_owner.so_owner.len, GFP_KERNEL); | 3864 | deny->ld_sop = sop; |
3943 | if (!deny->ld_owner.data) | 3865 | deny->ld_clientid = sop->so_client->cl_clientid; |
3944 | /* We just don't care that much */ | ||
3945 | goto nevermind; | ||
3946 | deny->ld_owner.len = lo->lo_owner.so_owner.len; | ||
3947 | deny->ld_clientid = lo->lo_owner.so_client->cl_clientid; | ||
3948 | } else { | 3866 | } else { |
3949 | nevermind: | 3867 | deny->ld_sop = NULL; |
3950 | deny->ld_owner.len = 0; | ||
3951 | deny->ld_owner.data = NULL; | ||
3952 | deny->ld_clientid.cl_boot = 0; | 3868 | deny->ld_clientid.cl_boot = 0; |
3953 | deny->ld_clientid.cl_id = 0; | 3869 | deny->ld_clientid.cl_id = 0; |
3954 | } | 3870 | } |
@@ -3961,85 +3877,89 @@ nevermind: | |||
3961 | deny->ld_type = NFS4_WRITE_LT; | 3877 | deny->ld_type = NFS4_WRITE_LT; |
3962 | } | 3878 | } |
3963 | 3879 | ||
3964 | static bool same_lockowner_ino(struct nfs4_lockowner *lo, struct inode *inode, clientid_t *clid, struct xdr_netobj *owner) | 3880 | static struct nfs4_stateowner * |
3965 | { | 3881 | find_lockstateowner_str(struct inode *inode, clientid_t *clid, |
3966 | struct nfs4_ol_stateid *lst; | 3882 | struct xdr_netobj *owner) |
3967 | |||
3968 | if (!same_owner_str(&lo->lo_owner, owner, clid)) | ||
3969 | return false; | ||
3970 | lst = list_first_entry(&lo->lo_owner.so_stateids, | ||
3971 | struct nfs4_ol_stateid, st_perstateowner); | ||
3972 | return lst->st_file->fi_inode == inode; | ||
3973 | } | ||
3974 | |||
3975 | static struct nfs4_lockowner * | ||
3976 | find_lockowner_str(struct inode *inode, clientid_t *clid, | ||
3977 | struct xdr_netobj *owner, struct nfsd_net *nn) | ||
3978 | { | 3883 | { |
3979 | unsigned int hashval = lockowner_ino_hashval(inode, clid->cl_id, owner); | 3884 | unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner); |
3980 | struct nfs4_lockowner *lo; | 3885 | struct nfs4_stateowner *op; |
3981 | 3886 | ||
3982 | list_for_each_entry(lo, &nn->lockowner_ino_hashtbl[hashval], lo_owner_ino_hash) { | 3887 | list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) { |
3983 | if (same_lockowner_ino(lo, inode, clid, owner)) | 3888 | if (same_owner_str(op, owner, clid)) |
3984 | return lo; | 3889 | return op; |
3985 | } | 3890 | } |
3986 | return NULL; | 3891 | return NULL; |
3987 | } | 3892 | } |
3988 | 3893 | ||
3989 | static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp) | ||
3990 | { | ||
3991 | struct inode *inode = open_stp->st_file->fi_inode; | ||
3992 | unsigned int inohash = lockowner_ino_hashval(inode, | ||
3993 | clp->cl_clientid.cl_id, &lo->lo_owner.so_owner); | ||
3994 | struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); | ||
3995 | |||
3996 | list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); | ||
3997 | list_add(&lo->lo_owner_ino_hash, &nn->lockowner_ino_hashtbl[inohash]); | ||
3998 | list_add(&lo->lo_perstateid, &open_stp->st_lockowners); | ||
3999 | } | ||
4000 | |||
4001 | /* | 3894 | /* |
4002 | * Alloc a lock owner structure. | 3895 | * Alloc a lock owner structure. |
4003 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has | 3896 | * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has |
4004 | * occurred. | 3897 | * occurred. |
4005 | * | 3898 | * |
4006 | * strhashval = ownerstr_hashval | 3899 | * strhashval = lock_ownerstr_hashval |
4007 | */ | 3900 | */ |
4008 | 3901 | ||
4009 | static struct nfs4_lockowner * | 3902 | static struct nfs4_stateowner * |
4010 | alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) { | 3903 | alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) { |
4011 | struct nfs4_lockowner *lo; | 3904 | struct nfs4_stateowner *sop; |
3905 | struct nfs4_replay *rp; | ||
3906 | unsigned int idhashval; | ||
4012 | 3907 | ||
4013 | lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp); | 3908 | if (!(sop = alloc_stateowner(&lock->lk_new_owner))) |
4014 | if (!lo) | ||
4015 | return NULL; | 3909 | return NULL; |
4016 | INIT_LIST_HEAD(&lo->lo_owner.so_stateids); | 3910 | idhashval = lockownerid_hashval(current_ownerid); |
4017 | lo->lo_owner.so_is_open_owner = 0; | 3911 | INIT_LIST_HEAD(&sop->so_idhash); |
3912 | INIT_LIST_HEAD(&sop->so_strhash); | ||
3913 | INIT_LIST_HEAD(&sop->so_perclient); | ||
3914 | INIT_LIST_HEAD(&sop->so_stateids); | ||
3915 | INIT_LIST_HEAD(&sop->so_perstateid); | ||
3916 | INIT_LIST_HEAD(&sop->so_close_lru); /* not used */ | ||
3917 | sop->so_time = 0; | ||
3918 | list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]); | ||
3919 | list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]); | ||
3920 | list_add(&sop->so_perstateid, &open_stp->st_lockowners); | ||
3921 | sop->so_is_open_owner = 0; | ||
3922 | sop->so_id = current_ownerid++; | ||
3923 | sop->so_client = clp; | ||
4018 | /* It is the openowner seqid that will be incremented in encode in the | 3924 | /* It is the openowner seqid that will be incremented in encode in the |
4019 | * case of new lockowners; so increment the lock seqid manually: */ | 3925 | * case of new lockowners; so increment the lock seqid manually: */ |
4020 | lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1; | 3926 | sop->so_seqid = lock->lk_new_lock_seqid + 1; |
4021 | hash_lockowner(lo, strhashval, clp, open_stp); | 3927 | sop->so_confirmed = 1; |
4022 | return lo; | 3928 | rp = &sop->so_replay; |
3929 | rp->rp_status = nfserr_serverfault; | ||
3930 | rp->rp_buflen = 0; | ||
3931 | rp->rp_buf = rp->rp_ibuf; | ||
3932 | return sop; | ||
4023 | } | 3933 | } |
4024 | 3934 | ||
4025 | static struct nfs4_ol_stateid * | 3935 | static struct nfs4_stateid * |
4026 | alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp) | 3936 | alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp) |
4027 | { | 3937 | { |
4028 | struct nfs4_ol_stateid *stp; | 3938 | struct nfs4_stateid *stp; |
4029 | struct nfs4_client *clp = lo->lo_owner.so_client; | 3939 | unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id); |
4030 | 3940 | ||
4031 | stp = nfs4_alloc_stateid(clp); | 3941 | stp = nfs4_alloc_stateid(); |
4032 | if (stp == NULL) | 3942 | if (stp == NULL) |
4033 | return NULL; | 3943 | goto out; |
4034 | init_stid(&stp->st_stid, clp, NFS4_LOCK_STID); | 3944 | INIT_LIST_HEAD(&stp->st_hash); |
3945 | INIT_LIST_HEAD(&stp->st_perfile); | ||
3946 | INIT_LIST_HEAD(&stp->st_perstateowner); | ||
3947 | INIT_LIST_HEAD(&stp->st_lockowners); /* not used */ | ||
3948 | list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]); | ||
4035 | list_add(&stp->st_perfile, &fp->fi_stateids); | 3949 | list_add(&stp->st_perfile, &fp->fi_stateids); |
4036 | list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); | 3950 | list_add(&stp->st_perstateowner, &sop->so_stateids); |
4037 | stp->st_stateowner = &lo->lo_owner; | 3951 | stp->st_stateowner = sop; |
4038 | get_nfs4_file(fp); | 3952 | get_nfs4_file(fp); |
4039 | stp->st_file = fp; | 3953 | stp->st_file = fp; |
3954 | stp->st_stateid.si_boot = boot_time; | ||
3955 | stp->st_stateid.si_stateownerid = sop->so_id; | ||
3956 | stp->st_stateid.si_fileid = fp->fi_id; | ||
3957 | stp->st_stateid.si_generation = 0; | ||
4040 | stp->st_access_bmap = 0; | 3958 | stp->st_access_bmap = 0; |
4041 | stp->st_deny_bmap = open_stp->st_deny_bmap; | 3959 | stp->st_deny_bmap = open_stp->st_deny_bmap; |
4042 | stp->st_openstp = open_stp; | 3960 | stp->st_openstp = open_stp; |
3961 | |||
3962 | out: | ||
4043 | return stp; | 3963 | return stp; |
4044 | } | 3964 | } |
4045 | 3965 | ||
@@ -4050,48 +3970,15 @@ check_lock_length(u64 offset, u64 length) | |||
4050 | LOFF_OVERFLOW(offset, length))); | 3970 | LOFF_OVERFLOW(offset, length))); |
4051 | } | 3971 | } |
4052 | 3972 | ||
4053 | static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access) | 3973 | static void get_lock_access(struct nfs4_stateid *lock_stp, u32 access) |
4054 | { | 3974 | { |
4055 | struct nfs4_file *fp = lock_stp->st_file; | 3975 | struct nfs4_file *fp = lock_stp->st_file; |
4056 | int oflag = nfs4_access_to_omode(access); | 3976 | int oflag = nfs4_access_to_omode(access); |
4057 | 3977 | ||
4058 | if (test_access(access, lock_stp)) | 3978 | if (test_bit(access, &lock_stp->st_access_bmap)) |
4059 | return; | 3979 | return; |
4060 | nfs4_file_get_access(fp, oflag); | 3980 | nfs4_file_get_access(fp, oflag); |
4061 | set_access(access, lock_stp); | 3981 | __set_bit(access, &lock_stp->st_access_bmap); |
4062 | } | ||
4063 | |||
4064 | static __be32 lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *ost, struct nfsd4_lock *lock, struct nfs4_ol_stateid **lst, bool *new) | ||
4065 | { | ||
4066 | struct nfs4_file *fi = ost->st_file; | ||
4067 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); | ||
4068 | struct nfs4_client *cl = oo->oo_owner.so_client; | ||
4069 | struct nfs4_lockowner *lo; | ||
4070 | unsigned int strhashval; | ||
4071 | struct nfsd_net *nn = net_generic(cl->net, nfsd_net_id); | ||
4072 | |||
4073 | lo = find_lockowner_str(fi->fi_inode, &cl->cl_clientid, | ||
4074 | &lock->v.new.owner, nn); | ||
4075 | if (lo) { | ||
4076 | if (!cstate->minorversion) | ||
4077 | return nfserr_bad_seqid; | ||
4078 | /* XXX: a lockowner always has exactly one stateid: */ | ||
4079 | *lst = list_first_entry(&lo->lo_owner.so_stateids, | ||
4080 | struct nfs4_ol_stateid, st_perstateowner); | ||
4081 | return nfs_ok; | ||
4082 | } | ||
4083 | strhashval = ownerstr_hashval(cl->cl_clientid.cl_id, | ||
4084 | &lock->v.new.owner); | ||
4085 | lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); | ||
4086 | if (lo == NULL) | ||
4087 | return nfserr_jukebox; | ||
4088 | *lst = alloc_init_lock_stateid(lo, fi, ost); | ||
4089 | if (*lst == NULL) { | ||
4090 | release_lockowner(lo); | ||
4091 | return nfserr_jukebox; | ||
4092 | } | ||
4093 | *new = true; | ||
4094 | return nfs_ok; | ||
4095 | } | 3982 | } |
4096 | 3983 | ||
4097 | /* | 3984 | /* |
@@ -4101,18 +3988,16 @@ __be32 | |||
4101 | nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3988 | nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
4102 | struct nfsd4_lock *lock) | 3989 | struct nfsd4_lock *lock) |
4103 | { | 3990 | { |
4104 | struct nfs4_openowner *open_sop = NULL; | 3991 | struct nfs4_stateowner *open_sop = NULL; |
4105 | struct nfs4_lockowner *lock_sop = NULL; | 3992 | struct nfs4_stateowner *lock_sop = NULL; |
4106 | struct nfs4_ol_stateid *lock_stp; | 3993 | struct nfs4_stateid *lock_stp; |
3994 | struct nfs4_file *fp; | ||
4107 | struct file *filp = NULL; | 3995 | struct file *filp = NULL; |
4108 | struct file_lock *file_lock = NULL; | 3996 | struct file_lock file_lock; |
4109 | struct file_lock *conflock = NULL; | 3997 | struct file_lock conflock; |
4110 | __be32 status = 0; | 3998 | __be32 status = 0; |
4111 | bool new_state = false; | 3999 | unsigned int strhashval; |
4112 | int lkflg; | ||
4113 | int err; | 4000 | int err; |
4114 | struct net *net = SVC_NET(rqstp); | ||
4115 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4116 | 4001 | ||
4117 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", | 4002 | dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n", |
4118 | (long long) lock->lk_offset, | 4003 | (long long) lock->lk_offset, |
@@ -4130,75 +4015,80 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4130 | nfs4_lock_state(); | 4015 | nfs4_lock_state(); |
4131 | 4016 | ||
4132 | if (lock->lk_is_new) { | 4017 | if (lock->lk_is_new) { |
4133 | struct nfs4_ol_stateid *open_stp = NULL; | 4018 | /* |
4134 | 4019 | * Client indicates that this is a new lockowner. | |
4135 | if (nfsd4_has_session(cstate)) | 4020 | * Use open owner and open stateid to create lock owner and |
4136 | /* See rfc 5661 18.10.3: given clientid is ignored: */ | 4021 | * lock stateid. |
4137 | memcpy(&lock->v.new.clientid, | 4022 | */ |
4138 | &cstate->session->se_client->cl_clientid, | 4023 | struct nfs4_stateid *open_stp = NULL; |
4139 | sizeof(clientid_t)); | 4024 | |
4140 | |||
4141 | status = nfserr_stale_clientid; | 4025 | status = nfserr_stale_clientid; |
4142 | if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) | 4026 | if (!nfsd4_has_session(cstate) && |
4027 | STALE_CLIENTID(&lock->lk_new_clientid)) | ||
4143 | goto out; | 4028 | goto out; |
4144 | 4029 | ||
4145 | /* validate and update open stateid and open seqid */ | 4030 | /* validate and update open stateid and open seqid */ |
4146 | status = nfs4_preprocess_confirmed_seqid_op(cstate, | 4031 | status = nfs4_preprocess_seqid_op(cstate, |
4147 | lock->lk_new_open_seqid, | 4032 | lock->lk_new_open_seqid, |
4148 | &lock->lk_new_open_stateid, | 4033 | &lock->lk_new_open_stateid, |
4149 | &open_stp, nn); | 4034 | OPEN_STATE, |
4035 | &lock->lk_replay_owner, &open_stp, | ||
4036 | lock); | ||
4150 | if (status) | 4037 | if (status) |
4151 | goto out; | 4038 | goto out; |
4152 | open_sop = openowner(open_stp->st_stateowner); | 4039 | open_sop = lock->lk_replay_owner; |
4153 | status = nfserr_bad_stateid; | 4040 | /* create lockowner and lock stateid */ |
4154 | if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, | 4041 | fp = open_stp->st_file; |
4155 | &lock->v.new.clientid)) | 4042 | strhashval = lock_ownerstr_hashval(fp->fi_inode, |
4043 | open_sop->so_client->cl_clientid.cl_id, | ||
4044 | &lock->v.new.owner); | ||
4045 | /* XXX: Do we need to check for duplicate stateowners on | ||
4046 | * the same file, or should they just be allowed (and | ||
4047 | * create new stateids)? */ | ||
4048 | status = nfserr_jukebox; | ||
4049 | lock_sop = alloc_init_lock_stateowner(strhashval, | ||
4050 | open_sop->so_client, open_stp, lock); | ||
4051 | if (lock_sop == NULL) | ||
4156 | goto out; | 4052 | goto out; |
4157 | status = lookup_or_create_lock_state(cstate, open_stp, lock, | 4053 | lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp); |
4158 | &lock_stp, &new_state); | 4054 | if (lock_stp == NULL) |
4159 | } else | 4055 | goto out; |
4056 | } else { | ||
4057 | /* lock (lock owner + lock stateid) already exists */ | ||
4160 | status = nfs4_preprocess_seqid_op(cstate, | 4058 | status = nfs4_preprocess_seqid_op(cstate, |
4161 | lock->lk_old_lock_seqid, | 4059 | lock->lk_old_lock_seqid, |
4162 | &lock->lk_old_lock_stateid, | 4060 | &lock->lk_old_lock_stateid, |
4163 | NFS4_LOCK_STID, &lock_stp, nn); | 4061 | LOCK_STATE, |
4164 | if (status) | 4062 | &lock->lk_replay_owner, &lock_stp, lock); |
4165 | goto out; | 4063 | if (status) |
4166 | lock_sop = lockowner(lock_stp->st_stateowner); | 4064 | goto out; |
4167 | 4065 | lock_sop = lock->lk_replay_owner; | |
4168 | lkflg = setlkflg(lock->lk_type); | 4066 | fp = lock_stp->st_file; |
4169 | status = nfs4_check_openmode(lock_stp, lkflg); | 4067 | } |
4170 | if (status) | 4068 | /* lock->lk_replay_owner and lock_stp have been created or found */ |
4171 | goto out; | ||
4172 | 4069 | ||
4173 | status = nfserr_grace; | 4070 | status = nfserr_grace; |
4174 | if (locks_in_grace(net) && !lock->lk_reclaim) | 4071 | if (locks_in_grace() && !lock->lk_reclaim) |
4175 | goto out; | 4072 | goto out; |
4176 | status = nfserr_no_grace; | 4073 | status = nfserr_no_grace; |
4177 | if (!locks_in_grace(net) && lock->lk_reclaim) | 4074 | if (!locks_in_grace() && lock->lk_reclaim) |
4178 | goto out; | ||
4179 | |||
4180 | file_lock = locks_alloc_lock(); | ||
4181 | if (!file_lock) { | ||
4182 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); | ||
4183 | status = nfserr_jukebox; | ||
4184 | goto out; | 4075 | goto out; |
4185 | } | ||
4186 | 4076 | ||
4187 | locks_init_lock(file_lock); | 4077 | locks_init_lock(&file_lock); |
4188 | switch (lock->lk_type) { | 4078 | switch (lock->lk_type) { |
4189 | case NFS4_READ_LT: | 4079 | case NFS4_READ_LT: |
4190 | case NFS4_READW_LT: | 4080 | case NFS4_READW_LT: |
4191 | filp = find_readable_file(lock_stp->st_file); | 4081 | filp = find_readable_file(lock_stp->st_file); |
4192 | if (filp) | 4082 | if (filp) |
4193 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); | 4083 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); |
4194 | file_lock->fl_type = F_RDLCK; | 4084 | file_lock.fl_type = F_RDLCK; |
4195 | break; | 4085 | break; |
4196 | case NFS4_WRITE_LT: | 4086 | case NFS4_WRITE_LT: |
4197 | case NFS4_WRITEW_LT: | 4087 | case NFS4_WRITEW_LT: |
4198 | filp = find_writeable_file(lock_stp->st_file); | 4088 | filp = find_writeable_file(lock_stp->st_file); |
4199 | if (filp) | 4089 | if (filp) |
4200 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); | 4090 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); |
4201 | file_lock->fl_type = F_WRLCK; | 4091 | file_lock.fl_type = F_WRLCK; |
4202 | break; | 4092 | break; |
4203 | default: | 4093 | default: |
4204 | status = nfserr_inval; | 4094 | status = nfserr_inval; |
@@ -4208,34 +4098,33 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4208 | status = nfserr_openmode; | 4098 | status = nfserr_openmode; |
4209 | goto out; | 4099 | goto out; |
4210 | } | 4100 | } |
4211 | file_lock->fl_owner = (fl_owner_t)lock_sop; | 4101 | file_lock.fl_owner = (fl_owner_t)lock_sop; |
4212 | file_lock->fl_pid = current->tgid; | 4102 | file_lock.fl_pid = current->tgid; |
4213 | file_lock->fl_file = filp; | 4103 | file_lock.fl_file = filp; |
4214 | file_lock->fl_flags = FL_POSIX; | 4104 | file_lock.fl_flags = FL_POSIX; |
4215 | file_lock->fl_lmops = &nfsd_posix_mng_ops; | 4105 | file_lock.fl_lmops = &nfsd_posix_mng_ops; |
4216 | file_lock->fl_start = lock->lk_offset; | ||
4217 | file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); | ||
4218 | nfs4_transform_lock_offset(file_lock); | ||
4219 | |||
4220 | conflock = locks_alloc_lock(); | ||
4221 | if (!conflock) { | ||
4222 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); | ||
4223 | status = nfserr_jukebox; | ||
4224 | goto out; | ||
4225 | } | ||
4226 | 4106 | ||
4227 | err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); | 4107 | file_lock.fl_start = lock->lk_offset; |
4108 | file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); | ||
4109 | nfs4_transform_lock_offset(&file_lock); | ||
4110 | |||
4111 | /* | ||
4112 | * Try to lock the file in the VFS. | ||
4113 | * Note: locks.c uses the BKL to protect the inode's lock list. | ||
4114 | */ | ||
4115 | |||
4116 | err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); | ||
4228 | switch (-err) { | 4117 | switch (-err) { |
4229 | case 0: /* success! */ | 4118 | case 0: /* success! */ |
4230 | update_stateid(&lock_stp->st_stid.sc_stateid); | 4119 | update_stateid(&lock_stp->st_stateid); |
4231 | memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid, | 4120 | memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid, |
4232 | sizeof(stateid_t)); | 4121 | sizeof(stateid_t)); |
4233 | status = 0; | 4122 | status = 0; |
4234 | break; | 4123 | break; |
4235 | case (EAGAIN): /* conflock holds conflicting lock */ | 4124 | case (EAGAIN): /* conflock holds conflicting lock */ |
4236 | status = nfserr_denied; | 4125 | status = nfserr_denied; |
4237 | dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); | 4126 | dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); |
4238 | nfs4_set_lock_denied(conflock, &lock->lk_denied); | 4127 | nfs4_set_lock_denied(&conflock, &lock->lk_denied); |
4239 | break; | 4128 | break; |
4240 | case (EDEADLK): | 4129 | case (EDEADLK): |
4241 | status = nfserr_deadlock; | 4130 | status = nfserr_deadlock; |
@@ -4246,14 +4135,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4246 | break; | 4135 | break; |
4247 | } | 4136 | } |
4248 | out: | 4137 | out: |
4249 | if (status && new_state) | 4138 | if (status && lock->lk_is_new && lock_sop) |
4250 | release_lockowner(lock_sop); | 4139 | release_lockowner(lock_sop); |
4251 | if (!cstate->replay_owner) | 4140 | if (lock->lk_replay_owner) { |
4252 | nfs4_unlock_state(); | 4141 | nfs4_get_stateowner(lock->lk_replay_owner); |
4253 | if (file_lock) | 4142 | cstate->replay_owner = lock->lk_replay_owner; |
4254 | locks_free_lock(file_lock); | 4143 | } |
4255 | if (conflock) | 4144 | nfs4_unlock_state(); |
4256 | locks_free_lock(conflock); | ||
4257 | return status; | 4145 | return status; |
4258 | } | 4146 | } |
4259 | 4147 | ||
@@ -4263,14 +4151,16 @@ out: | |||
4263 | * vfs_test_lock. (Arguably perhaps test_lock should be done with an | 4151 | * vfs_test_lock. (Arguably perhaps test_lock should be done with an |
4264 | * inode operation.) | 4152 | * inode operation.) |
4265 | */ | 4153 | */ |
4266 | static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) | 4154 | static int nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) |
4267 | { | 4155 | { |
4268 | struct file *file; | 4156 | struct file *file; |
4269 | __be32 err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); | 4157 | int err; |
4270 | if (!err) { | 4158 | |
4271 | err = nfserrno(vfs_test_lock(file, lock)); | 4159 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file); |
4272 | nfsd_close(file); | 4160 | if (err) |
4273 | } | 4161 | return err; |
4162 | err = vfs_test_lock(file, lock); | ||
4163 | nfsd_close(file); | ||
4274 | return err; | 4164 | return err; |
4275 | } | 4165 | } |
4276 | 4166 | ||
@@ -4282,44 +4172,40 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4282 | struct nfsd4_lockt *lockt) | 4172 | struct nfsd4_lockt *lockt) |
4283 | { | 4173 | { |
4284 | struct inode *inode; | 4174 | struct inode *inode; |
4285 | struct file_lock *file_lock = NULL; | 4175 | struct file_lock file_lock; |
4286 | struct nfs4_lockowner *lo; | 4176 | int error; |
4287 | __be32 status; | 4177 | __be32 status; |
4288 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
4289 | 4178 | ||
4290 | if (locks_in_grace(SVC_NET(rqstp))) | 4179 | if (locks_in_grace()) |
4291 | return nfserr_grace; | 4180 | return nfserr_grace; |
4292 | 4181 | ||
4293 | if (check_lock_length(lockt->lt_offset, lockt->lt_length)) | 4182 | if (check_lock_length(lockt->lt_offset, lockt->lt_length)) |
4294 | return nfserr_inval; | 4183 | return nfserr_inval; |
4295 | 4184 | ||
4185 | lockt->lt_stateowner = NULL; | ||
4296 | nfs4_lock_state(); | 4186 | nfs4_lock_state(); |
4297 | 4187 | ||
4298 | if (!nfsd4_has_session(cstate)) { | 4188 | status = nfserr_stale_clientid; |
4299 | status = lookup_clientid(&lockt->lt_clientid, false, nn, NULL); | 4189 | if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid)) |
4300 | if (status) | ||
4301 | goto out; | ||
4302 | } | ||
4303 | |||
4304 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | ||
4305 | goto out; | 4190 | goto out; |
4306 | 4191 | ||
4307 | inode = cstate->current_fh.fh_dentry->d_inode; | 4192 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) { |
4308 | file_lock = locks_alloc_lock(); | 4193 | dprintk("NFSD: nfsd4_lockt: fh_verify() failed!\n"); |
4309 | if (!file_lock) { | 4194 | if (status == nfserr_symlink) |
4310 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); | 4195 | status = nfserr_inval; |
4311 | status = nfserr_jukebox; | ||
4312 | goto out; | 4196 | goto out; |
4313 | } | 4197 | } |
4314 | locks_init_lock(file_lock); | 4198 | |
4199 | inode = cstate->current_fh.fh_dentry->d_inode; | ||
4200 | locks_init_lock(&file_lock); | ||
4315 | switch (lockt->lt_type) { | 4201 | switch (lockt->lt_type) { |
4316 | case NFS4_READ_LT: | 4202 | case NFS4_READ_LT: |
4317 | case NFS4_READW_LT: | 4203 | case NFS4_READW_LT: |
4318 | file_lock->fl_type = F_RDLCK; | 4204 | file_lock.fl_type = F_RDLCK; |
4319 | break; | 4205 | break; |
4320 | case NFS4_WRITE_LT: | 4206 | case NFS4_WRITE_LT: |
4321 | case NFS4_WRITEW_LT: | 4207 | case NFS4_WRITEW_LT: |
4322 | file_lock->fl_type = F_WRLCK; | 4208 | file_lock.fl_type = F_WRLCK; |
4323 | break; | 4209 | break; |
4324 | default: | 4210 | default: |
4325 | dprintk("NFSD: nfs4_lockt: bad lock type!\n"); | 4211 | dprintk("NFSD: nfs4_lockt: bad lock type!\n"); |
@@ -4327,29 +4213,30 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4327 | goto out; | 4213 | goto out; |
4328 | } | 4214 | } |
4329 | 4215 | ||
4330 | lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner, nn); | 4216 | lockt->lt_stateowner = find_lockstateowner_str(inode, |
4331 | if (lo) | 4217 | &lockt->lt_clientid, &lockt->lt_owner); |
4332 | file_lock->fl_owner = (fl_owner_t)lo; | 4218 | if (lockt->lt_stateowner) |
4333 | file_lock->fl_pid = current->tgid; | 4219 | file_lock.fl_owner = (fl_owner_t)lockt->lt_stateowner; |
4334 | file_lock->fl_flags = FL_POSIX; | 4220 | file_lock.fl_pid = current->tgid; |
4221 | file_lock.fl_flags = FL_POSIX; | ||
4335 | 4222 | ||
4336 | file_lock->fl_start = lockt->lt_offset; | 4223 | file_lock.fl_start = lockt->lt_offset; |
4337 | file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); | 4224 | file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); |
4338 | 4225 | ||
4339 | nfs4_transform_lock_offset(file_lock); | 4226 | nfs4_transform_lock_offset(&file_lock); |
4340 | 4227 | ||
4341 | status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); | 4228 | status = nfs_ok; |
4342 | if (status) | 4229 | error = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock); |
4230 | if (error) { | ||
4231 | status = nfserrno(error); | ||
4343 | goto out; | 4232 | goto out; |
4344 | 4233 | } | |
4345 | if (file_lock->fl_type != F_UNLCK) { | 4234 | if (file_lock.fl_type != F_UNLCK) { |
4346 | status = nfserr_denied; | 4235 | status = nfserr_denied; |
4347 | nfs4_set_lock_denied(file_lock, &lockt->lt_denied); | 4236 | nfs4_set_lock_denied(&file_lock, &lockt->lt_denied); |
4348 | } | 4237 | } |
4349 | out: | 4238 | out: |
4350 | nfs4_unlock_state(); | 4239 | nfs4_unlock_state(); |
4351 | if (file_lock) | ||
4352 | locks_free_lock(file_lock); | ||
4353 | return status; | 4240 | return status; |
4354 | } | 4241 | } |
4355 | 4242 | ||
@@ -4357,13 +4244,12 @@ __be32 | |||
4357 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 4244 | nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
4358 | struct nfsd4_locku *locku) | 4245 | struct nfsd4_locku *locku) |
4359 | { | 4246 | { |
4360 | struct nfs4_ol_stateid *stp; | 4247 | struct nfs4_stateid *stp; |
4361 | struct file *filp = NULL; | 4248 | struct file *filp = NULL; |
4362 | struct file_lock *file_lock = NULL; | 4249 | struct file_lock file_lock; |
4363 | __be32 status; | 4250 | __be32 status; |
4364 | int err; | 4251 | int err; |
4365 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 4252 | |
4366 | |||
4367 | dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", | 4253 | dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n", |
4368 | (long long) locku->lu_offset, | 4254 | (long long) locku->lu_offset, |
4369 | (long long) locku->lu_length); | 4255 | (long long) locku->lu_length); |
@@ -4373,39 +4259,35 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4373 | 4259 | ||
4374 | nfs4_lock_state(); | 4260 | nfs4_lock_state(); |
4375 | 4261 | ||
4376 | status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid, | 4262 | if ((status = nfs4_preprocess_seqid_op(cstate, |
4377 | &locku->lu_stateid, NFS4_LOCK_STID, | 4263 | locku->lu_seqid, |
4378 | &stp, nn); | 4264 | &locku->lu_stateid, |
4379 | if (status) | 4265 | LOCK_STATE, |
4266 | &locku->lu_stateowner, &stp, NULL))) | ||
4380 | goto out; | 4267 | goto out; |
4268 | |||
4381 | filp = find_any_file(stp->st_file); | 4269 | filp = find_any_file(stp->st_file); |
4382 | if (!filp) { | 4270 | if (!filp) { |
4383 | status = nfserr_lock_range; | 4271 | status = nfserr_lock_range; |
4384 | goto out; | 4272 | goto out; |
4385 | } | 4273 | } |
4386 | file_lock = locks_alloc_lock(); | 4274 | BUG_ON(!filp); |
4387 | if (!file_lock) { | 4275 | locks_init_lock(&file_lock); |
4388 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); | 4276 | file_lock.fl_type = F_UNLCK; |
4389 | status = nfserr_jukebox; | 4277 | file_lock.fl_owner = (fl_owner_t) locku->lu_stateowner; |
4390 | goto out; | 4278 | file_lock.fl_pid = current->tgid; |
4391 | } | 4279 | file_lock.fl_file = filp; |
4392 | locks_init_lock(file_lock); | 4280 | file_lock.fl_flags = FL_POSIX; |
4393 | file_lock->fl_type = F_UNLCK; | 4281 | file_lock.fl_lmops = &nfsd_posix_mng_ops; |
4394 | file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); | 4282 | file_lock.fl_start = locku->lu_offset; |
4395 | file_lock->fl_pid = current->tgid; | 4283 | |
4396 | file_lock->fl_file = filp; | 4284 | file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length); |
4397 | file_lock->fl_flags = FL_POSIX; | 4285 | nfs4_transform_lock_offset(&file_lock); |
4398 | file_lock->fl_lmops = &nfsd_posix_mng_ops; | ||
4399 | file_lock->fl_start = locku->lu_offset; | ||
4400 | |||
4401 | file_lock->fl_end = last_byte_offset(locku->lu_offset, | ||
4402 | locku->lu_length); | ||
4403 | nfs4_transform_lock_offset(file_lock); | ||
4404 | 4286 | ||
4405 | /* | 4287 | /* |
4406 | * Try to unlock the file in the VFS. | 4288 | * Try to unlock the file in the VFS. |
4407 | */ | 4289 | */ |
4408 | err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); | 4290 | err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL); |
4409 | if (err) { | 4291 | if (err) { |
4410 | dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); | 4292 | dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); |
4411 | goto out_nfserr; | 4293 | goto out_nfserr; |
@@ -4413,14 +4295,15 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4413 | /* | 4295 | /* |
4414 | * OK, unlock succeeded; the only thing left to do is update the stateid. | 4296 | * OK, unlock succeeded; the only thing left to do is update the stateid. |
4415 | */ | 4297 | */ |
4416 | update_stateid(&stp->st_stid.sc_stateid); | 4298 | update_stateid(&stp->st_stateid); |
4417 | memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t)); | 4299 | memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t)); |
4418 | 4300 | ||
4419 | out: | 4301 | out: |
4420 | if (!cstate->replay_owner) | 4302 | if (locku->lu_stateowner) { |
4421 | nfs4_unlock_state(); | 4303 | nfs4_get_stateowner(locku->lu_stateowner); |
4422 | if (file_lock) | 4304 | cstate->replay_owner = locku->lu_stateowner; |
4423 | locks_free_lock(file_lock); | 4305 | } |
4306 | nfs4_unlock_state(); | ||
4424 | return status; | 4307 | return status; |
4425 | 4308 | ||
4426 | out_nfserr: | 4309 | out_nfserr: |
@@ -4434,7 +4317,7 @@ out_nfserr: | |||
4434 | * 0: no locks held by lockowner | 4317 | * 0: no locks held by lockowner |
4435 | */ | 4318 | */ |
4436 | static int | 4319 | static int |
4437 | check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner) | 4320 | check_for_locks(struct nfs4_file *filp, struct nfs4_stateowner *lowner) |
4438 | { | 4321 | { |
4439 | struct file_lock **flpp; | 4322 | struct file_lock **flpp; |
4440 | struct inode *inode = filp->fi_inode; | 4323 | struct inode *inode = filp->fi_inode; |
@@ -4459,37 +4342,41 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
4459 | { | 4342 | { |
4460 | clientid_t *clid = &rlockowner->rl_clientid; | 4343 | clientid_t *clid = &rlockowner->rl_clientid; |
4461 | struct nfs4_stateowner *sop; | 4344 | struct nfs4_stateowner *sop; |
4462 | struct nfs4_lockowner *lo; | 4345 | struct nfs4_stateid *stp; |
4463 | struct nfs4_ol_stateid *stp; | ||
4464 | struct xdr_netobj *owner = &rlockowner->rl_owner; | 4346 | struct xdr_netobj *owner = &rlockowner->rl_owner; |
4465 | struct list_head matches; | 4347 | struct list_head matches; |
4466 | unsigned int hashval = ownerstr_hashval(clid->cl_id, owner); | 4348 | int i; |
4467 | __be32 status; | 4349 | __be32 status; |
4468 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | ||
4469 | 4350 | ||
4470 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", | 4351 | dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", |
4471 | clid->cl_boot, clid->cl_id); | 4352 | clid->cl_boot, clid->cl_id); |
4472 | 4353 | ||
4473 | nfs4_lock_state(); | 4354 | /* XXX check for lease expiration */ |
4474 | 4355 | ||
4475 | status = lookup_clientid(clid, cstate->minorversion, nn, NULL); | 4356 | status = nfserr_stale_clientid; |
4476 | if (status) | 4357 | if (STALE_CLIENTID(clid)) |
4477 | goto out; | 4358 | return status; |
4359 | |||
4360 | nfs4_lock_state(); | ||
4478 | 4361 | ||
4479 | status = nfserr_locks_held; | 4362 | status = nfserr_locks_held; |
4363 | /* XXX: we're doing a linear search through all the lockowners. | ||
4364 | * Yipes! For now we'll just hope clients aren't really using | ||
4365 | * release_lockowner much, but eventually we have to fix these | ||
4366 | * data structures. */ | ||
4480 | INIT_LIST_HEAD(&matches); | 4367 | INIT_LIST_HEAD(&matches); |
4481 | 4368 | for (i = 0; i < LOCK_HASH_SIZE; i++) { | |
4482 | list_for_each_entry(sop, &nn->ownerstr_hashtbl[hashval], so_strhash) { | 4369 | list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) { |
4483 | if (sop->so_is_open_owner) | 4370 | if (!same_owner_str(sop, owner, clid)) |
4484 | continue; | 4371 | continue; |
4485 | if (!same_owner_str(sop, owner, clid)) | 4372 | list_for_each_entry(stp, &sop->so_stateids, |
4486 | continue; | 4373 | st_perstateowner) { |
4487 | list_for_each_entry(stp, &sop->so_stateids, | 4374 | if (check_for_locks(stp->st_file, sop)) |
4488 | st_perstateowner) { | 4375 | goto out; |
4489 | lo = lockowner(sop); | 4376 | /* Note: so_perclient unused for lockowners, |
4490 | if (check_for_locks(stp->st_file, lo)) | 4377 | * so it's OK to fool with here. */ |
4491 | goto out; | 4378 | list_add(&sop->so_perclient, &matches); |
4492 | list_add(&lo->lo_list, &matches); | 4379 | } |
4493 | } | 4380 | } |
4494 | } | 4381 | } |
4495 | /* Clients probably won't expect us to return with some (but not all) | 4382 | /* Clients probably won't expect us to return with some (but not all) |
@@ -4497,12 +4384,12 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
4497 | * have been checked. */ | 4384 | * have been checked. */ |
4498 | status = nfs_ok; | 4385 | status = nfs_ok; |
4499 | while (!list_empty(&matches)) { | 4386 | while (!list_empty(&matches)) { |
4500 | lo = list_entry(matches.next, struct nfs4_lockowner, | 4387 | sop = list_entry(matches.next, struct nfs4_stateowner, |
4501 | lo_list); | 4388 | so_perclient); |
4502 | /* unhash_stateowner deletes so_perclient only | 4389 | /* unhash_stateowner deletes so_perclient only |
4503 | * for openowners. */ | 4390 | * for openowners. */ |
4504 | list_del(&lo->lo_list); | 4391 | list_del(&sop->so_perclient); |
4505 | release_lockowner(lo); | 4392 | release_lockowner(sop); |
4506 | } | 4393 | } |
4507 | out: | 4394 | out: |
4508 | nfs4_unlock_state(); | 4395 | nfs4_unlock_state(); |
@@ -4515,74 +4402,78 @@ alloc_reclaim(void) | |||
4515 | return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); | 4402 | return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL); |
4516 | } | 4403 | } |
4517 | 4404 | ||
4518 | bool | 4405 | int |
4519 | nfs4_has_reclaimed_state(const char *name, struct nfsd_net *nn) | 4406 | nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) |
4520 | { | 4407 | { |
4521 | struct nfs4_client_reclaim *crp; | 4408 | unsigned int strhashval = clientstr_hashval(name); |
4409 | struct nfs4_client *clp; | ||
4522 | 4410 | ||
4523 | crp = nfsd4_find_reclaim_client(name, nn); | 4411 | clp = find_confirmed_client_by_str(name, strhashval); |
4524 | return (crp && crp->cr_clp); | 4412 | return clp ? 1 : 0; |
4525 | } | 4413 | } |
4526 | 4414 | ||
4527 | /* | 4415 | /* |
4528 | * failure => all reset bets are off, nfserr_no_grace... | 4416 | * failure => all reset bets are off, nfserr_no_grace... |
4529 | */ | 4417 | */ |
4530 | struct nfs4_client_reclaim * | 4418 | int |
4531 | nfs4_client_to_reclaim(const char *name, struct nfsd_net *nn) | 4419 | nfs4_client_to_reclaim(const char *name) |
4532 | { | 4420 | { |
4533 | unsigned int strhashval; | 4421 | unsigned int strhashval; |
4534 | struct nfs4_client_reclaim *crp; | 4422 | struct nfs4_client_reclaim *crp = NULL; |
4535 | 4423 | ||
4536 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); | 4424 | dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name); |
4537 | crp = alloc_reclaim(); | 4425 | crp = alloc_reclaim(); |
4538 | if (crp) { | 4426 | if (!crp) |
4539 | strhashval = clientstr_hashval(name); | 4427 | return 0; |
4540 | INIT_LIST_HEAD(&crp->cr_strhash); | 4428 | strhashval = clientstr_hashval(name); |
4541 | list_add(&crp->cr_strhash, &nn->reclaim_str_hashtbl[strhashval]); | 4429 | INIT_LIST_HEAD(&crp->cr_strhash); |
4542 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); | 4430 | list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]); |
4543 | crp->cr_clp = NULL; | 4431 | memcpy(crp->cr_recdir, name, HEXDIR_LEN); |
4544 | nn->reclaim_str_hashtbl_size++; | 4432 | reclaim_str_hashtbl_size++; |
4545 | } | 4433 | return 1; |
4546 | return crp; | ||
4547 | } | ||
4548 | |||
4549 | void | ||
4550 | nfs4_remove_reclaim_record(struct nfs4_client_reclaim *crp, struct nfsd_net *nn) | ||
4551 | { | ||
4552 | list_del(&crp->cr_strhash); | ||
4553 | kfree(crp); | ||
4554 | nn->reclaim_str_hashtbl_size--; | ||
4555 | } | 4434 | } |
4556 | 4435 | ||
4557 | void | 4436 | static void |
4558 | nfs4_release_reclaim(struct nfsd_net *nn) | 4437 | nfs4_release_reclaim(void) |
4559 | { | 4438 | { |
4560 | struct nfs4_client_reclaim *crp = NULL; | 4439 | struct nfs4_client_reclaim *crp = NULL; |
4561 | int i; | 4440 | int i; |
4562 | 4441 | ||
4563 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | 4442 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
4564 | while (!list_empty(&nn->reclaim_str_hashtbl[i])) { | 4443 | while (!list_empty(&reclaim_str_hashtbl[i])) { |
4565 | crp = list_entry(nn->reclaim_str_hashtbl[i].next, | 4444 | crp = list_entry(reclaim_str_hashtbl[i].next, |
4566 | struct nfs4_client_reclaim, cr_strhash); | 4445 | struct nfs4_client_reclaim, cr_strhash); |
4567 | nfs4_remove_reclaim_record(crp, nn); | 4446 | list_del(&crp->cr_strhash); |
4447 | kfree(crp); | ||
4448 | reclaim_str_hashtbl_size--; | ||
4568 | } | 4449 | } |
4569 | } | 4450 | } |
4570 | WARN_ON_ONCE(nn->reclaim_str_hashtbl_size); | 4451 | BUG_ON(reclaim_str_hashtbl_size); |
4571 | } | 4452 | } |
4572 | 4453 | ||
4573 | /* | 4454 | /* |
4574 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ | 4455 | * called from OPEN, CLAIM_PREVIOUS with a new clientid. */ |
4575 | struct nfs4_client_reclaim * | 4456 | static struct nfs4_client_reclaim * |
4576 | nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) | 4457 | nfs4_find_reclaim_client(clientid_t *clid) |
4577 | { | 4458 | { |
4578 | unsigned int strhashval; | 4459 | unsigned int strhashval; |
4460 | struct nfs4_client *clp; | ||
4579 | struct nfs4_client_reclaim *crp = NULL; | 4461 | struct nfs4_client_reclaim *crp = NULL; |
4580 | 4462 | ||
4581 | dprintk("NFSD: nfs4_find_reclaim_client for recdir %s\n", recdir); | ||
4582 | 4463 | ||
4583 | strhashval = clientstr_hashval(recdir); | 4464 | /* find clientid in conf_id_hashtbl */ |
4584 | list_for_each_entry(crp, &nn->reclaim_str_hashtbl[strhashval], cr_strhash) { | 4465 | clp = find_confirmed_client(clid); |
4585 | if (same_name(crp->cr_recdir, recdir)) { | 4466 | if (clp == NULL) |
4467 | return NULL; | ||
4468 | |||
4469 | dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n", | ||
4470 | clp->cl_name.len, clp->cl_name.data, | ||
4471 | clp->cl_recdir); | ||
4472 | |||
4473 | /* find clp->cl_name in reclaim_str_hashtbl */ | ||
4474 | strhashval = clientstr_hashval(clp->cl_recdir); | ||
4475 | list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) { | ||
4476 | if (same_name(crp->cr_recdir, clp->cl_recdir)) { | ||
4586 | return crp; | 4477 | return crp; |
4587 | } | 4478 | } |
4588 | } | 4479 | } |
@@ -4593,206 +4484,64 @@ nfsd4_find_reclaim_client(const char *recdir, struct nfsd_net *nn) | |||
4593 | * Called from OPEN. Look for clientid in reclaim list. | 4484 | * Called from OPEN. Look for clientid in reclaim list. |
4594 | */ | 4485 | */ |
4595 | __be32 | 4486 | __be32 |
4596 | nfs4_check_open_reclaim(clientid_t *clid, bool sessions, struct nfsd_net *nn) | 4487 | nfs4_check_open_reclaim(clientid_t *clid) |
4597 | { | ||
4598 | struct nfs4_client *clp; | ||
4599 | |||
4600 | /* find clientid in conf_id_hashtbl */ | ||
4601 | clp = find_confirmed_client(clid, sessions, nn); | ||
4602 | if (clp == NULL) | ||
4603 | return nfserr_reclaim_bad; | ||
4604 | |||
4605 | return nfsd4_client_record_check(clp) ? nfserr_reclaim_bad : nfs_ok; | ||
4606 | } | ||
4607 | |||
4608 | #ifdef CONFIG_NFSD_FAULT_INJECTION | ||
4609 | |||
4610 | u64 nfsd_forget_client(struct nfs4_client *clp, u64 max) | ||
4611 | { | ||
4612 | expire_client(clp); | ||
4613 | return 1; | ||
4614 | } | ||
4615 | |||
4616 | u64 nfsd_print_client(struct nfs4_client *clp, u64 num) | ||
4617 | { | 4488 | { |
4618 | char buf[INET6_ADDRSTRLEN]; | 4489 | return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad; |
4619 | rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); | ||
4620 | printk(KERN_INFO "NFS Client: %s\n", buf); | ||
4621 | return 1; | ||
4622 | } | 4490 | } |
4623 | 4491 | ||
4624 | static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, | 4492 | /* initialization to perform at module load time: */ |
4625 | const char *type) | ||
4626 | { | ||
4627 | char buf[INET6_ADDRSTRLEN]; | ||
4628 | rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); | ||
4629 | printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); | ||
4630 | } | ||
4631 | 4493 | ||
4632 | static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_lockowner *)) | 4494 | int |
4495 | nfs4_state_init(void) | ||
4633 | { | 4496 | { |
4634 | struct nfs4_openowner *oop; | 4497 | int i, status; |
4635 | struct nfs4_lockowner *lop, *lo_next; | ||
4636 | struct nfs4_ol_stateid *stp, *st_next; | ||
4637 | u64 count = 0; | ||
4638 | 4498 | ||
4639 | list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { | 4499 | status = nfsd4_init_slabs(); |
4640 | list_for_each_entry_safe(stp, st_next, &oop->oo_owner.so_stateids, st_perstateowner) { | 4500 | if (status) |
4641 | list_for_each_entry_safe(lop, lo_next, &stp->st_lockowners, lo_perstateid) { | 4501 | return status; |
4642 | if (func) | 4502 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { |
4643 | func(lop); | 4503 | INIT_LIST_HEAD(&conf_id_hashtbl[i]); |
4644 | if (++count == max) | 4504 | INIT_LIST_HEAD(&conf_str_hashtbl[i]); |
4645 | return count; | 4505 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); |
4646 | } | 4506 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); |
4647 | } | 4507 | INIT_LIST_HEAD(&reclaim_str_hashtbl[i]); |
4648 | } | 4508 | } |
4649 | 4509 | for (i = 0; i < SESSION_HASH_SIZE; i++) | |
4650 | return count; | 4510 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); |
4651 | } | 4511 | for (i = 0; i < FILE_HASH_SIZE; i++) { |
4652 | 4512 | INIT_LIST_HEAD(&file_hashtbl[i]); | |
4653 | u64 nfsd_forget_client_locks(struct nfs4_client *clp, u64 max) | ||
4654 | { | ||
4655 | return nfsd_foreach_client_lock(clp, max, release_lockowner); | ||
4656 | } | ||
4657 | |||
4658 | u64 nfsd_print_client_locks(struct nfs4_client *clp, u64 max) | ||
4659 | { | ||
4660 | u64 count = nfsd_foreach_client_lock(clp, max, NULL); | ||
4661 | nfsd_print_count(clp, count, "locked files"); | ||
4662 | return count; | ||
4663 | } | ||
4664 | |||
4665 | static u64 nfsd_foreach_client_open(struct nfs4_client *clp, u64 max, void (*func)(struct nfs4_openowner *)) | ||
4666 | { | ||
4667 | struct nfs4_openowner *oop, *next; | ||
4668 | u64 count = 0; | ||
4669 | |||
4670 | list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { | ||
4671 | if (func) | ||
4672 | func(oop); | ||
4673 | if (++count == max) | ||
4674 | break; | ||
4675 | } | 4513 | } |
4676 | 4514 | for (i = 0; i < OWNER_HASH_SIZE; i++) { | |
4677 | return count; | 4515 | INIT_LIST_HEAD(&ownerstr_hashtbl[i]); |
4678 | } | 4516 | INIT_LIST_HEAD(&ownerid_hashtbl[i]); |
4679 | |||
4680 | u64 nfsd_forget_client_openowners(struct nfs4_client *clp, u64 max) | ||
4681 | { | ||
4682 | return nfsd_foreach_client_open(clp, max, release_openowner); | ||
4683 | } | ||
4684 | |||
4685 | u64 nfsd_print_client_openowners(struct nfs4_client *clp, u64 max) | ||
4686 | { | ||
4687 | u64 count = nfsd_foreach_client_open(clp, max, NULL); | ||
4688 | nfsd_print_count(clp, count, "open files"); | ||
4689 | return count; | ||
4690 | } | ||
4691 | |||
4692 | static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, | ||
4693 | struct list_head *victims) | ||
4694 | { | ||
4695 | struct nfs4_delegation *dp, *next; | ||
4696 | u64 count = 0; | ||
4697 | |||
4698 | list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { | ||
4699 | if (victims) | ||
4700 | list_move(&dp->dl_recall_lru, victims); | ||
4701 | if (++count == max) | ||
4702 | break; | ||
4703 | } | 4517 | } |
4704 | return count; | 4518 | for (i = 0; i < STATEID_HASH_SIZE; i++) { |
4705 | } | 4519 | INIT_LIST_HEAD(&stateid_hashtbl[i]); |
4706 | 4520 | INIT_LIST_HEAD(&lockstateid_hashtbl[i]); | |
4707 | u64 nfsd_forget_client_delegations(struct nfs4_client *clp, u64 max) | ||
4708 | { | ||
4709 | struct nfs4_delegation *dp, *next; | ||
4710 | LIST_HEAD(victims); | ||
4711 | u64 count; | ||
4712 | |||
4713 | spin_lock(&recall_lock); | ||
4714 | count = nfsd_find_all_delegations(clp, max, &victims); | ||
4715 | spin_unlock(&recall_lock); | ||
4716 | |||
4717 | list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) | ||
4718 | unhash_delegation(dp); | ||
4719 | |||
4720 | return count; | ||
4721 | } | ||
4722 | |||
4723 | u64 nfsd_recall_client_delegations(struct nfs4_client *clp, u64 max) | ||
4724 | { | ||
4725 | struct nfs4_delegation *dp, *next; | ||
4726 | LIST_HEAD(victims); | ||
4727 | u64 count; | ||
4728 | |||
4729 | spin_lock(&recall_lock); | ||
4730 | count = nfsd_find_all_delegations(clp, max, &victims); | ||
4731 | list_for_each_entry_safe(dp, next, &victims, dl_recall_lru) | ||
4732 | nfsd_break_one_deleg(dp); | ||
4733 | spin_unlock(&recall_lock); | ||
4734 | |||
4735 | return count; | ||
4736 | } | ||
4737 | |||
4738 | u64 nfsd_print_client_delegations(struct nfs4_client *clp, u64 max) | ||
4739 | { | ||
4740 | u64 count = 0; | ||
4741 | |||
4742 | spin_lock(&recall_lock); | ||
4743 | count = nfsd_find_all_delegations(clp, max, NULL); | ||
4744 | spin_unlock(&recall_lock); | ||
4745 | |||
4746 | nfsd_print_count(clp, count, "delegations"); | ||
4747 | return count; | ||
4748 | } | ||
4749 | |||
4750 | u64 nfsd_for_n_state(u64 max, u64 (*func)(struct nfs4_client *, u64)) | ||
4751 | { | ||
4752 | struct nfs4_client *clp, *next; | ||
4753 | u64 count = 0; | ||
4754 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); | ||
4755 | |||
4756 | if (!nfsd_netns_ready(nn)) | ||
4757 | return 0; | ||
4758 | |||
4759 | list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { | ||
4760 | count += func(clp, max - count); | ||
4761 | if ((max != 0) && (count >= max)) | ||
4762 | break; | ||
4763 | } | 4521 | } |
4764 | 4522 | for (i = 0; i < LOCK_HASH_SIZE; i++) { | |
4765 | return count; | 4523 | INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]); |
4766 | } | 4524 | INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]); |
4767 | |||
4768 | struct nfs4_client *nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) | ||
4769 | { | ||
4770 | struct nfs4_client *clp; | ||
4771 | struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, nfsd_net_id); | ||
4772 | |||
4773 | if (!nfsd_netns_ready(nn)) | ||
4774 | return NULL; | ||
4775 | |||
4776 | list_for_each_entry(clp, &nn->client_lru, cl_lru) { | ||
4777 | if (memcmp(&clp->cl_addr, addr, addr_size) == 0) | ||
4778 | return clp; | ||
4779 | } | 4525 | } |
4780 | return NULL; | 4526 | memset(&onestateid, ~0, sizeof(stateid_t)); |
4527 | INIT_LIST_HEAD(&close_lru); | ||
4528 | INIT_LIST_HEAD(&client_lru); | ||
4529 | INIT_LIST_HEAD(&del_recall_lru); | ||
4530 | reclaim_str_hashtbl_size = 0; | ||
4531 | return 0; | ||
4781 | } | 4532 | } |
4782 | 4533 | ||
4783 | #endif /* CONFIG_NFSD_FAULT_INJECTION */ | 4534 | static void |
4784 | 4535 | nfsd4_load_reboot_recovery_data(void) | |
4785 | /* initialization to perform at module load time: */ | ||
4786 | |||
4787 | void | ||
4788 | nfs4_state_init(void) | ||
4789 | { | 4536 | { |
4790 | int i; | 4537 | int status; |
4791 | 4538 | ||
4792 | for (i = 0; i < FILE_HASH_SIZE; i++) { | 4539 | nfs4_lock_state(); |
4793 | INIT_LIST_HEAD(&file_hashtbl[i]); | 4540 | nfsd4_init_recdir(user_recovery_dirname); |
4794 | } | 4541 | status = nfsd4_recdir_load(); |
4795 | INIT_LIST_HEAD(&del_recall_lru); | 4542 | nfs4_unlock_state(); |
4543 | if (status) | ||
4544 | printk("NFSD: Failure reading reboot recovery data\n"); | ||
4796 | } | 4545 | } |
4797 | 4546 | ||
4798 | /* | 4547 | /* |
@@ -4816,288 +4565,121 @@ set_max_delegations(void) | |||
4816 | max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); | 4565 | max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT); |
4817 | } | 4566 | } |
4818 | 4567 | ||
4819 | static int nfs4_state_create_net(struct net *net) | ||
4820 | { | ||
4821 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4822 | int i; | ||
4823 | |||
4824 | nn->conf_id_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4825 | CLIENT_HASH_SIZE, GFP_KERNEL); | ||
4826 | if (!nn->conf_id_hashtbl) | ||
4827 | goto err; | ||
4828 | nn->unconf_id_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4829 | CLIENT_HASH_SIZE, GFP_KERNEL); | ||
4830 | if (!nn->unconf_id_hashtbl) | ||
4831 | goto err_unconf_id; | ||
4832 | nn->ownerstr_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4833 | OWNER_HASH_SIZE, GFP_KERNEL); | ||
4834 | if (!nn->ownerstr_hashtbl) | ||
4835 | goto err_ownerstr; | ||
4836 | nn->lockowner_ino_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4837 | LOCKOWNER_INO_HASH_SIZE, GFP_KERNEL); | ||
4838 | if (!nn->lockowner_ino_hashtbl) | ||
4839 | goto err_lockowner_ino; | ||
4840 | nn->sessionid_hashtbl = kmalloc(sizeof(struct list_head) * | ||
4841 | SESSION_HASH_SIZE, GFP_KERNEL); | ||
4842 | if (!nn->sessionid_hashtbl) | ||
4843 | goto err_sessionid; | ||
4844 | |||
4845 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
4846 | INIT_LIST_HEAD(&nn->conf_id_hashtbl[i]); | ||
4847 | INIT_LIST_HEAD(&nn->unconf_id_hashtbl[i]); | ||
4848 | } | ||
4849 | for (i = 0; i < OWNER_HASH_SIZE; i++) | ||
4850 | INIT_LIST_HEAD(&nn->ownerstr_hashtbl[i]); | ||
4851 | for (i = 0; i < LOCKOWNER_INO_HASH_SIZE; i++) | ||
4852 | INIT_LIST_HEAD(&nn->lockowner_ino_hashtbl[i]); | ||
4853 | for (i = 0; i < SESSION_HASH_SIZE; i++) | ||
4854 | INIT_LIST_HEAD(&nn->sessionid_hashtbl[i]); | ||
4855 | nn->conf_name_tree = RB_ROOT; | ||
4856 | nn->unconf_name_tree = RB_ROOT; | ||
4857 | INIT_LIST_HEAD(&nn->client_lru); | ||
4858 | INIT_LIST_HEAD(&nn->close_lru); | ||
4859 | spin_lock_init(&nn->client_lock); | ||
4860 | |||
4861 | INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); | ||
4862 | get_net(net); | ||
4863 | |||
4864 | return 0; | ||
4865 | |||
4866 | err_sessionid: | ||
4867 | kfree(nn->lockowner_ino_hashtbl); | ||
4868 | err_lockowner_ino: | ||
4869 | kfree(nn->ownerstr_hashtbl); | ||
4870 | err_ownerstr: | ||
4871 | kfree(nn->unconf_id_hashtbl); | ||
4872 | err_unconf_id: | ||
4873 | kfree(nn->conf_id_hashtbl); | ||
4874 | err: | ||
4875 | return -ENOMEM; | ||
4876 | } | ||
4877 | |||
4878 | static void | ||
4879 | nfs4_state_destroy_net(struct net *net) | ||
4880 | { | ||
4881 | int i; | ||
4882 | struct nfs4_client *clp = NULL; | ||
4883 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4884 | struct rb_node *node, *tmp; | ||
4885 | |||
4886 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
4887 | while (!list_empty(&nn->conf_id_hashtbl[i])) { | ||
4888 | clp = list_entry(nn->conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); | ||
4889 | destroy_client(clp); | ||
4890 | } | ||
4891 | } | ||
4892 | |||
4893 | node = rb_first(&nn->unconf_name_tree); | ||
4894 | while (node != NULL) { | ||
4895 | tmp = node; | ||
4896 | node = rb_next(tmp); | ||
4897 | clp = rb_entry(tmp, struct nfs4_client, cl_namenode); | ||
4898 | rb_erase(tmp, &nn->unconf_name_tree); | ||
4899 | destroy_client(clp); | ||
4900 | } | ||
4901 | |||
4902 | kfree(nn->sessionid_hashtbl); | ||
4903 | kfree(nn->lockowner_ino_hashtbl); | ||
4904 | kfree(nn->ownerstr_hashtbl); | ||
4905 | kfree(nn->unconf_id_hashtbl); | ||
4906 | kfree(nn->conf_id_hashtbl); | ||
4907 | put_net(net); | ||
4908 | } | ||
4909 | |||
4910 | int | ||
4911 | nfs4_state_start_net(struct net *net) | ||
4912 | { | ||
4913 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4914 | int ret; | ||
4915 | |||
4916 | /* | ||
4917 | * FIXME: For now, we hang most of the pernet global stuff off of | ||
4918 | * init_net until nfsd is fully containerized. Eventually, we'll | ||
4919 | * need to pass a net pointer into this function, take a reference | ||
4920 | * to that instead and then do most of the rest of this on a per-net | ||
4921 | * basis. | ||
4922 | */ | ||
4923 | if (net != &init_net) | ||
4924 | return -EINVAL; | ||
4925 | |||
4926 | ret = nfs4_state_create_net(net); | ||
4927 | if (ret) | ||
4928 | return ret; | ||
4929 | nfsd4_client_tracking_init(net); | ||
4930 | nn->boot_time = get_seconds(); | ||
4931 | locks_start_grace(net, &nn->nfsd4_manager); | ||
4932 | nn->grace_ended = false; | ||
4933 | printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n", | ||
4934 | nn->nfsd4_grace, net); | ||
4935 | queue_delayed_work(laundry_wq, &nn->laundromat_work, nn->nfsd4_grace * HZ); | ||
4936 | return 0; | ||
4937 | } | ||
4938 | |||
4939 | /* initialization to perform when the nfsd service is started: */ | 4568 | /* initialization to perform when the nfsd service is started: */ |
4940 | 4569 | ||
4941 | int | 4570 | static int |
4942 | nfs4_state_start(void) | 4571 | __nfs4_state_start(void) |
4943 | { | 4572 | { |
4944 | int ret; | 4573 | int ret; |
4945 | 4574 | ||
4575 | boot_time = get_seconds(); | ||
4576 | locks_start_grace(&nfsd4_manager); | ||
4577 | printk(KERN_INFO "NFSD: starting %ld-second grace period\n", | ||
4578 | nfsd4_grace); | ||
4946 | ret = set_callback_cred(); | 4579 | ret = set_callback_cred(); |
4947 | if (ret) | 4580 | if (ret) |
4948 | return -ENOMEM; | 4581 | return -ENOMEM; |
4949 | laundry_wq = create_singlethread_workqueue("nfsd4"); | 4582 | laundry_wq = create_singlethread_workqueue("nfsd4"); |
4950 | if (laundry_wq == NULL) { | 4583 | if (laundry_wq == NULL) |
4951 | ret = -ENOMEM; | 4584 | return -ENOMEM; |
4952 | goto out_recovery; | ||
4953 | } | ||
4954 | ret = nfsd4_create_callback_queue(); | 4585 | ret = nfsd4_create_callback_queue(); |
4955 | if (ret) | 4586 | if (ret) |
4956 | goto out_free_laundry; | 4587 | goto out_free_laundry; |
4957 | 4588 | queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ); | |
4958 | set_max_delegations(); | 4589 | set_max_delegations(); |
4959 | |||
4960 | return 0; | 4590 | return 0; |
4961 | |||
4962 | out_free_laundry: | 4591 | out_free_laundry: |
4963 | destroy_workqueue(laundry_wq); | 4592 | destroy_workqueue(laundry_wq); |
4964 | out_recovery: | ||
4965 | return ret; | 4593 | return ret; |
4966 | } | 4594 | } |
4967 | 4595 | ||
4968 | /* should be called with the state lock held */ | 4596 | int |
4969 | void | 4597 | nfs4_state_start(void) |
4970 | nfs4_state_shutdown_net(struct net *net) | 4598 | { |
4599 | nfsd4_load_reboot_recovery_data(); | ||
4600 | return __nfs4_state_start(); | ||
4601 | } | ||
4602 | |||
4603 | static void | ||
4604 | __nfs4_state_shutdown(void) | ||
4971 | { | 4605 | { |
4606 | int i; | ||
4607 | struct nfs4_client *clp = NULL; | ||
4972 | struct nfs4_delegation *dp = NULL; | 4608 | struct nfs4_delegation *dp = NULL; |
4973 | struct list_head *pos, *next, reaplist; | 4609 | struct list_head *pos, *next, reaplist; |
4974 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | ||
4975 | |||
4976 | cancel_delayed_work_sync(&nn->laundromat_work); | ||
4977 | locks_end_grace(&nn->nfsd4_manager); | ||
4978 | 4610 | ||
4611 | for (i = 0; i < CLIENT_HASH_SIZE; i++) { | ||
4612 | while (!list_empty(&conf_id_hashtbl[i])) { | ||
4613 | clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); | ||
4614 | expire_client(clp); | ||
4615 | } | ||
4616 | while (!list_empty(&unconf_str_hashtbl[i])) { | ||
4617 | clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash); | ||
4618 | expire_client(clp); | ||
4619 | } | ||
4620 | } | ||
4979 | INIT_LIST_HEAD(&reaplist); | 4621 | INIT_LIST_HEAD(&reaplist); |
4980 | spin_lock(&recall_lock); | 4622 | spin_lock(&recall_lock); |
4981 | list_for_each_safe(pos, next, &del_recall_lru) { | 4623 | list_for_each_safe(pos, next, &del_recall_lru) { |
4982 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 4624 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
4983 | if (dp->dl_stid.sc_client->net != net) | ||
4984 | continue; | ||
4985 | list_move(&dp->dl_recall_lru, &reaplist); | 4625 | list_move(&dp->dl_recall_lru, &reaplist); |
4986 | } | 4626 | } |
4987 | spin_unlock(&recall_lock); | 4627 | spin_unlock(&recall_lock); |
4988 | list_for_each_safe(pos, next, &reaplist) { | 4628 | list_for_each_safe(pos, next, &reaplist) { |
4989 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); | 4629 | dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); |
4630 | list_del_init(&dp->dl_recall_lru); | ||
4990 | unhash_delegation(dp); | 4631 | unhash_delegation(dp); |
4991 | } | 4632 | } |
4992 | 4633 | ||
4993 | nfsd4_client_tracking_exit(net); | 4634 | nfsd4_shutdown_recdir(); |
4994 | nfs4_state_destroy_net(net); | ||
4995 | } | 4635 | } |
4996 | 4636 | ||
4997 | void | 4637 | void |
4998 | nfs4_state_shutdown(void) | 4638 | nfs4_state_shutdown(void) |
4999 | { | 4639 | { |
4640 | cancel_delayed_work_sync(&laundromat_work); | ||
5000 | destroy_workqueue(laundry_wq); | 4641 | destroy_workqueue(laundry_wq); |
4642 | locks_end_grace(&nfsd4_manager); | ||
4643 | nfs4_lock_state(); | ||
4644 | nfs4_release_reclaim(); | ||
4645 | __nfs4_state_shutdown(); | ||
4646 | nfs4_unlock_state(); | ||
5001 | nfsd4_destroy_callback_queue(); | 4647 | nfsd4_destroy_callback_queue(); |
5002 | } | 4648 | } |
5003 | 4649 | ||
5004 | static void | ||
5005 | get_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) | ||
5006 | { | ||
5007 | if (HAS_STATE_ID(cstate, CURRENT_STATE_ID_FLAG) && CURRENT_STATEID(stateid)) | ||
5008 | memcpy(stateid, &cstate->current_stateid, sizeof(stateid_t)); | ||
5009 | } | ||
5010 | |||
5011 | static void | ||
5012 | put_stateid(struct nfsd4_compound_state *cstate, stateid_t *stateid) | ||
5013 | { | ||
5014 | if (cstate->minorversion) { | ||
5015 | memcpy(&cstate->current_stateid, stateid, sizeof(stateid_t)); | ||
5016 | SET_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); | ||
5017 | } | ||
5018 | } | ||
5019 | |||
5020 | void | ||
5021 | clear_current_stateid(struct nfsd4_compound_state *cstate) | ||
5022 | { | ||
5023 | CLEAR_STATE_ID(cstate, CURRENT_STATE_ID_FLAG); | ||
5024 | } | ||
5025 | |||
5026 | /* | 4650 | /* |
5027 | * functions to set current state id | 4651 | * user_recovery_dirname is protected by the nfsd_mutex since it's only |
4652 | * accessed when nfsd is starting. | ||
5028 | */ | 4653 | */ |
5029 | void | 4654 | static void |
5030 | nfsd4_set_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) | 4655 | nfs4_set_recdir(char *recdir) |
5031 | { | ||
5032 | put_stateid(cstate, &odp->od_stateid); | ||
5033 | } | ||
5034 | |||
5035 | void | ||
5036 | nfsd4_set_openstateid(struct nfsd4_compound_state *cstate, struct nfsd4_open *open) | ||
5037 | { | ||
5038 | put_stateid(cstate, &open->op_stateid); | ||
5039 | } | ||
5040 | |||
5041 | void | ||
5042 | nfsd4_set_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) | ||
5043 | { | ||
5044 | put_stateid(cstate, &close->cl_stateid); | ||
5045 | } | ||
5046 | |||
5047 | void | ||
5048 | nfsd4_set_lockstateid(struct nfsd4_compound_state *cstate, struct nfsd4_lock *lock) | ||
5049 | { | 4656 | { |
5050 | put_stateid(cstate, &lock->lk_resp_stateid); | 4657 | strcpy(user_recovery_dirname, recdir); |
5051 | } | 4658 | } |
5052 | 4659 | ||
5053 | /* | 4660 | /* |
5054 | * functions to consume current state id | 4661 | * Change the NFSv4 recovery directory to recdir. |
5055 | */ | 4662 | */ |
5056 | 4663 | int | |
5057 | void | 4664 | nfs4_reset_recoverydir(char *recdir) |
5058 | nfsd4_get_opendowngradestateid(struct nfsd4_compound_state *cstate, struct nfsd4_open_downgrade *odp) | ||
5059 | { | ||
5060 | get_stateid(cstate, &odp->od_stateid); | ||
5061 | } | ||
5062 | |||
5063 | void | ||
5064 | nfsd4_get_delegreturnstateid(struct nfsd4_compound_state *cstate, struct nfsd4_delegreturn *drp) | ||
5065 | { | ||
5066 | get_stateid(cstate, &drp->dr_stateid); | ||
5067 | } | ||
5068 | |||
5069 | void | ||
5070 | nfsd4_get_freestateid(struct nfsd4_compound_state *cstate, struct nfsd4_free_stateid *fsp) | ||
5071 | { | ||
5072 | get_stateid(cstate, &fsp->fr_stateid); | ||
5073 | } | ||
5074 | |||
5075 | void | ||
5076 | nfsd4_get_setattrstateid(struct nfsd4_compound_state *cstate, struct nfsd4_setattr *setattr) | ||
5077 | { | ||
5078 | get_stateid(cstate, &setattr->sa_stateid); | ||
5079 | } | ||
5080 | |||
5081 | void | ||
5082 | nfsd4_get_closestateid(struct nfsd4_compound_state *cstate, struct nfsd4_close *close) | ||
5083 | { | ||
5084 | get_stateid(cstate, &close->cl_stateid); | ||
5085 | } | ||
5086 | |||
5087 | void | ||
5088 | nfsd4_get_lockustateid(struct nfsd4_compound_state *cstate, struct nfsd4_locku *locku) | ||
5089 | { | 4665 | { |
5090 | get_stateid(cstate, &locku->lu_stateid); | 4666 | int status; |
5091 | } | 4667 | struct path path; |
5092 | 4668 | ||
5093 | void | 4669 | status = kern_path(recdir, LOOKUP_FOLLOW, &path); |
5094 | nfsd4_get_readstateid(struct nfsd4_compound_state *cstate, struct nfsd4_read *read) | 4670 | if (status) |
5095 | { | 4671 | return status; |
5096 | get_stateid(cstate, &read->rd_stateid); | 4672 | status = -ENOTDIR; |
4673 | if (S_ISDIR(path.dentry->d_inode->i_mode)) { | ||
4674 | nfs4_set_recdir(recdir); | ||
4675 | status = 0; | ||
4676 | } | ||
4677 | path_put(&path); | ||
4678 | return status; | ||
5097 | } | 4679 | } |
5098 | 4680 | ||
5099 | void | 4681 | char * |
5100 | nfsd4_get_writestateid(struct nfsd4_compound_state *cstate, struct nfsd4_write *write) | 4682 | nfs4_recoverydir(void) |
5101 | { | 4683 | { |
5102 | get_stateid(cstate, &write->wr_stateid); | 4684 | return user_recovery_dirname; |
5103 | } | 4685 | } |