diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 1196 |
1 files changed, 1017 insertions, 179 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index b6f60f48e94b..c65a27b76a9d 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -68,6 +68,7 @@ static u32 current_delegid = 1; | |||
68 | static u32 nfs4_init; | 68 | static u32 nfs4_init; |
69 | static stateid_t zerostateid; /* bits all 0 */ | 69 | static stateid_t zerostateid; /* bits all 0 */ |
70 | static stateid_t onestateid; /* bits all 1 */ | 70 | static stateid_t onestateid; /* bits all 1 */ |
71 | static u64 current_sessionid = 1; | ||
71 | 72 | ||
72 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) | 73 | #define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t))) |
73 | #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) | 74 | #define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t))) |
@@ -75,18 +76,21 @@ static stateid_t onestateid; /* bits all 1 */ | |||
75 | /* forward declarations */ | 76 | /* forward declarations */ |
76 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); | 77 | static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags); |
77 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); | 78 | static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid); |
78 | static void release_stateid_lockowners(struct nfs4_stateid *open_stp); | ||
79 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; | 79 | static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery"; |
80 | static void nfs4_set_recdir(char *recdir); | 80 | static void nfs4_set_recdir(char *recdir); |
81 | 81 | ||
82 | /* Locking: | 82 | /* Locking: */ |
83 | * | 83 | |
84 | * client_mutex: | 84 | /* Currently used for almost all code touching nfsv4 state: */ |
85 | * protects clientid_hashtbl[], clientstr_hashtbl[], | ||
86 | * unconfstr_hashtbl[], uncofid_hashtbl[]. | ||
87 | */ | ||
88 | static DEFINE_MUTEX(client_mutex); | 85 | static DEFINE_MUTEX(client_mutex); |
89 | 86 | ||
87 | /* | ||
88 | * Currently used for the del_recall_lru and file hash table. In an | ||
89 | * effort to decrease the scope of the client_mutex, this spinlock may | ||
90 | * eventually cover more: | ||
91 | */ | ||
92 | static DEFINE_SPINLOCK(recall_lock); | ||
93 | |||
90 | static struct kmem_cache *stateowner_slab = NULL; | 94 | static struct kmem_cache *stateowner_slab = NULL; |
91 | static struct kmem_cache *file_slab = NULL; | 95 | static struct kmem_cache *file_slab = NULL; |
92 | static struct kmem_cache *stateid_slab = NULL; | 96 | static struct kmem_cache *stateid_slab = NULL; |
@@ -117,37 +121,23 @@ opaque_hashval(const void *ptr, int nbytes) | |||
117 | return x; | 121 | return x; |
118 | } | 122 | } |
119 | 123 | ||
120 | /* forward declarations */ | ||
121 | static void release_stateowner(struct nfs4_stateowner *sop); | ||
122 | static void release_stateid(struct nfs4_stateid *stp, int flags); | ||
123 | |||
124 | /* | ||
125 | * Delegation state | ||
126 | */ | ||
127 | |||
128 | /* recall_lock protects the del_recall_lru */ | ||
129 | static DEFINE_SPINLOCK(recall_lock); | ||
130 | static struct list_head del_recall_lru; | 124 | static struct list_head del_recall_lru; |
131 | 125 | ||
132 | static void | ||
133 | free_nfs4_file(struct kref *kref) | ||
134 | { | ||
135 | struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref); | ||
136 | list_del(&fp->fi_hash); | ||
137 | iput(fp->fi_inode); | ||
138 | kmem_cache_free(file_slab, fp); | ||
139 | } | ||
140 | |||
141 | static inline void | 126 | static inline void |
142 | put_nfs4_file(struct nfs4_file *fi) | 127 | put_nfs4_file(struct nfs4_file *fi) |
143 | { | 128 | { |
144 | kref_put(&fi->fi_ref, free_nfs4_file); | 129 | if (atomic_dec_and_lock(&fi->fi_ref, &recall_lock)) { |
130 | list_del(&fi->fi_hash); | ||
131 | spin_unlock(&recall_lock); | ||
132 | iput(fi->fi_inode); | ||
133 | kmem_cache_free(file_slab, fi); | ||
134 | } | ||
145 | } | 135 | } |
146 | 136 | ||
147 | static inline void | 137 | static inline void |
148 | get_nfs4_file(struct nfs4_file *fi) | 138 | get_nfs4_file(struct nfs4_file *fi) |
149 | { | 139 | { |
150 | kref_get(&fi->fi_ref); | 140 | atomic_inc(&fi->fi_ref); |
151 | } | 141 | } |
152 | 142 | ||
153 | static int num_delegations; | 143 | static int num_delegations; |
@@ -220,9 +210,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f | |||
220 | dp->dl_stateid.si_stateownerid = current_delegid++; | 210 | dp->dl_stateid.si_stateownerid = current_delegid++; |
221 | dp->dl_stateid.si_fileid = 0; | 211 | dp->dl_stateid.si_fileid = 0; |
222 | dp->dl_stateid.si_generation = 0; | 212 | dp->dl_stateid.si_generation = 0; |
223 | dp->dl_fhlen = current_fh->fh_handle.fh_size; | 213 | fh_copy_shallow(&dp->dl_fh, ¤t_fh->fh_handle); |
224 | memcpy(dp->dl_fhval, ¤t_fh->fh_handle.fh_base, | ||
225 | current_fh->fh_handle.fh_size); | ||
226 | dp->dl_time = 0; | 214 | dp->dl_time = 0; |
227 | atomic_set(&dp->dl_count, 1); | 215 | atomic_set(&dp->dl_count, 1); |
228 | list_add(&dp->dl_perfile, &fp->fi_delegations); | 216 | list_add(&dp->dl_perfile, &fp->fi_delegations); |
@@ -311,6 +299,291 @@ static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE]; | |||
311 | static struct list_head client_lru; | 299 | static struct list_head client_lru; |
312 | static struct list_head close_lru; | 300 | static struct list_head close_lru; |
313 | 301 | ||
302 | static void unhash_generic_stateid(struct nfs4_stateid *stp) | ||
303 | { | ||
304 | list_del(&stp->st_hash); | ||
305 | list_del(&stp->st_perfile); | ||
306 | list_del(&stp->st_perstateowner); | ||
307 | } | ||
308 | |||
309 | static void free_generic_stateid(struct nfs4_stateid *stp) | ||
310 | { | ||
311 | put_nfs4_file(stp->st_file); | ||
312 | kmem_cache_free(stateid_slab, stp); | ||
313 | } | ||
314 | |||
315 | static void release_lock_stateid(struct nfs4_stateid *stp) | ||
316 | { | ||
317 | unhash_generic_stateid(stp); | ||
318 | locks_remove_posix(stp->st_vfs_file, (fl_owner_t)stp->st_stateowner); | ||
319 | free_generic_stateid(stp); | ||
320 | } | ||
321 | |||
322 | static void unhash_lockowner(struct nfs4_stateowner *sop) | ||
323 | { | ||
324 | struct nfs4_stateid *stp; | ||
325 | |||
326 | list_del(&sop->so_idhash); | ||
327 | list_del(&sop->so_strhash); | ||
328 | list_del(&sop->so_perstateid); | ||
329 | while (!list_empty(&sop->so_stateids)) { | ||
330 | stp = list_first_entry(&sop->so_stateids, | ||
331 | struct nfs4_stateid, st_perstateowner); | ||
332 | release_lock_stateid(stp); | ||
333 | } | ||
334 | } | ||
335 | |||
336 | static void release_lockowner(struct nfs4_stateowner *sop) | ||
337 | { | ||
338 | unhash_lockowner(sop); | ||
339 | nfs4_put_stateowner(sop); | ||
340 | } | ||
341 | |||
342 | static void | ||
343 | release_stateid_lockowners(struct nfs4_stateid *open_stp) | ||
344 | { | ||
345 | struct nfs4_stateowner *lock_sop; | ||
346 | |||
347 | while (!list_empty(&open_stp->st_lockowners)) { | ||
348 | lock_sop = list_entry(open_stp->st_lockowners.next, | ||
349 | struct nfs4_stateowner, so_perstateid); | ||
350 | /* list_del(&open_stp->st_lockowners); */ | ||
351 | BUG_ON(lock_sop->so_is_open_owner); | ||
352 | release_lockowner(lock_sop); | ||
353 | } | ||
354 | } | ||
355 | |||
356 | static void release_open_stateid(struct nfs4_stateid *stp) | ||
357 | { | ||
358 | unhash_generic_stateid(stp); | ||
359 | release_stateid_lockowners(stp); | ||
360 | nfsd_close(stp->st_vfs_file); | ||
361 | free_generic_stateid(stp); | ||
362 | } | ||
363 | |||
364 | static void unhash_openowner(struct nfs4_stateowner *sop) | ||
365 | { | ||
366 | struct nfs4_stateid *stp; | ||
367 | |||
368 | list_del(&sop->so_idhash); | ||
369 | list_del(&sop->so_strhash); | ||
370 | list_del(&sop->so_perclient); | ||
371 | list_del(&sop->so_perstateid); /* XXX: necessary? */ | ||
372 | while (!list_empty(&sop->so_stateids)) { | ||
373 | stp = list_first_entry(&sop->so_stateids, | ||
374 | struct nfs4_stateid, st_perstateowner); | ||
375 | release_open_stateid(stp); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | static void release_openowner(struct nfs4_stateowner *sop) | ||
380 | { | ||
381 | unhash_openowner(sop); | ||
382 | list_del(&sop->so_close_lru); | ||
383 | nfs4_put_stateowner(sop); | ||
384 | } | ||
385 | |||
386 | static DEFINE_SPINLOCK(sessionid_lock); | ||
387 | #define SESSION_HASH_SIZE 512 | ||
388 | static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE]; | ||
389 | |||
390 | static inline int | ||
391 | hash_sessionid(struct nfs4_sessionid *sessionid) | ||
392 | { | ||
393 | struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid; | ||
394 | |||
395 | return sid->sequence % SESSION_HASH_SIZE; | ||
396 | } | ||
397 | |||
398 | static inline void | ||
399 | dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid) | ||
400 | { | ||
401 | u32 *ptr = (u32 *)(&sessionid->data[0]); | ||
402 | dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]); | ||
403 | } | ||
404 | |||
405 | static void | ||
406 | gen_sessionid(struct nfsd4_session *ses) | ||
407 | { | ||
408 | struct nfs4_client *clp = ses->se_client; | ||
409 | struct nfsd4_sessionid *sid; | ||
410 | |||
411 | sid = (struct nfsd4_sessionid *)ses->se_sessionid.data; | ||
412 | sid->clientid = clp->cl_clientid; | ||
413 | sid->sequence = current_sessionid++; | ||
414 | sid->reserved = 0; | ||
415 | } | ||
416 | |||
417 | /* | ||
418 | * Give the client the number of slots it requests bound by | ||
419 | * NFSD_MAX_SLOTS_PER_SESSION and by sv_drc_max_pages. | ||
420 | * | ||
421 | * If we run out of pages (sv_drc_pages_used == sv_drc_max_pages) we | ||
422 | * should (up to a point) re-negotiate active sessions and reduce their | ||
423 | * slot usage to make rooom for new connections. For now we just fail the | ||
424 | * create session. | ||
425 | */ | ||
426 | static int set_forechannel_maxreqs(struct nfsd4_channel_attrs *fchan) | ||
427 | { | ||
428 | int status = 0, np = fchan->maxreqs * NFSD_PAGES_PER_SLOT; | ||
429 | |||
430 | spin_lock(&nfsd_serv->sv_lock); | ||
431 | if (np + nfsd_serv->sv_drc_pages_used > nfsd_serv->sv_drc_max_pages) | ||
432 | np = nfsd_serv->sv_drc_max_pages - nfsd_serv->sv_drc_pages_used; | ||
433 | nfsd_serv->sv_drc_pages_used += np; | ||
434 | spin_unlock(&nfsd_serv->sv_lock); | ||
435 | |||
436 | if (np <= 0) { | ||
437 | status = nfserr_resource; | ||
438 | fchan->maxreqs = 0; | ||
439 | } else | ||
440 | fchan->maxreqs = np / NFSD_PAGES_PER_SLOT; | ||
441 | |||
442 | return status; | ||
443 | } | ||
444 | |||
445 | /* | ||
446 | * fchan holds the client values on input, and the server values on output | ||
447 | */ | ||
448 | static int init_forechannel_attrs(struct svc_rqst *rqstp, | ||
449 | struct nfsd4_session *session, | ||
450 | struct nfsd4_channel_attrs *fchan) | ||
451 | { | ||
452 | int status = 0; | ||
453 | __u32 maxcount = svc_max_payload(rqstp); | ||
454 | |||
455 | /* headerpadsz set to zero in encode routine */ | ||
456 | |||
457 | /* Use the client's max request and max response size if possible */ | ||
458 | if (fchan->maxreq_sz > maxcount) | ||
459 | fchan->maxreq_sz = maxcount; | ||
460 | session->se_fmaxreq_sz = fchan->maxreq_sz; | ||
461 | |||
462 | if (fchan->maxresp_sz > maxcount) | ||
463 | fchan->maxresp_sz = maxcount; | ||
464 | session->se_fmaxresp_sz = fchan->maxresp_sz; | ||
465 | |||
466 | /* Set the max response cached size our default which is | ||
467 | * a multiple of PAGE_SIZE and small */ | ||
468 | session->se_fmaxresp_cached = NFSD_PAGES_PER_SLOT * PAGE_SIZE; | ||
469 | fchan->maxresp_cached = session->se_fmaxresp_cached; | ||
470 | |||
471 | /* Use the client's maxops if possible */ | ||
472 | if (fchan->maxops > NFSD_MAX_OPS_PER_COMPOUND) | ||
473 | fchan->maxops = NFSD_MAX_OPS_PER_COMPOUND; | ||
474 | session->se_fmaxops = fchan->maxops; | ||
475 | |||
476 | /* try to use the client requested number of slots */ | ||
477 | if (fchan->maxreqs > NFSD_MAX_SLOTS_PER_SESSION) | ||
478 | fchan->maxreqs = NFSD_MAX_SLOTS_PER_SESSION; | ||
479 | |||
480 | /* FIXME: Error means no more DRC pages so the server should | ||
481 | * recover pages from existing sessions. For now fail session | ||
482 | * creation. | ||
483 | */ | ||
484 | status = set_forechannel_maxreqs(fchan); | ||
485 | |||
486 | session->se_fnumslots = fchan->maxreqs; | ||
487 | return status; | ||
488 | } | ||
489 | |||
490 | static int | ||
491 | alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, | ||
492 | struct nfsd4_create_session *cses) | ||
493 | { | ||
494 | struct nfsd4_session *new, tmp; | ||
495 | int idx, status = nfserr_resource, slotsize; | ||
496 | |||
497 | memset(&tmp, 0, sizeof(tmp)); | ||
498 | |||
499 | /* FIXME: For now, we just accept the client back channel attributes. */ | ||
500 | status = init_forechannel_attrs(rqstp, &tmp, &cses->fore_channel); | ||
501 | if (status) | ||
502 | goto out; | ||
503 | |||
504 | /* allocate struct nfsd4_session and slot table in one piece */ | ||
505 | slotsize = tmp.se_fnumslots * sizeof(struct nfsd4_slot); | ||
506 | new = kzalloc(sizeof(*new) + slotsize, GFP_KERNEL); | ||
507 | if (!new) | ||
508 | goto out; | ||
509 | |||
510 | memcpy(new, &tmp, sizeof(*new)); | ||
511 | |||
512 | new->se_client = clp; | ||
513 | gen_sessionid(new); | ||
514 | idx = hash_sessionid(&new->se_sessionid); | ||
515 | memcpy(clp->cl_sessionid.data, new->se_sessionid.data, | ||
516 | NFS4_MAX_SESSIONID_LEN); | ||
517 | |||
518 | new->se_flags = cses->flags; | ||
519 | kref_init(&new->se_ref); | ||
520 | spin_lock(&sessionid_lock); | ||
521 | list_add(&new->se_hash, &sessionid_hashtbl[idx]); | ||
522 | list_add(&new->se_perclnt, &clp->cl_sessions); | ||
523 | spin_unlock(&sessionid_lock); | ||
524 | |||
525 | status = nfs_ok; | ||
526 | out: | ||
527 | return status; | ||
528 | } | ||
529 | |||
530 | /* caller must hold sessionid_lock */ | ||
531 | static struct nfsd4_session * | ||
532 | find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid) | ||
533 | { | ||
534 | struct nfsd4_session *elem; | ||
535 | int idx; | ||
536 | |||
537 | dump_sessionid(__func__, sessionid); | ||
538 | idx = hash_sessionid(sessionid); | ||
539 | dprintk("%s: idx is %d\n", __func__, idx); | ||
540 | /* Search in the appropriate list */ | ||
541 | list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) { | ||
542 | dump_sessionid("list traversal", &elem->se_sessionid); | ||
543 | if (!memcmp(elem->se_sessionid.data, sessionid->data, | ||
544 | NFS4_MAX_SESSIONID_LEN)) { | ||
545 | return elem; | ||
546 | } | ||
547 | } | ||
548 | |||
549 | dprintk("%s: session not found\n", __func__); | ||
550 | return NULL; | ||
551 | } | ||
552 | |||
553 | /* caller must hold sessionid_lock */ | ||
554 | static void | ||
555 | unhash_session(struct nfsd4_session *ses) | ||
556 | { | ||
557 | list_del(&ses->se_hash); | ||
558 | list_del(&ses->se_perclnt); | ||
559 | } | ||
560 | |||
561 | static void | ||
562 | release_session(struct nfsd4_session *ses) | ||
563 | { | ||
564 | spin_lock(&sessionid_lock); | ||
565 | unhash_session(ses); | ||
566 | spin_unlock(&sessionid_lock); | ||
567 | nfsd4_put_session(ses); | ||
568 | } | ||
569 | |||
570 | static void nfsd4_release_respages(struct page **respages, short resused); | ||
571 | |||
572 | void | ||
573 | free_session(struct kref *kref) | ||
574 | { | ||
575 | struct nfsd4_session *ses; | ||
576 | int i; | ||
577 | |||
578 | ses = container_of(kref, struct nfsd4_session, se_ref); | ||
579 | for (i = 0; i < ses->se_fnumslots; i++) { | ||
580 | struct nfsd4_cache_entry *e = &ses->se_slots[i].sl_cache_entry; | ||
581 | nfsd4_release_respages(e->ce_respages, e->ce_resused); | ||
582 | } | ||
583 | kfree(ses->se_slots); | ||
584 | kfree(ses); | ||
585 | } | ||
586 | |||
314 | static inline void | 587 | static inline void |
315 | renew_client(struct nfs4_client *clp) | 588 | renew_client(struct nfs4_client *clp) |
316 | { | 589 | { |
@@ -330,8 +603,8 @@ STALE_CLIENTID(clientid_t *clid) | |||
330 | { | 603 | { |
331 | if (clid->cl_boot == boot_time) | 604 | if (clid->cl_boot == boot_time) |
332 | return 0; | 605 | return 0; |
333 | dprintk("NFSD stale clientid (%08x/%08x)\n", | 606 | dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n", |
334 | clid->cl_boot, clid->cl_id); | 607 | clid->cl_boot, clid->cl_id, boot_time); |
335 | return 1; | 608 | return 1; |
336 | } | 609 | } |
337 | 610 | ||
@@ -376,6 +649,8 @@ static inline void | |||
376 | free_client(struct nfs4_client *clp) | 649 | free_client(struct nfs4_client *clp) |
377 | { | 650 | { |
378 | shutdown_callback_client(clp); | 651 | shutdown_callback_client(clp); |
652 | nfsd4_release_respages(clp->cl_slot.sl_cache_entry.ce_respages, | ||
653 | clp->cl_slot.sl_cache_entry.ce_resused); | ||
379 | if (clp->cl_cred.cr_group_info) | 654 | if (clp->cl_cred.cr_group_info) |
380 | put_group_info(clp->cl_cred.cr_group_info); | 655 | put_group_info(clp->cl_cred.cr_group_info); |
381 | kfree(clp->cl_principal); | 656 | kfree(clp->cl_principal); |
@@ -420,7 +695,13 @@ expire_client(struct nfs4_client *clp) | |||
420 | list_del(&clp->cl_lru); | 695 | list_del(&clp->cl_lru); |
421 | while (!list_empty(&clp->cl_openowners)) { | 696 | while (!list_empty(&clp->cl_openowners)) { |
422 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); | 697 | sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient); |
423 | release_stateowner(sop); | 698 | release_openowner(sop); |
699 | } | ||
700 | while (!list_empty(&clp->cl_sessions)) { | ||
701 | struct nfsd4_session *ses; | ||
702 | ses = list_entry(clp->cl_sessions.next, struct nfsd4_session, | ||
703 | se_perclnt); | ||
704 | release_session(ses); | ||
424 | } | 705 | } |
425 | put_nfs4_client(clp); | 706 | put_nfs4_client(clp); |
426 | } | 707 | } |
@@ -439,6 +720,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir) | |||
439 | INIT_LIST_HEAD(&clp->cl_strhash); | 720 | INIT_LIST_HEAD(&clp->cl_strhash); |
440 | INIT_LIST_HEAD(&clp->cl_openowners); | 721 | INIT_LIST_HEAD(&clp->cl_openowners); |
441 | INIT_LIST_HEAD(&clp->cl_delegations); | 722 | INIT_LIST_HEAD(&clp->cl_delegations); |
723 | INIT_LIST_HEAD(&clp->cl_sessions); | ||
442 | INIT_LIST_HEAD(&clp->cl_lru); | 724 | INIT_LIST_HEAD(&clp->cl_lru); |
443 | return clp; | 725 | return clp; |
444 | } | 726 | } |
@@ -568,25 +850,45 @@ find_unconfirmed_client(clientid_t *clid) | |||
568 | return NULL; | 850 | return NULL; |
569 | } | 851 | } |
570 | 852 | ||
853 | /* | ||
854 | * Return 1 iff clp's clientid establishment method matches the use_exchange_id | ||
855 | * parameter. Matching is based on the fact the at least one of the | ||
856 | * EXCHGID4_FLAG_USE_{NON_PNFS,PNFS_MDS,PNFS_DS} flags must be set for v4.1 | ||
857 | * | ||
858 | * FIXME: we need to unify the clientid namespaces for nfsv4.x | ||
859 | * and correctly deal with client upgrade/downgrade in EXCHANGE_ID | ||
860 | * and SET_CLIENTID{,_CONFIRM} | ||
861 | */ | ||
862 | static inline int | ||
863 | match_clientid_establishment(struct nfs4_client *clp, bool use_exchange_id) | ||
864 | { | ||
865 | bool has_exchange_flags = (clp->cl_exchange_flags != 0); | ||
866 | return use_exchange_id == has_exchange_flags; | ||
867 | } | ||
868 | |||
571 | static struct nfs4_client * | 869 | static struct nfs4_client * |
572 | find_confirmed_client_by_str(const char *dname, unsigned int hashval) | 870 | find_confirmed_client_by_str(const char *dname, unsigned int hashval, |
871 | bool use_exchange_id) | ||
573 | { | 872 | { |
574 | struct nfs4_client *clp; | 873 | struct nfs4_client *clp; |
575 | 874 | ||
576 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { | 875 | list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) { |
577 | if (same_name(clp->cl_recdir, dname)) | 876 | if (same_name(clp->cl_recdir, dname) && |
877 | match_clientid_establishment(clp, use_exchange_id)) | ||
578 | return clp; | 878 | return clp; |
579 | } | 879 | } |
580 | return NULL; | 880 | return NULL; |
581 | } | 881 | } |
582 | 882 | ||
583 | static struct nfs4_client * | 883 | static struct nfs4_client * |
584 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval) | 884 | find_unconfirmed_client_by_str(const char *dname, unsigned int hashval, |
885 | bool use_exchange_id) | ||
585 | { | 886 | { |
586 | struct nfs4_client *clp; | 887 | struct nfs4_client *clp; |
587 | 888 | ||
588 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { | 889 | list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) { |
589 | if (same_name(clp->cl_recdir, dname)) | 890 | if (same_name(clp->cl_recdir, dname) && |
891 | match_clientid_establishment(clp, use_exchange_id)) | ||
590 | return clp; | 892 | return clp; |
591 | } | 893 | } |
592 | return NULL; | 894 | return NULL; |
@@ -685,6 +987,534 @@ out_err: | |||
685 | return; | 987 | return; |
686 | } | 988 | } |
687 | 989 | ||
990 | void | ||
991 | nfsd4_set_statp(struct svc_rqst *rqstp, __be32 *statp) | ||
992 | { | ||
993 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
994 | |||
995 | resp->cstate.statp = statp; | ||
996 | } | ||
997 | |||
998 | /* | ||
999 | * Dereference the result pages. | ||
1000 | */ | ||
1001 | static void | ||
1002 | nfsd4_release_respages(struct page **respages, short resused) | ||
1003 | { | ||
1004 | int i; | ||
1005 | |||
1006 | dprintk("--> %s\n", __func__); | ||
1007 | for (i = 0; i < resused; i++) { | ||
1008 | if (!respages[i]) | ||
1009 | continue; | ||
1010 | put_page(respages[i]); | ||
1011 | respages[i] = NULL; | ||
1012 | } | ||
1013 | } | ||
1014 | |||
1015 | static void | ||
1016 | nfsd4_copy_pages(struct page **topages, struct page **frompages, short count) | ||
1017 | { | ||
1018 | int i; | ||
1019 | |||
1020 | for (i = 0; i < count; i++) { | ||
1021 | topages[i] = frompages[i]; | ||
1022 | if (!topages[i]) | ||
1023 | continue; | ||
1024 | get_page(topages[i]); | ||
1025 | } | ||
1026 | } | ||
1027 | |||
1028 | /* | ||
1029 | * Cache the reply pages up to NFSD_PAGES_PER_SLOT + 1, clearing the previous | ||
1030 | * pages. We add a page to NFSD_PAGES_PER_SLOT for the case where the total | ||
1031 | * length of the XDR response is less than se_fmaxresp_cached | ||
1032 | * (NFSD_PAGES_PER_SLOT * PAGE_SIZE) but the xdr_buf pages is used for a | ||
1033 | * of the reply (e.g. readdir). | ||
1034 | * | ||
1035 | * Store the base and length of the rq_req.head[0] page | ||
1036 | * of the NFSv4.1 data, just past the rpc header. | ||
1037 | */ | ||
1038 | void | ||
1039 | nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) | ||
1040 | { | ||
1041 | struct nfsd4_cache_entry *entry = &resp->cstate.slot->sl_cache_entry; | ||
1042 | struct svc_rqst *rqstp = resp->rqstp; | ||
1043 | struct nfsd4_compoundargs *args = rqstp->rq_argp; | ||
1044 | struct nfsd4_op *op = &args->ops[resp->opcnt]; | ||
1045 | struct kvec *resv = &rqstp->rq_res.head[0]; | ||
1046 | |||
1047 | dprintk("--> %s entry %p\n", __func__, entry); | ||
1048 | |||
1049 | /* Don't cache a failed OP_SEQUENCE. */ | ||
1050 | if (resp->opcnt == 1 && op->opnum == OP_SEQUENCE && resp->cstate.status) | ||
1051 | return; | ||
1052 | |||
1053 | nfsd4_release_respages(entry->ce_respages, entry->ce_resused); | ||
1054 | entry->ce_opcnt = resp->opcnt; | ||
1055 | entry->ce_status = resp->cstate.status; | ||
1056 | |||
1057 | /* | ||
1058 | * Don't need a page to cache just the sequence operation - the slot | ||
1059 | * does this for us! | ||
1060 | */ | ||
1061 | |||
1062 | if (nfsd4_not_cached(resp)) { | ||
1063 | entry->ce_resused = 0; | ||
1064 | entry->ce_rpchdrlen = 0; | ||
1065 | dprintk("%s Just cache SEQUENCE. ce_cachethis %d\n", __func__, | ||
1066 | resp->cstate.slot->sl_cache_entry.ce_cachethis); | ||
1067 | return; | ||
1068 | } | ||
1069 | entry->ce_resused = rqstp->rq_resused; | ||
1070 | if (entry->ce_resused > NFSD_PAGES_PER_SLOT + 1) | ||
1071 | entry->ce_resused = NFSD_PAGES_PER_SLOT + 1; | ||
1072 | nfsd4_copy_pages(entry->ce_respages, rqstp->rq_respages, | ||
1073 | entry->ce_resused); | ||
1074 | entry->ce_datav.iov_base = resp->cstate.statp; | ||
1075 | entry->ce_datav.iov_len = resv->iov_len - ((char *)resp->cstate.statp - | ||
1076 | (char *)page_address(rqstp->rq_respages[0])); | ||
1077 | /* Current request rpc header length*/ | ||
1078 | entry->ce_rpchdrlen = (char *)resp->cstate.statp - | ||
1079 | (char *)page_address(rqstp->rq_respages[0]); | ||
1080 | } | ||
1081 | |||
1082 | /* | ||
1083 | * We keep the rpc header, but take the nfs reply from the replycache. | ||
1084 | */ | ||
1085 | static int | ||
1086 | nfsd41_copy_replay_data(struct nfsd4_compoundres *resp, | ||
1087 | struct nfsd4_cache_entry *entry) | ||
1088 | { | ||
1089 | struct svc_rqst *rqstp = resp->rqstp; | ||
1090 | struct kvec *resv = &resp->rqstp->rq_res.head[0]; | ||
1091 | int len; | ||
1092 | |||
1093 | /* Current request rpc header length*/ | ||
1094 | len = (char *)resp->cstate.statp - | ||
1095 | (char *)page_address(rqstp->rq_respages[0]); | ||
1096 | if (entry->ce_datav.iov_len + len > PAGE_SIZE) { | ||
1097 | dprintk("%s v41 cached reply too large (%Zd).\n", __func__, | ||
1098 | entry->ce_datav.iov_len); | ||
1099 | return 0; | ||
1100 | } | ||
1101 | /* copy the cached reply nfsd data past the current rpc header */ | ||
1102 | memcpy((char *)resv->iov_base + len, entry->ce_datav.iov_base, | ||
1103 | entry->ce_datav.iov_len); | ||
1104 | resv->iov_len = len + entry->ce_datav.iov_len; | ||
1105 | return 1; | ||
1106 | } | ||
1107 | |||
1108 | /* | ||
1109 | * Keep the first page of the replay. Copy the NFSv4.1 data from the first | ||
1110 | * cached page. Replace any futher replay pages from the cache. | ||
1111 | */ | ||
1112 | __be32 | ||
1113 | nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, | ||
1114 | struct nfsd4_sequence *seq) | ||
1115 | { | ||
1116 | struct nfsd4_cache_entry *entry = &resp->cstate.slot->sl_cache_entry; | ||
1117 | __be32 status; | ||
1118 | |||
1119 | dprintk("--> %s entry %p\n", __func__, entry); | ||
1120 | |||
1121 | /* | ||
1122 | * If this is just the sequence operation, we did not keep | ||
1123 | * a page in the cache entry because we can just use the | ||
1124 | * slot info stored in struct nfsd4_sequence that was checked | ||
1125 | * against the slot in nfsd4_sequence(). | ||
1126 | * | ||
1127 | * This occurs when seq->cachethis is FALSE, or when the client | ||
1128 | * session inactivity timer fires and a solo sequence operation | ||
1129 | * is sent (lease renewal). | ||
1130 | */ | ||
1131 | if (seq && nfsd4_not_cached(resp)) { | ||
1132 | seq->maxslots = resp->cstate.session->se_fnumslots; | ||
1133 | return nfs_ok; | ||
1134 | } | ||
1135 | |||
1136 | if (!nfsd41_copy_replay_data(resp, entry)) { | ||
1137 | /* | ||
1138 | * Not enough room to use the replay rpc header, send the | ||
1139 | * cached header. Release all the allocated result pages. | ||
1140 | */ | ||
1141 | svc_free_res_pages(resp->rqstp); | ||
1142 | nfsd4_copy_pages(resp->rqstp->rq_respages, entry->ce_respages, | ||
1143 | entry->ce_resused); | ||
1144 | } else { | ||
1145 | /* Release all but the first allocated result page */ | ||
1146 | |||
1147 | resp->rqstp->rq_resused--; | ||
1148 | svc_free_res_pages(resp->rqstp); | ||
1149 | |||
1150 | nfsd4_copy_pages(&resp->rqstp->rq_respages[1], | ||
1151 | &entry->ce_respages[1], | ||
1152 | entry->ce_resused - 1); | ||
1153 | } | ||
1154 | |||
1155 | resp->rqstp->rq_resused = entry->ce_resused; | ||
1156 | resp->opcnt = entry->ce_opcnt; | ||
1157 | resp->cstate.iovlen = entry->ce_datav.iov_len + entry->ce_rpchdrlen; | ||
1158 | status = entry->ce_status; | ||
1159 | |||
1160 | return status; | ||
1161 | } | ||
1162 | |||
1163 | /* | ||
1164 | * Set the exchange_id flags returned by the server. | ||
1165 | */ | ||
1166 | static void | ||
1167 | nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid) | ||
1168 | { | ||
1169 | /* pNFS is not supported */ | ||
1170 | new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS; | ||
1171 | |||
1172 | /* Referrals are supported, Migration is not. */ | ||
1173 | new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER; | ||
1174 | |||
1175 | /* set the wire flags to return to client. */ | ||
1176 | clid->flags = new->cl_exchange_flags; | ||
1177 | } | ||
1178 | |||
1179 | __be32 | ||
1180 | nfsd4_exchange_id(struct svc_rqst *rqstp, | ||
1181 | struct nfsd4_compound_state *cstate, | ||
1182 | struct nfsd4_exchange_id *exid) | ||
1183 | { | ||
1184 | struct nfs4_client *unconf, *conf, *new; | ||
1185 | int status; | ||
1186 | unsigned int strhashval; | ||
1187 | char dname[HEXDIR_LEN]; | ||
1188 | nfs4_verifier verf = exid->verifier; | ||
1189 | u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr; | ||
1190 | |||
1191 | dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " | ||
1192 | " ip_addr=%u flags %x, spa_how %d\n", | ||
1193 | __func__, rqstp, exid, exid->clname.len, exid->clname.data, | ||
1194 | ip_addr, exid->flags, exid->spa_how); | ||
1195 | |||
1196 | if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A)) | ||
1197 | return nfserr_inval; | ||
1198 | |||
1199 | /* Currently only support SP4_NONE */ | ||
1200 | switch (exid->spa_how) { | ||
1201 | case SP4_NONE: | ||
1202 | break; | ||
1203 | case SP4_SSV: | ||
1204 | return nfserr_encr_alg_unsupp; | ||
1205 | default: | ||
1206 | BUG(); /* checked by xdr code */ | ||
1207 | case SP4_MACH_CRED: | ||
1208 | return nfserr_serverfault; /* no excuse :-/ */ | ||
1209 | } | ||
1210 | |||
1211 | status = nfs4_make_rec_clidname(dname, &exid->clname); | ||
1212 | |||
1213 | if (status) | ||
1214 | goto error; | ||
1215 | |||
1216 | strhashval = clientstr_hashval(dname); | ||
1217 | |||
1218 | nfs4_lock_state(); | ||
1219 | status = nfs_ok; | ||
1220 | |||
1221 | conf = find_confirmed_client_by_str(dname, strhashval, true); | ||
1222 | if (conf) { | ||
1223 | if (!same_verf(&verf, &conf->cl_verifier)) { | ||
1224 | /* 18.35.4 case 8 */ | ||
1225 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
1226 | status = nfserr_not_same; | ||
1227 | goto out; | ||
1228 | } | ||
1229 | /* Client reboot: destroy old state */ | ||
1230 | expire_client(conf); | ||
1231 | goto out_new; | ||
1232 | } | ||
1233 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { | ||
1234 | /* 18.35.4 case 9 */ | ||
1235 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
1236 | status = nfserr_perm; | ||
1237 | goto out; | ||
1238 | } | ||
1239 | expire_client(conf); | ||
1240 | goto out_new; | ||
1241 | } | ||
1242 | if (ip_addr != conf->cl_addr && | ||
1243 | !(exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A)) { | ||
1244 | /* Client collision. 18.35.4 case 3 */ | ||
1245 | status = nfserr_clid_inuse; | ||
1246 | goto out; | ||
1247 | } | ||
1248 | /* | ||
1249 | * Set bit when the owner id and verifier map to an already | ||
1250 | * confirmed client id (18.35.3). | ||
1251 | */ | ||
1252 | exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; | ||
1253 | |||
1254 | /* | ||
1255 | * Falling into 18.35.4 case 2, possible router replay. | ||
1256 | * Leave confirmed record intact and return same result. | ||
1257 | */ | ||
1258 | copy_verf(conf, &verf); | ||
1259 | new = conf; | ||
1260 | goto out_copy; | ||
1261 | } else { | ||
1262 | /* 18.35.4 case 7 */ | ||
1263 | if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) { | ||
1264 | status = nfserr_noent; | ||
1265 | goto out; | ||
1266 | } | ||
1267 | } | ||
1268 | |||
1269 | unconf = find_unconfirmed_client_by_str(dname, strhashval, true); | ||
1270 | if (unconf) { | ||
1271 | /* | ||
1272 | * Possible retry or client restart. Per 18.35.4 case 4, | ||
1273 | * a new unconfirmed record should be generated regardless | ||
1274 | * of whether any properties have changed. | ||
1275 | */ | ||
1276 | expire_client(unconf); | ||
1277 | } | ||
1278 | |||
1279 | out_new: | ||
1280 | /* Normal case */ | ||
1281 | new = create_client(exid->clname, dname); | ||
1282 | if (new == NULL) { | ||
1283 | status = nfserr_resource; | ||
1284 | goto out; | ||
1285 | } | ||
1286 | |||
1287 | copy_verf(new, &verf); | ||
1288 | copy_cred(&new->cl_cred, &rqstp->rq_cred); | ||
1289 | new->cl_addr = ip_addr; | ||
1290 | gen_clid(new); | ||
1291 | gen_confirm(new); | ||
1292 | add_to_unconfirmed(new, strhashval); | ||
1293 | out_copy: | ||
1294 | exid->clientid.cl_boot = new->cl_clientid.cl_boot; | ||
1295 | exid->clientid.cl_id = new->cl_clientid.cl_id; | ||
1296 | |||
1297 | new->cl_slot.sl_seqid = 0; | ||
1298 | exid->seqid = 1; | ||
1299 | nfsd4_set_ex_flags(new, exid); | ||
1300 | |||
1301 | dprintk("nfsd4_exchange_id seqid %d flags %x\n", | ||
1302 | new->cl_slot.sl_seqid, new->cl_exchange_flags); | ||
1303 | status = nfs_ok; | ||
1304 | |||
1305 | out: | ||
1306 | nfs4_unlock_state(); | ||
1307 | error: | ||
1308 | dprintk("nfsd4_exchange_id returns %d\n", ntohl(status)); | ||
1309 | return status; | ||
1310 | } | ||
1311 | |||
1312 | static int | ||
1313 | check_slot_seqid(u32 seqid, struct nfsd4_slot *slot) | ||
1314 | { | ||
1315 | dprintk("%s enter. seqid %d slot->sl_seqid %d\n", __func__, seqid, | ||
1316 | slot->sl_seqid); | ||
1317 | |||
1318 | /* The slot is in use, and no response has been sent. */ | ||
1319 | if (slot->sl_inuse) { | ||
1320 | if (seqid == slot->sl_seqid) | ||
1321 | return nfserr_jukebox; | ||
1322 | else | ||
1323 | return nfserr_seq_misordered; | ||
1324 | } | ||
1325 | /* Normal */ | ||
1326 | if (likely(seqid == slot->sl_seqid + 1)) | ||
1327 | return nfs_ok; | ||
1328 | /* Replay */ | ||
1329 | if (seqid == slot->sl_seqid) | ||
1330 | return nfserr_replay_cache; | ||
1331 | /* Wraparound */ | ||
1332 | if (seqid == 1 && (slot->sl_seqid + 1) == 0) | ||
1333 | return nfs_ok; | ||
1334 | /* Misordered replay or misordered new request */ | ||
1335 | return nfserr_seq_misordered; | ||
1336 | } | ||
1337 | |||
1338 | __be32 | ||
1339 | nfsd4_create_session(struct svc_rqst *rqstp, | ||
1340 | struct nfsd4_compound_state *cstate, | ||
1341 | struct nfsd4_create_session *cr_ses) | ||
1342 | { | ||
1343 | u32 ip_addr = svc_addr_in(rqstp)->sin_addr.s_addr; | ||
1344 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1345 | struct nfs4_client *conf, *unconf; | ||
1346 | struct nfsd4_slot *slot = NULL; | ||
1347 | int status = 0; | ||
1348 | |||
1349 | nfs4_lock_state(); | ||
1350 | unconf = find_unconfirmed_client(&cr_ses->clientid); | ||
1351 | conf = find_confirmed_client(&cr_ses->clientid); | ||
1352 | |||
1353 | if (conf) { | ||
1354 | slot = &conf->cl_slot; | ||
1355 | status = check_slot_seqid(cr_ses->seqid, slot); | ||
1356 | if (status == nfserr_replay_cache) { | ||
1357 | dprintk("Got a create_session replay! seqid= %d\n", | ||
1358 | slot->sl_seqid); | ||
1359 | cstate->slot = slot; | ||
1360 | cstate->status = status; | ||
1361 | /* Return the cached reply status */ | ||
1362 | status = nfsd4_replay_cache_entry(resp, NULL); | ||
1363 | goto out; | ||
1364 | } else if (cr_ses->seqid != conf->cl_slot.sl_seqid + 1) { | ||
1365 | status = nfserr_seq_misordered; | ||
1366 | dprintk("Sequence misordered!\n"); | ||
1367 | dprintk("Expected seqid= %d but got seqid= %d\n", | ||
1368 | slot->sl_seqid, cr_ses->seqid); | ||
1369 | goto out; | ||
1370 | } | ||
1371 | conf->cl_slot.sl_seqid++; | ||
1372 | } else if (unconf) { | ||
1373 | if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || | ||
1374 | (ip_addr != unconf->cl_addr)) { | ||
1375 | status = nfserr_clid_inuse; | ||
1376 | goto out; | ||
1377 | } | ||
1378 | |||
1379 | slot = &unconf->cl_slot; | ||
1380 | status = check_slot_seqid(cr_ses->seqid, slot); | ||
1381 | if (status) { | ||
1382 | /* an unconfirmed replay returns misordered */ | ||
1383 | status = nfserr_seq_misordered; | ||
1384 | goto out; | ||
1385 | } | ||
1386 | |||
1387 | slot->sl_seqid++; /* from 0 to 1 */ | ||
1388 | move_to_confirmed(unconf); | ||
1389 | |||
1390 | /* | ||
1391 | * We do not support RDMA or persistent sessions | ||
1392 | */ | ||
1393 | cr_ses->flags &= ~SESSION4_PERSIST; | ||
1394 | cr_ses->flags &= ~SESSION4_RDMA; | ||
1395 | |||
1396 | conf = unconf; | ||
1397 | } else { | ||
1398 | status = nfserr_stale_clientid; | ||
1399 | goto out; | ||
1400 | } | ||
1401 | |||
1402 | status = alloc_init_session(rqstp, conf, cr_ses); | ||
1403 | if (status) | ||
1404 | goto out; | ||
1405 | |||
1406 | memcpy(cr_ses->sessionid.data, conf->cl_sessionid.data, | ||
1407 | NFS4_MAX_SESSIONID_LEN); | ||
1408 | cr_ses->seqid = slot->sl_seqid; | ||
1409 | |||
1410 | slot->sl_inuse = true; | ||
1411 | cstate->slot = slot; | ||
1412 | /* Ensure a page is used for the cache */ | ||
1413 | slot->sl_cache_entry.ce_cachethis = 1; | ||
1414 | out: | ||
1415 | nfs4_unlock_state(); | ||
1416 | dprintk("%s returns %d\n", __func__, ntohl(status)); | ||
1417 | return status; | ||
1418 | } | ||
1419 | |||
1420 | __be32 | ||
1421 | nfsd4_destroy_session(struct svc_rqst *r, | ||
1422 | struct nfsd4_compound_state *cstate, | ||
1423 | struct nfsd4_destroy_session *sessionid) | ||
1424 | { | ||
1425 | struct nfsd4_session *ses; | ||
1426 | u32 status = nfserr_badsession; | ||
1427 | |||
1428 | /* Notes: | ||
1429 | * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid | ||
1430 | * - Should we return nfserr_back_chan_busy if waiting for | ||
1431 | * callbacks on to-be-destroyed session? | ||
1432 | * - Do we need to clear any callback info from previous session? | ||
1433 | */ | ||
1434 | |||
1435 | dump_sessionid(__func__, &sessionid->sessionid); | ||
1436 | spin_lock(&sessionid_lock); | ||
1437 | ses = find_in_sessionid_hashtbl(&sessionid->sessionid); | ||
1438 | if (!ses) { | ||
1439 | spin_unlock(&sessionid_lock); | ||
1440 | goto out; | ||
1441 | } | ||
1442 | |||
1443 | unhash_session(ses); | ||
1444 | spin_unlock(&sessionid_lock); | ||
1445 | |||
1446 | /* wait for callbacks */ | ||
1447 | shutdown_callback_client(ses->se_client); | ||
1448 | nfsd4_put_session(ses); | ||
1449 | status = nfs_ok; | ||
1450 | out: | ||
1451 | dprintk("%s returns %d\n", __func__, ntohl(status)); | ||
1452 | return status; | ||
1453 | } | ||
1454 | |||
1455 | __be32 | ||
1456 | nfsd4_sequence(struct svc_rqst *rqstp, | ||
1457 | struct nfsd4_compound_state *cstate, | ||
1458 | struct nfsd4_sequence *seq) | ||
1459 | { | ||
1460 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1461 | struct nfsd4_session *session; | ||
1462 | struct nfsd4_slot *slot; | ||
1463 | int status; | ||
1464 | |||
1465 | if (resp->opcnt != 1) | ||
1466 | return nfserr_sequence_pos; | ||
1467 | |||
1468 | spin_lock(&sessionid_lock); | ||
1469 | status = nfserr_badsession; | ||
1470 | session = find_in_sessionid_hashtbl(&seq->sessionid); | ||
1471 | if (!session) | ||
1472 | goto out; | ||
1473 | |||
1474 | status = nfserr_badslot; | ||
1475 | if (seq->slotid >= session->se_fnumslots) | ||
1476 | goto out; | ||
1477 | |||
1478 | slot = &session->se_slots[seq->slotid]; | ||
1479 | dprintk("%s: slotid %d\n", __func__, seq->slotid); | ||
1480 | |||
1481 | status = check_slot_seqid(seq->seqid, slot); | ||
1482 | if (status == nfserr_replay_cache) { | ||
1483 | cstate->slot = slot; | ||
1484 | cstate->session = session; | ||
1485 | /* Return the cached reply status and set cstate->status | ||
1486 | * for nfsd4_svc_encode_compoundres processing */ | ||
1487 | status = nfsd4_replay_cache_entry(resp, seq); | ||
1488 | cstate->status = nfserr_replay_cache; | ||
1489 | goto replay_cache; | ||
1490 | } | ||
1491 | if (status) | ||
1492 | goto out; | ||
1493 | |||
1494 | /* Success! bump slot seqid */ | ||
1495 | slot->sl_inuse = true; | ||
1496 | slot->sl_seqid = seq->seqid; | ||
1497 | slot->sl_cache_entry.ce_cachethis = seq->cachethis; | ||
1498 | /* Always set the cache entry cachethis for solo sequence */ | ||
1499 | if (nfsd4_is_solo_sequence(resp)) | ||
1500 | slot->sl_cache_entry.ce_cachethis = 1; | ||
1501 | |||
1502 | cstate->slot = slot; | ||
1503 | cstate->session = session; | ||
1504 | |||
1505 | replay_cache: | ||
1506 | /* Renew the clientid on success and on replay. | ||
1507 | * Hold a session reference until done processing the compound: | ||
1508 | * nfsd4_put_session called only if the cstate slot is set. | ||
1509 | */ | ||
1510 | renew_client(session->se_client); | ||
1511 | nfsd4_get_session(session); | ||
1512 | out: | ||
1513 | spin_unlock(&sessionid_lock); | ||
1514 | dprintk("%s: return %d\n", __func__, ntohl(status)); | ||
1515 | return status; | ||
1516 | } | ||
1517 | |||
688 | __be32 | 1518 | __be32 |
689 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 1519 | nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
690 | struct nfsd4_setclientid *setclid) | 1520 | struct nfsd4_setclientid *setclid) |
@@ -716,14 +1546,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
716 | strhashval = clientstr_hashval(dname); | 1546 | strhashval = clientstr_hashval(dname); |
717 | 1547 | ||
718 | nfs4_lock_state(); | 1548 | nfs4_lock_state(); |
719 | conf = find_confirmed_client_by_str(dname, strhashval); | 1549 | conf = find_confirmed_client_by_str(dname, strhashval, false); |
720 | if (conf) { | 1550 | if (conf) { |
721 | /* RFC 3530 14.2.33 CASE 0: */ | 1551 | /* RFC 3530 14.2.33 CASE 0: */ |
722 | status = nfserr_clid_inuse; | 1552 | status = nfserr_clid_inuse; |
723 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred) | 1553 | if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { |
724 | || conf->cl_addr != sin->sin_addr.s_addr) { | 1554 | dprintk("NFSD: setclientid: string in use by client" |
725 | dprintk("NFSD: setclientid: string in use by clientat %pI4\n", | 1555 | " at %pI4\n", &conf->cl_addr); |
726 | &conf->cl_addr); | ||
727 | goto out; | 1556 | goto out; |
728 | } | 1557 | } |
729 | } | 1558 | } |
@@ -732,7 +1561,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
732 | * has a description of SETCLIENTID request processing consisting | 1561 | * has a description of SETCLIENTID request processing consisting |
733 | * of 5 bullet points, labeled as CASE0 - CASE4 below. | 1562 | * of 5 bullet points, labeled as CASE0 - CASE4 below. |
734 | */ | 1563 | */ |
735 | unconf = find_unconfirmed_client_by_str(dname, strhashval); | 1564 | unconf = find_unconfirmed_client_by_str(dname, strhashval, false); |
736 | status = nfserr_resource; | 1565 | status = nfserr_resource; |
737 | if (!conf) { | 1566 | if (!conf) { |
738 | /* | 1567 | /* |
@@ -887,7 +1716,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, | |||
887 | unsigned int hash = | 1716 | unsigned int hash = |
888 | clientstr_hashval(unconf->cl_recdir); | 1717 | clientstr_hashval(unconf->cl_recdir); |
889 | conf = find_confirmed_client_by_str(unconf->cl_recdir, | 1718 | conf = find_confirmed_client_by_str(unconf->cl_recdir, |
890 | hash); | 1719 | hash, false); |
891 | if (conf) { | 1720 | if (conf) { |
892 | nfsd4_remove_clid_dir(conf); | 1721 | nfsd4_remove_clid_dir(conf); |
893 | expire_client(conf); | 1722 | expire_client(conf); |
@@ -923,11 +1752,13 @@ alloc_init_file(struct inode *ino) | |||
923 | 1752 | ||
924 | fp = kmem_cache_alloc(file_slab, GFP_KERNEL); | 1753 | fp = kmem_cache_alloc(file_slab, GFP_KERNEL); |
925 | if (fp) { | 1754 | if (fp) { |
926 | kref_init(&fp->fi_ref); | 1755 | atomic_set(&fp->fi_ref, 1); |
927 | INIT_LIST_HEAD(&fp->fi_hash); | 1756 | INIT_LIST_HEAD(&fp->fi_hash); |
928 | INIT_LIST_HEAD(&fp->fi_stateids); | 1757 | INIT_LIST_HEAD(&fp->fi_stateids); |
929 | INIT_LIST_HEAD(&fp->fi_delegations); | 1758 | INIT_LIST_HEAD(&fp->fi_delegations); |
1759 | spin_lock(&recall_lock); | ||
930 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); | 1760 | list_add(&fp->fi_hash, &file_hashtbl[hashval]); |
1761 | spin_unlock(&recall_lock); | ||
931 | fp->fi_inode = igrab(ino); | 1762 | fp->fi_inode = igrab(ino); |
932 | fp->fi_id = current_fileid++; | 1763 | fp->fi_id = current_fileid++; |
933 | fp->fi_had_conflict = false; | 1764 | fp->fi_had_conflict = false; |
@@ -1037,48 +1868,6 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
1037 | return sop; | 1868 | return sop; |
1038 | } | 1869 | } |
1039 | 1870 | ||
1040 | static void | ||
1041 | release_stateid_lockowners(struct nfs4_stateid *open_stp) | ||
1042 | { | ||
1043 | struct nfs4_stateowner *lock_sop; | ||
1044 | |||
1045 | while (!list_empty(&open_stp->st_lockowners)) { | ||
1046 | lock_sop = list_entry(open_stp->st_lockowners.next, | ||
1047 | struct nfs4_stateowner, so_perstateid); | ||
1048 | /* list_del(&open_stp->st_lockowners); */ | ||
1049 | BUG_ON(lock_sop->so_is_open_owner); | ||
1050 | release_stateowner(lock_sop); | ||
1051 | } | ||
1052 | } | ||
1053 | |||
1054 | static void | ||
1055 | unhash_stateowner(struct nfs4_stateowner *sop) | ||
1056 | { | ||
1057 | struct nfs4_stateid *stp; | ||
1058 | |||
1059 | list_del(&sop->so_idhash); | ||
1060 | list_del(&sop->so_strhash); | ||
1061 | if (sop->so_is_open_owner) | ||
1062 | list_del(&sop->so_perclient); | ||
1063 | list_del(&sop->so_perstateid); | ||
1064 | while (!list_empty(&sop->so_stateids)) { | ||
1065 | stp = list_entry(sop->so_stateids.next, | ||
1066 | struct nfs4_stateid, st_perstateowner); | ||
1067 | if (sop->so_is_open_owner) | ||
1068 | release_stateid(stp, OPEN_STATE); | ||
1069 | else | ||
1070 | release_stateid(stp, LOCK_STATE); | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | static void | ||
1075 | release_stateowner(struct nfs4_stateowner *sop) | ||
1076 | { | ||
1077 | unhash_stateowner(sop); | ||
1078 | list_del(&sop->so_close_lru); | ||
1079 | nfs4_put_stateowner(sop); | ||
1080 | } | ||
1081 | |||
1082 | static inline void | 1871 | static inline void |
1083 | init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { | 1872 | init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) { |
1084 | struct nfs4_stateowner *sop = open->op_stateowner; | 1873 | struct nfs4_stateowner *sop = open->op_stateowner; |
@@ -1100,30 +1889,13 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open * | |||
1100 | stp->st_stateid.si_generation = 0; | 1889 | stp->st_stateid.si_generation = 0; |
1101 | stp->st_access_bmap = 0; | 1890 | stp->st_access_bmap = 0; |
1102 | stp->st_deny_bmap = 0; | 1891 | stp->st_deny_bmap = 0; |
1103 | __set_bit(open->op_share_access, &stp->st_access_bmap); | 1892 | __set_bit(open->op_share_access & ~NFS4_SHARE_WANT_MASK, |
1893 | &stp->st_access_bmap); | ||
1104 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); | 1894 | __set_bit(open->op_share_deny, &stp->st_deny_bmap); |
1105 | stp->st_openstp = NULL; | 1895 | stp->st_openstp = NULL; |
1106 | } | 1896 | } |
1107 | 1897 | ||
1108 | static void | 1898 | static void |
1109 | release_stateid(struct nfs4_stateid *stp, int flags) | ||
1110 | { | ||
1111 | struct file *filp = stp->st_vfs_file; | ||
1112 | |||
1113 | list_del(&stp->st_hash); | ||
1114 | list_del(&stp->st_perfile); | ||
1115 | list_del(&stp->st_perstateowner); | ||
1116 | if (flags & OPEN_STATE) { | ||
1117 | release_stateid_lockowners(stp); | ||
1118 | stp->st_vfs_file = NULL; | ||
1119 | nfsd_close(filp); | ||
1120 | } else if (flags & LOCK_STATE) | ||
1121 | locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner); | ||
1122 | put_nfs4_file(stp->st_file); | ||
1123 | kmem_cache_free(stateid_slab, stp); | ||
1124 | } | ||
1125 | |||
1126 | static void | ||
1127 | move_to_close_lru(struct nfs4_stateowner *sop) | 1899 | move_to_close_lru(struct nfs4_stateowner *sop) |
1128 | { | 1900 | { |
1129 | dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); | 1901 | dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop); |
@@ -1160,20 +1932,33 @@ find_file(struct inode *ino) | |||
1160 | unsigned int hashval = file_hashval(ino); | 1932 | unsigned int hashval = file_hashval(ino); |
1161 | struct nfs4_file *fp; | 1933 | struct nfs4_file *fp; |
1162 | 1934 | ||
1935 | spin_lock(&recall_lock); | ||
1163 | list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { | 1936 | list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) { |
1164 | if (fp->fi_inode == ino) { | 1937 | if (fp->fi_inode == ino) { |
1165 | get_nfs4_file(fp); | 1938 | get_nfs4_file(fp); |
1939 | spin_unlock(&recall_lock); | ||
1166 | return fp; | 1940 | return fp; |
1167 | } | 1941 | } |
1168 | } | 1942 | } |
1943 | spin_unlock(&recall_lock); | ||
1169 | return NULL; | 1944 | return NULL; |
1170 | } | 1945 | } |
1171 | 1946 | ||
1172 | static inline int access_valid(u32 x) | 1947 | static inline int access_valid(u32 x, u32 minorversion) |
1173 | { | 1948 | { |
1174 | if (x < NFS4_SHARE_ACCESS_READ) | 1949 | if ((x & NFS4_SHARE_ACCESS_MASK) < NFS4_SHARE_ACCESS_READ) |
1175 | return 0; | 1950 | return 0; |
1176 | if (x > NFS4_SHARE_ACCESS_BOTH) | 1951 | if ((x & NFS4_SHARE_ACCESS_MASK) > NFS4_SHARE_ACCESS_BOTH) |
1952 | return 0; | ||
1953 | x &= ~NFS4_SHARE_ACCESS_MASK; | ||
1954 | if (minorversion && x) { | ||
1955 | if ((x & NFS4_SHARE_WANT_MASK) > NFS4_SHARE_WANT_CANCEL) | ||
1956 | return 0; | ||
1957 | if ((x & NFS4_SHARE_WHEN_MASK) > NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED) | ||
1958 | return 0; | ||
1959 | x &= ~(NFS4_SHARE_WANT_MASK | NFS4_SHARE_WHEN_MASK); | ||
1960 | } | ||
1961 | if (x) | ||
1177 | return 0; | 1962 | return 0; |
1178 | return 1; | 1963 | return 1; |
1179 | } | 1964 | } |
@@ -1409,7 +2194,8 @@ static struct lock_manager_operations nfsd_lease_mng_ops = { | |||
1409 | 2194 | ||
1410 | 2195 | ||
1411 | __be32 | 2196 | __be32 |
1412 | nfsd4_process_open1(struct nfsd4_open *open) | 2197 | nfsd4_process_open1(struct nfsd4_compound_state *cstate, |
2198 | struct nfsd4_open *open) | ||
1413 | { | 2199 | { |
1414 | clientid_t *clientid = &open->op_clientid; | 2200 | clientid_t *clientid = &open->op_clientid; |
1415 | struct nfs4_client *clp = NULL; | 2201 | struct nfs4_client *clp = NULL; |
@@ -1432,10 +2218,13 @@ nfsd4_process_open1(struct nfsd4_open *open) | |||
1432 | return nfserr_expired; | 2218 | return nfserr_expired; |
1433 | goto renew; | 2219 | goto renew; |
1434 | } | 2220 | } |
2221 | /* When sessions are used, skip open sequenceid processing */ | ||
2222 | if (nfsd4_has_session(cstate)) | ||
2223 | goto renew; | ||
1435 | if (!sop->so_confirmed) { | 2224 | if (!sop->so_confirmed) { |
1436 | /* Replace unconfirmed owners without checking for replay. */ | 2225 | /* Replace unconfirmed owners without checking for replay. */ |
1437 | clp = sop->so_client; | 2226 | clp = sop->so_client; |
1438 | release_stateowner(sop); | 2227 | release_openowner(sop); |
1439 | open->op_stateowner = NULL; | 2228 | open->op_stateowner = NULL; |
1440 | goto renew; | 2229 | goto renew; |
1441 | } | 2230 | } |
@@ -1709,6 +2498,7 @@ out: | |||
1709 | __be32 | 2498 | __be32 |
1710 | nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) | 2499 | nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) |
1711 | { | 2500 | { |
2501 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | ||
1712 | struct nfs4_file *fp = NULL; | 2502 | struct nfs4_file *fp = NULL; |
1713 | struct inode *ino = current_fh->fh_dentry->d_inode; | 2503 | struct inode *ino = current_fh->fh_dentry->d_inode; |
1714 | struct nfs4_stateid *stp = NULL; | 2504 | struct nfs4_stateid *stp = NULL; |
@@ -1716,7 +2506,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1716 | __be32 status; | 2506 | __be32 status; |
1717 | 2507 | ||
1718 | status = nfserr_inval; | 2508 | status = nfserr_inval; |
1719 | if (!access_valid(open->op_share_access) | 2509 | if (!access_valid(open->op_share_access, resp->cstate.minorversion) |
1720 | || !deny_valid(open->op_share_deny)) | 2510 | || !deny_valid(open->op_share_deny)) |
1721 | goto out; | 2511 | goto out; |
1722 | /* | 2512 | /* |
@@ -1764,12 +2554,17 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf | |||
1764 | init_stateid(stp, fp, open); | 2554 | init_stateid(stp, fp, open); |
1765 | status = nfsd4_truncate(rqstp, current_fh, open); | 2555 | status = nfsd4_truncate(rqstp, current_fh, open); |
1766 | if (status) { | 2556 | if (status) { |
1767 | release_stateid(stp, OPEN_STATE); | 2557 | release_open_stateid(stp); |
1768 | goto out; | 2558 | goto out; |
1769 | } | 2559 | } |
2560 | if (nfsd4_has_session(&resp->cstate)) | ||
2561 | update_stateid(&stp->st_stateid); | ||
1770 | } | 2562 | } |
1771 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); | 2563 | memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t)); |
1772 | 2564 | ||
2565 | if (nfsd4_has_session(&resp->cstate)) | ||
2566 | open->op_stateowner->so_confirmed = 1; | ||
2567 | |||
1773 | /* | 2568 | /* |
1774 | * Attempt to hand out a delegation. No error return, because the | 2569 | * Attempt to hand out a delegation. No error return, because the |
1775 | * OPEN succeeds even if we fail. | 2570 | * OPEN succeeds even if we fail. |
@@ -1790,7 +2585,8 @@ out: | |||
1790 | * To finish the open response, we just need to set the rflags. | 2585 | * To finish the open response, we just need to set the rflags. |
1791 | */ | 2586 | */ |
1792 | open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; | 2587 | open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX; |
1793 | if (!open->op_stateowner->so_confirmed) | 2588 | if (!open->op_stateowner->so_confirmed && |
2589 | !nfsd4_has_session(&resp->cstate)) | ||
1794 | open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; | 2590 | open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM; |
1795 | 2591 | ||
1796 | return status; | 2592 | return status; |
@@ -1898,7 +2694,7 @@ nfs4_laundromat(void) | |||
1898 | } | 2694 | } |
1899 | dprintk("NFSD: purging unused open stateowner (so_id %d)\n", | 2695 | dprintk("NFSD: purging unused open stateowner (so_id %d)\n", |
1900 | sop->so_id); | 2696 | sop->so_id); |
1901 | release_stateowner(sop); | 2697 | release_openowner(sop); |
1902 | } | 2698 | } |
1903 | if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) | 2699 | if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT) |
1904 | clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; | 2700 | clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT; |
@@ -1983,10 +2779,7 @@ out: | |||
1983 | static inline __be32 | 2779 | static inline __be32 |
1984 | check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) | 2780 | check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) |
1985 | { | 2781 | { |
1986 | /* Trying to call delegreturn with a special stateid? Yuch: */ | 2782 | if (ONE_STATEID(stateid) && (flags & RD_STATE)) |
1987 | if (!(flags & (RD_STATE | WR_STATE))) | ||
1988 | return nfserr_bad_stateid; | ||
1989 | else if (ONE_STATEID(stateid) && (flags & RD_STATE)) | ||
1990 | return nfs_ok; | 2783 | return nfs_ok; |
1991 | else if (locks_in_grace()) { | 2784 | else if (locks_in_grace()) { |
1992 | /* Answer in remaining cases depends on existance of | 2785 | /* Answer in remaining cases depends on existance of |
@@ -2005,14 +2798,20 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) | |||
2005 | * that are not able to provide mandatory locking. | 2798 | * that are not able to provide mandatory locking. |
2006 | */ | 2799 | */ |
2007 | static inline int | 2800 | static inline int |
2008 | io_during_grace_disallowed(struct inode *inode, int flags) | 2801 | grace_disallows_io(struct inode *inode) |
2009 | { | 2802 | { |
2010 | return locks_in_grace() && (flags & (RD_STATE | WR_STATE)) | 2803 | return locks_in_grace() && mandatory_lock(inode); |
2011 | && mandatory_lock(inode); | ||
2012 | } | 2804 | } |
2013 | 2805 | ||
2014 | static int check_stateid_generation(stateid_t *in, stateid_t *ref) | 2806 | static int check_stateid_generation(stateid_t *in, stateid_t *ref, int flags) |
2015 | { | 2807 | { |
2808 | /* | ||
2809 | * When sessions are used the stateid generation number is ignored | ||
2810 | * when it is zero. | ||
2811 | */ | ||
2812 | if ((flags & HAS_SESSION) && in->si_generation == 0) | ||
2813 | goto out; | ||
2814 | |||
2016 | /* If the client sends us a stateid from the future, it's buggy: */ | 2815 | /* If the client sends us a stateid from the future, it's buggy: */ |
2017 | if (in->si_generation > ref->si_generation) | 2816 | if (in->si_generation > ref->si_generation) |
2018 | return nfserr_bad_stateid; | 2817 | return nfserr_bad_stateid; |
@@ -2028,74 +2827,77 @@ static int check_stateid_generation(stateid_t *in, stateid_t *ref) | |||
2028 | */ | 2827 | */ |
2029 | if (in->si_generation < ref->si_generation) | 2828 | if (in->si_generation < ref->si_generation) |
2030 | return nfserr_old_stateid; | 2829 | return nfserr_old_stateid; |
2830 | out: | ||
2031 | return nfs_ok; | 2831 | return nfs_ok; |
2032 | } | 2832 | } |
2033 | 2833 | ||
2834 | static int is_delegation_stateid(stateid_t *stateid) | ||
2835 | { | ||
2836 | return stateid->si_fileid == 0; | ||
2837 | } | ||
2838 | |||
2034 | /* | 2839 | /* |
2035 | * Checks for stateid operations | 2840 | * Checks for stateid operations |
2036 | */ | 2841 | */ |
2037 | __be32 | 2842 | __be32 |
2038 | nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp) | 2843 | nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, |
2844 | stateid_t *stateid, int flags, struct file **filpp) | ||
2039 | { | 2845 | { |
2040 | struct nfs4_stateid *stp = NULL; | 2846 | struct nfs4_stateid *stp = NULL; |
2041 | struct nfs4_delegation *dp = NULL; | 2847 | struct nfs4_delegation *dp = NULL; |
2042 | stateid_t *stidp; | 2848 | struct svc_fh *current_fh = &cstate->current_fh; |
2043 | struct inode *ino = current_fh->fh_dentry->d_inode; | 2849 | struct inode *ino = current_fh->fh_dentry->d_inode; |
2044 | __be32 status; | 2850 | __be32 status; |
2045 | 2851 | ||
2046 | dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n", | ||
2047 | stateid->si_boot, stateid->si_stateownerid, | ||
2048 | stateid->si_fileid, stateid->si_generation); | ||
2049 | if (filpp) | 2852 | if (filpp) |
2050 | *filpp = NULL; | 2853 | *filpp = NULL; |
2051 | 2854 | ||
2052 | if (io_during_grace_disallowed(ino, flags)) | 2855 | if (grace_disallows_io(ino)) |
2053 | return nfserr_grace; | 2856 | return nfserr_grace; |
2054 | 2857 | ||
2858 | if (nfsd4_has_session(cstate)) | ||
2859 | flags |= HAS_SESSION; | ||
2860 | |||
2055 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) | 2861 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
2056 | return check_special_stateids(current_fh, stateid, flags); | 2862 | return check_special_stateids(current_fh, stateid, flags); |
2057 | 2863 | ||
2058 | /* STALE STATEID */ | ||
2059 | status = nfserr_stale_stateid; | 2864 | status = nfserr_stale_stateid; |
2060 | if (STALE_STATEID(stateid)) | 2865 | if (STALE_STATEID(stateid)) |
2061 | goto out; | 2866 | goto out; |
2062 | 2867 | ||
2063 | /* BAD STATEID */ | ||
2064 | status = nfserr_bad_stateid; | 2868 | status = nfserr_bad_stateid; |
2065 | if (!stateid->si_fileid) { /* delegation stateid */ | 2869 | if (is_delegation_stateid(stateid)) { |
2066 | if(!(dp = find_delegation_stateid(ino, stateid))) { | 2870 | dp = find_delegation_stateid(ino, stateid); |
2067 | dprintk("NFSD: delegation stateid not found\n"); | 2871 | if (!dp) |
2068 | goto out; | 2872 | goto out; |
2069 | } | 2873 | status = check_stateid_generation(stateid, &dp->dl_stateid, |
2070 | stidp = &dp->dl_stateid; | 2874 | flags); |
2875 | if (status) | ||
2876 | goto out; | ||
2877 | status = nfs4_check_delegmode(dp, flags); | ||
2878 | if (status) | ||
2879 | goto out; | ||
2880 | renew_client(dp->dl_client); | ||
2881 | if (filpp) | ||
2882 | *filpp = dp->dl_vfs_file; | ||
2071 | } else { /* open or lock stateid */ | 2883 | } else { /* open or lock stateid */ |
2072 | if (!(stp = find_stateid(stateid, flags))) { | 2884 | stp = find_stateid(stateid, flags); |
2073 | dprintk("NFSD: open or lock stateid not found\n"); | 2885 | if (!stp) |
2074 | goto out; | 2886 | goto out; |
2075 | } | 2887 | if (nfs4_check_fh(current_fh, stp)) |
2076 | if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) | ||
2077 | goto out; | 2888 | goto out; |
2078 | if (!stp->st_stateowner->so_confirmed) | 2889 | if (!stp->st_stateowner->so_confirmed) |
2079 | goto out; | 2890 | goto out; |
2080 | stidp = &stp->st_stateid; | 2891 | status = check_stateid_generation(stateid, &stp->st_stateid, |
2081 | } | 2892 | flags); |
2082 | status = check_stateid_generation(stateid, stidp); | 2893 | if (status) |
2083 | if (status) | 2894 | goto out; |
2084 | goto out; | 2895 | status = nfs4_check_openmode(stp, flags); |
2085 | if (stp) { | 2896 | if (status) |
2086 | if ((status = nfs4_check_openmode(stp,flags))) | ||
2087 | goto out; | 2897 | goto out; |
2088 | renew_client(stp->st_stateowner->so_client); | 2898 | renew_client(stp->st_stateowner->so_client); |
2089 | if (filpp) | 2899 | if (filpp) |
2090 | *filpp = stp->st_vfs_file; | 2900 | *filpp = stp->st_vfs_file; |
2091 | } else { | ||
2092 | if ((status = nfs4_check_delegmode(dp, flags))) | ||
2093 | goto out; | ||
2094 | renew_client(dp->dl_client); | ||
2095 | if (flags & DELEG_RET) | ||
2096 | unhash_delegation(dp); | ||
2097 | if (filpp) | ||
2098 | *filpp = dp->dl_vfs_file; | ||
2099 | } | 2901 | } |
2100 | status = nfs_ok; | 2902 | status = nfs_ok; |
2101 | out: | 2903 | out: |
@@ -2113,10 +2915,14 @@ setlkflg (int type) | |||
2113 | * Checks for sequence id mutating operations. | 2915 | * Checks for sequence id mutating operations. |
2114 | */ | 2916 | */ |
2115 | static __be32 | 2917 | static __be32 |
2116 | nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock) | 2918 | nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, |
2919 | stateid_t *stateid, int flags, | ||
2920 | struct nfs4_stateowner **sopp, | ||
2921 | struct nfs4_stateid **stpp, struct nfsd4_lock *lock) | ||
2117 | { | 2922 | { |
2118 | struct nfs4_stateid *stp; | 2923 | struct nfs4_stateid *stp; |
2119 | struct nfs4_stateowner *sop; | 2924 | struct nfs4_stateowner *sop; |
2925 | struct svc_fh *current_fh = &cstate->current_fh; | ||
2120 | __be32 status; | 2926 | __be32 status; |
2121 | 2927 | ||
2122 | dprintk("NFSD: preprocess_seqid_op: seqid=%d " | 2928 | dprintk("NFSD: preprocess_seqid_op: seqid=%d " |
@@ -2134,6 +2940,10 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2134 | 2940 | ||
2135 | if (STALE_STATEID(stateid)) | 2941 | if (STALE_STATEID(stateid)) |
2136 | return nfserr_stale_stateid; | 2942 | return nfserr_stale_stateid; |
2943 | |||
2944 | if (nfsd4_has_session(cstate)) | ||
2945 | flags |= HAS_SESSION; | ||
2946 | |||
2137 | /* | 2947 | /* |
2138 | * We return BAD_STATEID if filehandle doesn't match stateid, | 2948 | * We return BAD_STATEID if filehandle doesn't match stateid, |
2139 | * the confirmed flag is incorrecly set, or the generation | 2949 | * the confirmed flag is incorrecly set, or the generation |
@@ -2166,8 +2976,9 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2166 | if (lock->lk_is_new) { | 2976 | if (lock->lk_is_new) { |
2167 | if (!sop->so_is_open_owner) | 2977 | if (!sop->so_is_open_owner) |
2168 | return nfserr_bad_stateid; | 2978 | return nfserr_bad_stateid; |
2169 | if (!same_clid(&clp->cl_clientid, lockclid)) | 2979 | if (!(flags & HAS_SESSION) && |
2170 | return nfserr_bad_stateid; | 2980 | !same_clid(&clp->cl_clientid, lockclid)) |
2981 | return nfserr_bad_stateid; | ||
2171 | /* stp is the open stateid */ | 2982 | /* stp is the open stateid */ |
2172 | status = nfs4_check_openmode(stp, lkflg); | 2983 | status = nfs4_check_openmode(stp, lkflg); |
2173 | if (status) | 2984 | if (status) |
@@ -2190,7 +3001,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2190 | * For the moment, we ignore the possibility of | 3001 | * For the moment, we ignore the possibility of |
2191 | * generation number wraparound. | 3002 | * generation number wraparound. |
2192 | */ | 3003 | */ |
2193 | if (seqid != sop->so_seqid) | 3004 | if (!(flags & HAS_SESSION) && seqid != sop->so_seqid) |
2194 | goto check_replay; | 3005 | goto check_replay; |
2195 | 3006 | ||
2196 | if (sop->so_confirmed && flags & CONFIRM) { | 3007 | if (sop->so_confirmed && flags & CONFIRM) { |
@@ -2203,7 +3014,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2203 | " confirmed yet!\n"); | 3014 | " confirmed yet!\n"); |
2204 | return nfserr_bad_stateid; | 3015 | return nfserr_bad_stateid; |
2205 | } | 3016 | } |
2206 | status = check_stateid_generation(stateid, &stp->st_stateid); | 3017 | status = check_stateid_generation(stateid, &stp->st_stateid, flags); |
2207 | if (status) | 3018 | if (status) |
2208 | return status; | 3019 | return status; |
2209 | renew_client(sop->so_client); | 3020 | renew_client(sop->so_client); |
@@ -2239,7 +3050,7 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2239 | 3050 | ||
2240 | nfs4_lock_state(); | 3051 | nfs4_lock_state(); |
2241 | 3052 | ||
2242 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 3053 | if ((status = nfs4_preprocess_seqid_op(cstate, |
2243 | oc->oc_seqid, &oc->oc_req_stateid, | 3054 | oc->oc_seqid, &oc->oc_req_stateid, |
2244 | CONFIRM | OPEN_STATE, | 3055 | CONFIRM | OPEN_STATE, |
2245 | &oc->oc_stateowner, &stp, NULL))) | 3056 | &oc->oc_stateowner, &stp, NULL))) |
@@ -2304,12 +3115,12 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, | |||
2304 | (int)cstate->current_fh.fh_dentry->d_name.len, | 3115 | (int)cstate->current_fh.fh_dentry->d_name.len, |
2305 | cstate->current_fh.fh_dentry->d_name.name); | 3116 | cstate->current_fh.fh_dentry->d_name.name); |
2306 | 3117 | ||
2307 | if (!access_valid(od->od_share_access) | 3118 | if (!access_valid(od->od_share_access, cstate->minorversion) |
2308 | || !deny_valid(od->od_share_deny)) | 3119 | || !deny_valid(od->od_share_deny)) |
2309 | return nfserr_inval; | 3120 | return nfserr_inval; |
2310 | 3121 | ||
2311 | nfs4_lock_state(); | 3122 | nfs4_lock_state(); |
2312 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 3123 | if ((status = nfs4_preprocess_seqid_op(cstate, |
2313 | od->od_seqid, | 3124 | od->od_seqid, |
2314 | &od->od_stateid, | 3125 | &od->od_stateid, |
2315 | OPEN_STATE, | 3126 | OPEN_STATE, |
@@ -2362,7 +3173,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2362 | 3173 | ||
2363 | nfs4_lock_state(); | 3174 | nfs4_lock_state(); |
2364 | /* check close_lru for replay */ | 3175 | /* check close_lru for replay */ |
2365 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 3176 | if ((status = nfs4_preprocess_seqid_op(cstate, |
2366 | close->cl_seqid, | 3177 | close->cl_seqid, |
2367 | &close->cl_stateid, | 3178 | &close->cl_stateid, |
2368 | OPEN_STATE | CLOSE_STATE, | 3179 | OPEN_STATE | CLOSE_STATE, |
@@ -2373,7 +3184,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2373 | memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); | 3184 | memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t)); |
2374 | 3185 | ||
2375 | /* release_stateid() calls nfsd_close() if needed */ | 3186 | /* release_stateid() calls nfsd_close() if needed */ |
2376 | release_stateid(stp, OPEN_STATE); | 3187 | release_open_stateid(stp); |
2377 | 3188 | ||
2378 | /* place unused nfs4_stateowners on so_close_lru list to be | 3189 | /* place unused nfs4_stateowners on so_close_lru list to be |
2379 | * released by the laundromat service after the lease period | 3190 | * released by the laundromat service after the lease period |
@@ -2394,16 +3205,40 @@ __be32 | |||
2394 | nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 3205 | nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
2395 | struct nfsd4_delegreturn *dr) | 3206 | struct nfsd4_delegreturn *dr) |
2396 | { | 3207 | { |
3208 | struct nfs4_delegation *dp; | ||
3209 | stateid_t *stateid = &dr->dr_stateid; | ||
3210 | struct inode *inode; | ||
2397 | __be32 status; | 3211 | __be32 status; |
3212 | int flags = 0; | ||
2398 | 3213 | ||
2399 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | 3214 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
2400 | goto out; | 3215 | return status; |
3216 | inode = cstate->current_fh.fh_dentry->d_inode; | ||
2401 | 3217 | ||
3218 | if (nfsd4_has_session(cstate)) | ||
3219 | flags |= HAS_SESSION; | ||
2402 | nfs4_lock_state(); | 3220 | nfs4_lock_state(); |
2403 | status = nfs4_preprocess_stateid_op(&cstate->current_fh, | 3221 | status = nfserr_bad_stateid; |
2404 | &dr->dr_stateid, DELEG_RET, NULL); | 3222 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
2405 | nfs4_unlock_state(); | 3223 | goto out; |
3224 | status = nfserr_stale_stateid; | ||
3225 | if (STALE_STATEID(stateid)) | ||
3226 | goto out; | ||
3227 | status = nfserr_bad_stateid; | ||
3228 | if (!is_delegation_stateid(stateid)) | ||
3229 | goto out; | ||
3230 | dp = find_delegation_stateid(inode, stateid); | ||
3231 | if (!dp) | ||
3232 | goto out; | ||
3233 | status = check_stateid_generation(stateid, &dp->dl_stateid, flags); | ||
3234 | if (status) | ||
3235 | goto out; | ||
3236 | renew_client(dp->dl_client); | ||
3237 | |||
3238 | unhash_delegation(dp); | ||
2406 | out: | 3239 | out: |
3240 | nfs4_unlock_state(); | ||
3241 | |||
2407 | return status; | 3242 | return status; |
2408 | } | 3243 | } |
2409 | 3244 | ||
@@ -2684,11 +3519,12 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2684 | struct nfs4_file *fp; | 3519 | struct nfs4_file *fp; |
2685 | 3520 | ||
2686 | status = nfserr_stale_clientid; | 3521 | status = nfserr_stale_clientid; |
2687 | if (STALE_CLIENTID(&lock->lk_new_clientid)) | 3522 | if (!nfsd4_has_session(cstate) && |
3523 | STALE_CLIENTID(&lock->lk_new_clientid)) | ||
2688 | goto out; | 3524 | goto out; |
2689 | 3525 | ||
2690 | /* validate and update open stateid and open seqid */ | 3526 | /* validate and update open stateid and open seqid */ |
2691 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 3527 | status = nfs4_preprocess_seqid_op(cstate, |
2692 | lock->lk_new_open_seqid, | 3528 | lock->lk_new_open_seqid, |
2693 | &lock->lk_new_open_stateid, | 3529 | &lock->lk_new_open_stateid, |
2694 | OPEN_STATE, | 3530 | OPEN_STATE, |
@@ -2715,7 +3551,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2715 | goto out; | 3551 | goto out; |
2716 | } else { | 3552 | } else { |
2717 | /* lock (lock owner + lock stateid) already exists */ | 3553 | /* lock (lock owner + lock stateid) already exists */ |
2718 | status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 3554 | status = nfs4_preprocess_seqid_op(cstate, |
2719 | lock->lk_old_lock_seqid, | 3555 | lock->lk_old_lock_seqid, |
2720 | &lock->lk_old_lock_stateid, | 3556 | &lock->lk_old_lock_stateid, |
2721 | LOCK_STATE, | 3557 | LOCK_STATE, |
@@ -2788,7 +3624,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2788 | } | 3624 | } |
2789 | out: | 3625 | out: |
2790 | if (status && lock->lk_is_new && lock_sop) | 3626 | if (status && lock->lk_is_new && lock_sop) |
2791 | release_stateowner(lock_sop); | 3627 | release_lockowner(lock_sop); |
2792 | if (lock->lk_replay_owner) { | 3628 | if (lock->lk_replay_owner) { |
2793 | nfs4_get_stateowner(lock->lk_replay_owner); | 3629 | nfs4_get_stateowner(lock->lk_replay_owner); |
2794 | cstate->replay_owner = lock->lk_replay_owner; | 3630 | cstate->replay_owner = lock->lk_replay_owner; |
@@ -2838,7 +3674,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2838 | nfs4_lock_state(); | 3674 | nfs4_lock_state(); |
2839 | 3675 | ||
2840 | status = nfserr_stale_clientid; | 3676 | status = nfserr_stale_clientid; |
2841 | if (STALE_CLIENTID(&lockt->lt_clientid)) | 3677 | if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid)) |
2842 | goto out; | 3678 | goto out; |
2843 | 3679 | ||
2844 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) { | 3680 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) { |
@@ -2911,7 +3747,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
2911 | 3747 | ||
2912 | nfs4_lock_state(); | 3748 | nfs4_lock_state(); |
2913 | 3749 | ||
2914 | if ((status = nfs4_preprocess_seqid_op(&cstate->current_fh, | 3750 | if ((status = nfs4_preprocess_seqid_op(cstate, |
2915 | locku->lu_seqid, | 3751 | locku->lu_seqid, |
2916 | &locku->lu_stateid, | 3752 | &locku->lu_stateid, |
2917 | LOCK_STATE, | 3753 | LOCK_STATE, |
@@ -3037,7 +3873,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, | |||
3037 | /* unhash_stateowner deletes so_perclient only | 3873 | /* unhash_stateowner deletes so_perclient only |
3038 | * for openowners. */ | 3874 | * for openowners. */ |
3039 | list_del(&sop->so_perclient); | 3875 | list_del(&sop->so_perclient); |
3040 | release_stateowner(sop); | 3876 | release_lockowner(sop); |
3041 | } | 3877 | } |
3042 | out: | 3878 | out: |
3043 | nfs4_unlock_state(); | 3879 | nfs4_unlock_state(); |
@@ -3051,12 +3887,12 @@ alloc_reclaim(void) | |||
3051 | } | 3887 | } |
3052 | 3888 | ||
3053 | int | 3889 | int |
3054 | nfs4_has_reclaimed_state(const char *name) | 3890 | nfs4_has_reclaimed_state(const char *name, bool use_exchange_id) |
3055 | { | 3891 | { |
3056 | unsigned int strhashval = clientstr_hashval(name); | 3892 | unsigned int strhashval = clientstr_hashval(name); |
3057 | struct nfs4_client *clp; | 3893 | struct nfs4_client *clp; |
3058 | 3894 | ||
3059 | clp = find_confirmed_client_by_str(name, strhashval); | 3895 | clp = find_confirmed_client_by_str(name, strhashval, use_exchange_id); |
3060 | return clp ? 1 : 0; | 3896 | return clp ? 1 : 0; |
3061 | } | 3897 | } |
3062 | 3898 | ||
@@ -3153,6 +3989,8 @@ nfs4_state_init(void) | |||
3153 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); | 3989 | INIT_LIST_HEAD(&unconf_str_hashtbl[i]); |
3154 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); | 3990 | INIT_LIST_HEAD(&unconf_id_hashtbl[i]); |
3155 | } | 3991 | } |
3992 | for (i = 0; i < SESSION_HASH_SIZE; i++) | ||
3993 | INIT_LIST_HEAD(&sessionid_hashtbl[i]); | ||
3156 | for (i = 0; i < FILE_HASH_SIZE; i++) { | 3994 | for (i = 0; i < FILE_HASH_SIZE; i++) { |
3157 | INIT_LIST_HEAD(&file_hashtbl[i]); | 3995 | INIT_LIST_HEAD(&file_hashtbl[i]); |
3158 | } | 3996 | } |