2 * linux/fs/nfsd/nfs4state.c
4 * Copyright (c) 2001 The Regents of the University of Michigan.
7 * Kendrick Smith <kmsmith@umich.edu>
8 * Andy Adamson <kandros@umich.edu>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its
20 * contributors may be used to endorse or promote products derived
21 * from this software without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include <linux/param.h>
38 #include <linux/major.h>
39 #include <linux/slab.h>
42 #include <linux/sunrpc/svc.h>
43 #include <linux/nfsd/nfsd.h>
44 #include <linux/nfsd/cache.h>
45 #include <linux/mount.h>
46 #include <linux/workqueue.h>
47 #include <linux/nfs4.h>
48 #include <linux/nfsd/state.h>
49 #include <linux/nfsd/xdr4.h>
51 #define NFSDDBG_FACILITY NFSDDBG_PROC
55 static u32 current_clientid = 1;
56 static u32 current_ownerid;
57 static u32 current_fileid;
59 stateid_t zerostateid; /* bits all 0 */
60 stateid_t onestateid; /* bits all 1 */
63 u32 list_add_perfile = 0;
64 u32 list_del_perfile = 0;
65 u32 add_perclient = 0;
66 u32 del_perclient = 0;
77 * protects clientid_hashtbl[], clientstr_hashtbl[],
78 * unconfstr_hashtbl[], uncofid_hashtbl[].
80 static struct semaphore client_sema;
83 nfsd4_lock_state(void)
89 nfsd4_unlock_state(void)
95 opaque_hashval(const void *ptr, int nbytes)
97 unsigned char *cptr = (unsigned char *) ptr;
107 /* forward declarations */
108 static void release_stateowner(struct nfs4_stateowner *sop);
109 static void release_stateid(struct nfs4_stateid *stp);
110 static void release_file(struct nfs4_file *fp);
117 /* Hash tables for nfs4_clientid state */
118 #define CLIENT_HASH_BITS 4
119 #define CLIENT_HASH_SIZE (1 << CLIENT_HASH_BITS)
120 #define CLIENT_HASH_MASK (CLIENT_HASH_SIZE - 1)
122 #define clientid_hashval(id) \
123 ((id) & CLIENT_HASH_MASK)
124 #define clientstr_hashval(name, namelen) \
125 (opaque_hashval((name), (namelen)) & CLIENT_HASH_MASK)
127 /* conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed
128 * setclientid_confirmed info.
130 * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed
133 * client_lru holds client queue ordered by nfs4_client.cl_time
136 static struct list_head conf_id_hashtbl[CLIENT_HASH_SIZE];
137 static struct list_head conf_str_hashtbl[CLIENT_HASH_SIZE];
138 static struct list_head unconf_str_hashtbl[CLIENT_HASH_SIZE];
139 static struct list_head unconf_id_hashtbl[CLIENT_HASH_SIZE];
140 static struct list_head client_lru;
143 renew_client(struct nfs4_client *clp)
146 * Move client to the end to the LRU list.
148 dprintk("renewing client (clientid %08x/%08x)\n",
149 clp->cl_clientid.cl_boot,
150 clp->cl_clientid.cl_id);
151 list_move_tail(&clp->cl_lru, &client_lru);
152 clp->cl_time = get_seconds();
155 /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
157 STALE_CLIENTID(clientid_t *clid)
159 if (clid->cl_boot == boot_time)
161 dprintk("NFSD stale clientid (%08x/%08x)\n",
162 clid->cl_boot, clid->cl_id);
167 * XXX Should we use a slab cache ?
168 * This type of memory management is somewhat inefficient, but we use it
169 * anyway since SETCLIENTID is not a common operation.
171 static inline struct nfs4_client *
172 alloc_client(struct xdr_netobj name)
174 struct nfs4_client *clp;
176 if ((clp = kmalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
177 memset(clp, 0, sizeof(*clp));
178 if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) {
179 memcpy(clp->cl_name.data, name.data, name.len);
180 clp->cl_name.len = name.len;
191 free_client(struct nfs4_client *clp)
193 kfree(clp->cl_name.data);
198 expire_client(struct nfs4_client *clp)
200 struct nfs4_stateowner *sop;
202 dprintk("NFSD: expire_client\n");
203 list_del(&clp->cl_idhash);
204 list_del(&clp->cl_strhash);
205 list_del(&clp->cl_lru);
206 while (!list_empty(&clp->cl_perclient)) {
207 sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient);
208 release_stateowner(sop);
213 static struct nfs4_client *
214 create_client(struct xdr_netobj name) {
215 struct nfs4_client *clp;
217 if(!(clp = alloc_client(name)))
219 INIT_LIST_HEAD(&clp->cl_idhash);
220 INIT_LIST_HEAD(&clp->cl_strhash);
221 INIT_LIST_HEAD(&clp->cl_perclient);
222 INIT_LIST_HEAD(&clp->cl_lru);
228 copy_verf(struct nfs4_client *target, nfs4_verifier source) {
229 memcpy(&target->cl_verifier, source, sizeof(nfs4_verifier));
233 copy_clid(struct nfs4_client *target, struct nfs4_client *source) {
234 target->cl_clientid.cl_boot = source->cl_clientid.cl_boot;
235 target->cl_clientid.cl_id = source->cl_clientid.cl_id;
239 copy_cred(struct svc_cred *target, struct svc_cred *source) {
242 target->cr_uid = source->cr_uid;
243 target->cr_gid = source->cr_gid;
244 for(i = 0; i < NGROUPS; i++)
245 target->cr_groups[i] = source->cr_groups[i];
249 cmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) {
252 return((n1->len == n2->len) && !memcmp(n1->data, n2->data, n2->len));
256 cmp_verf(nfs4_verifier v1, nfs4_verifier v2) {
257 return(!memcmp(v1,v2,sizeof(nfs4_verifier)));
261 cmp_clid(clientid_t * cl1, clientid_t * cl2) {
262 return((cl1->cl_boot == cl2->cl_boot) &&
263 (cl1->cl_id == cl2->cl_id));
266 /* XXX what about NGROUP */
268 cmp_creds(struct svc_cred *cr1, struct svc_cred *cr2){
269 return((cr1->cr_uid == cr2->cr_uid) &&
270 (cr1->cr_gid == cr2->cr_gid));
275 gen_clid(struct nfs4_client *clp) {
276 clp->cl_clientid.cl_boot = boot_time;
277 clp->cl_clientid.cl_id = current_clientid++;
281 gen_confirm(struct nfs4_client *clp) {
286 p = (u32 *)clp->cl_confirm;
292 check_name(struct xdr_netobj name) {
296 if (name.len > NFS4_OPAQUE_LIMIT) {
297 printk("NFSD: check_name: name too long(%d)!\n", name.len);
304 add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
306 unsigned int idhashval;
308 list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]);
309 idhashval = clientid_hashval(clp->cl_clientid.cl_id);
310 list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]);
311 list_add_tail(&clp->cl_lru, &client_lru);
312 clp->cl_time = get_seconds();
316 move_to_confirmed(struct nfs4_client *clp, unsigned int idhashval)
318 unsigned int strhashval;
320 dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
321 list_del_init(&clp->cl_strhash);
322 list_del_init(&clp->cl_idhash);
323 list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
324 strhashval = clientstr_hashval(clp->cl_name.data,
326 list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
331 * RFC 3010 has a complex implmentation description of processing a
332 * SETCLIENTID request consisting of 5 bullets, labeled as
333 * CASE0 - CASE4 below.
336 * callback information will be processed in a future patch
338 * an unconfirmed record is added when:
339 * NORMAL (part of CASE 4): there is no confirmed nor unconfirmed record.
340 * CASE 1: confirmed record found with matching name, principal,
341 * verifier, and clientid.
342 * CASE 2: confirmed record found with matching name, principal,
343 * and there is no unconfirmed record with matching
346 * an unconfirmed record is replaced when:
347 * CASE 3: confirmed record found with matching name, principal,
348 * and an unconfirmed record is found with matching
349 * name, principal, and with clientid and
350 * confirm that does not match the confirmed record.
351 * CASE 4: there is no confirmed record with matching name and
352 * principal. there is an unconfirmed record with
353 * matching name, principal.
355 * an unconfirmed record is deleted when:
356 * CASE 1: an unconfirmed record that matches input name, verifier,
357 * and confirmed clientid.
358 * CASE 4: any unconfirmed records with matching name and principal
359 * that exist after an unconfirmed record has been replaced
360 * as described above.
364 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
366 u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
367 struct xdr_netobj clname = {
368 .len = setclid->se_namelen,
369 .data = setclid->se_name,
371 char * clverifier = setclid->se_verf;
372 unsigned int strhashval;
373 struct nfs4_client * conf, * unconf, * new, * clp;
375 struct list_head *pos, *next;
377 status = nfserr_inval;
378 if (!check_name(clname))
382 * XXX The Duplicate Request Cache (DRC) has been checked (??)
383 * We get here on a DRC miss.
386 strhashval = clientstr_hashval(clname.data, clname.len);
390 list_for_each_safe(pos, next, &conf_str_hashtbl[strhashval]) {
391 clp = list_entry(pos, struct nfs4_client, cl_strhash);
392 if (!cmp_name(&clp->cl_name, &clname))
396 * clname match, confirmed, different principal
397 * or different ip_address
399 status = nfserr_clid_inuse;
400 if (!cmp_creds(&clp->cl_cred,&rqstp->rq_cred)) {
401 printk("NFSD: setclientid: string in use by client"
402 "(clientid %08x/%08x)\n",
403 clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
406 if (clp->cl_addr != ip_addr) {
407 printk("NFSD: setclientid: string in use by client"
408 "(clientid %08x/%08x)\n",
409 clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
414 * cl_name match from a previous SETCLIENTID operation
415 * XXX check for additional matches?
421 list_for_each_safe(pos, next, &unconf_str_hashtbl[strhashval]) {
422 clp = list_entry(pos, struct nfs4_client, cl_strhash);
423 if (!cmp_name(&clp->cl_name, &clname))
425 /* cl_name match from a previous SETCLIENTID operation */
429 status = nfserr_resource;
433 * placed first, because it is the normal case.
436 expire_client(unconf);
437 if (!(new = create_client(clname)))
439 copy_verf(new,clverifier);
440 new->cl_addr = ip_addr;
441 copy_cred(&new->cl_cred,&rqstp->rq_cred);
444 add_to_unconfirmed(new, strhashval);
445 } else if (cmp_verf(conf->cl_verifier, clverifier)) {
448 * cl_name match, confirmed, principal match
449 * verifier match: probable callback update
451 * remove any unconfirmed nfs4_client with
452 * matching cl_name, cl_verifier, and cl_clientid
454 * create and insert an unconfirmed nfs4_client with same
455 * cl_name, cl_verifier, and cl_clientid as existing
456 * nfs4_client, but with the new callback info and a
460 cmp_verf(unconf->cl_verifier, conf->cl_verifier) &&
461 cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) {
462 expire_client(unconf);
464 if (!(new = create_client(clname)))
466 copy_verf(new,conf->cl_verifier);
467 new->cl_addr = ip_addr;
468 copy_cred(&new->cl_cred,&rqstp->rq_cred);
469 copy_clid(new, conf);
471 add_to_unconfirmed(new,strhashval);
472 } else if (!unconf) {
475 * clname match, confirmed, principal match
476 * verfier does not match
477 * no unconfirmed. create a new unconfirmed nfs4_client
478 * using input clverifier, clname, and callback info
479 * and generate a new cl_clientid and cl_confirm.
481 if (!(new = create_client(clname)))
483 copy_verf(new,clverifier);
484 new->cl_addr = ip_addr;
485 copy_cred(&new->cl_cred,&rqstp->rq_cred);
488 add_to_unconfirmed(new, strhashval);
489 } else if (!cmp_clid(&conf->cl_clientid, &unconf->cl_clientid) &&
490 !cmp_verf(conf->cl_confirm, unconf->cl_confirm)) {
493 * confirmed found (name, principal match)
494 * confirmed verifier does not match input clverifier
496 * unconfirmed found (name match)
497 * confirmed->cl_clientid != unconfirmed->cl_clientid and
498 * confirmed->cl_confirm != unconfirmed->cl_confirm
500 * remove unconfirmed.
502 * create an unconfirmed nfs4_client
503 * with same cl_name as existing confirmed nfs4_client,
504 * but with new callback info, new cl_clientid,
505 * new cl_verifier and a new cl_confirm
507 expire_client(unconf);
508 if (!(new = create_client(clname)))
510 copy_verf(new,clverifier);
511 new->cl_addr = ip_addr;
512 copy_cred(&new->cl_cred,&rqstp->rq_cred);
515 add_to_unconfirmed(new, strhashval);
517 /* No cases hit !!! */
518 status = nfserr_inval;
522 setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
523 setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
524 memcpy(&setclid->se_confirm, new->cl_confirm, sizeof(nfs4_verifier));
525 printk(KERN_INFO "NFSD: this client will not receive delegations\n");
534 * RFC 3010 has a complex implmentation description of processing a
535 * SETCLIENTID_CONFIRM request consisting of 4 bullets describing
536 * processing on a DRC miss, labeled as CASE1 - CASE4 below.
538 * NOTE: callback information will be processed here in a future patch
541 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
543 u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
544 unsigned int idhashval;
545 struct nfs4_client *clp, *conf = NULL, *unconf = NULL;
546 char * confirm = setclientid_confirm->sc_confirm;
547 clientid_t * clid = &setclientid_confirm->sc_clientid;
548 struct list_head *pos, *next;
551 status = nfserr_stale_clientid;
552 if (STALE_CLIENTID(clid))
555 * XXX The Duplicate Request Cache (DRC) has been checked (??)
556 * We get here on a DRC miss.
559 idhashval = clientid_hashval(clid->cl_id);
561 list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
562 clp = list_entry(pos, struct nfs4_client, cl_idhash);
563 if (!cmp_clid(&clp->cl_clientid, clid))
566 status = nfserr_inval;
568 * Found a record for this clientid. If the IP addresses
569 * don't match, return ERR_INVAL just as if the record had
572 if (clp->cl_addr != ip_addr) {
573 printk("NFSD: setclientid: string in use by client"
574 "(clientid %08x/%08x)\n",
575 clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
581 list_for_each_safe(pos, next, &unconf_id_hashtbl[idhashval]) {
582 clp = list_entry(pos, struct nfs4_client, cl_idhash);
583 if (!cmp_clid(&clp->cl_clientid, clid))
585 status = nfserr_inval;
586 if (clp->cl_addr != ip_addr) {
587 printk("NFSD: setclientid: string in use by client"
588 "(clientid %08x/%08x)\n",
589 clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
596 * unconf record that matches input clientid and input confirm.
597 * conf record that matches input clientid.
598 * conf and unconf records match names, verifiers
600 if ((conf && unconf) &&
601 (cmp_verf(unconf->cl_confirm, confirm)) &&
602 (cmp_verf(conf->cl_verifier, unconf->cl_verifier)) &&
603 (cmp_name(&conf->cl_name,&unconf->cl_name)) &&
604 (!cmp_verf(conf->cl_confirm, unconf->cl_confirm))) {
605 if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred))
606 status = nfserr_clid_inuse;
609 move_to_confirmed(unconf, idhashval);
615 * conf record that matches input clientid.
616 * if unconf record that matches input clientid, then unconf->cl_name
617 * or unconf->cl_verifier don't match the conf record.
619 if ((conf && !unconf) ||
621 (!cmp_verf(conf->cl_verifier, unconf->cl_verifier) ||
622 !cmp_name(&conf->cl_name, &unconf->cl_name)))) {
623 if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) {
624 status = nfserr_clid_inuse;
631 * conf record not found.
632 * unconf record found.
633 * unconf->cl_confirm matches input confirm
635 if (!conf && unconf && cmp_verf(unconf->cl_confirm, confirm)) {
636 if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
637 status = nfserr_clid_inuse;
640 move_to_confirmed(unconf, idhashval);
645 * conf record not found, or if conf, then conf->cl_confirm does not
646 * match input confirm.
647 * unconf record not found, or if unconf, then unconf->cl_confirm
648 * does not match input confirm.
650 if ((!conf || (conf && !cmp_verf(conf->cl_confirm, confirm))) &&
651 (!unconf || (unconf && !cmp_verf(unconf->cl_confirm, confirm)))) {
652 status = nfserr_stale_clientid;
655 /* check that we have hit one of the cases...*/
656 status = nfserr_inval;
659 /* XXX if status == nfs_ok, probe callback path */
665 * Open owner state (share locks)
668 /* hash tables for nfs4_stateowner */
669 #define OWNER_HASH_BITS 8
670 #define OWNER_HASH_SIZE (1 << OWNER_HASH_BITS)
671 #define OWNER_HASH_MASK (OWNER_HASH_SIZE - 1)
673 #define ownerid_hashval(id) \
674 ((id) & OWNER_HASH_MASK)
675 #define ownerstr_hashval(clientid, ownername) \
676 (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
678 static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
679 static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
681 /* hash table for nfs4_file */
682 #define FILE_HASH_BITS 8
683 #define FILE_HASH_SIZE (1 << FILE_HASH_BITS)
684 #define FILE_HASH_MASK (FILE_HASH_SIZE - 1)
685 /* hash table for (open)nfs4_stateid */
686 #define OPENSTATEID_HASH_BITS 10
687 #define OPENSTATEID_HASH_SIZE (1 << OPENSTATEID_HASH_BITS)
688 #define OPENSTATEID_HASH_MASK (OPENSTATEID_HASH_SIZE - 1)
690 #define file_hashval(x) \
691 ((unsigned int)((x)->dev + (x)->ino + (x)->generation) & FILE_HASH_MASK)
692 #define openstateid_hashval(owner_id, file_id) \
693 (((owner_id) + (file_id)) & OPENSTATEID_HASH_MASK)
695 static struct list_head file_hashtbl[FILE_HASH_SIZE];
696 static struct list_head openstateid_hashtbl[OPENSTATEID_HASH_SIZE];
698 /* OPEN Share state helper functions */
699 static inline struct nfs4_file *
700 alloc_init_file(unsigned int hashval, nfs4_ino_desc_t *ino) {
701 struct nfs4_file *fp;
702 if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) {
703 INIT_LIST_HEAD(&fp->fi_hash);
704 INIT_LIST_HEAD(&fp->fi_perfile);
705 list_add(&fp->fi_hash, &file_hashtbl[hashval]);
706 memcpy(&fp->fi_ino, ino, sizeof(nfs4_ino_desc_t));
707 fp->fi_id = current_fileid++;
711 return (struct nfs4_file *)NULL;
715 release_all_files(void)
718 struct nfs4_file *fp;
720 for (i=0;i<FILE_HASH_SIZE;i++) {
721 while (!list_empty(&file_hashtbl[i])) {
722 fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash);
723 /* this should never be more than once... */
724 if(!list_empty(&fp->fi_perfile)) {
725 printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp);
732 static inline struct nfs4_stateowner *
733 alloc_stateowner(struct xdr_netobj *owner)
735 struct nfs4_stateowner *sop;
737 if ((sop = kmalloc(sizeof(struct nfs4_stateowner),GFP_KERNEL))) {
738 if((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) {
739 memcpy(sop->so_owner.data, owner->data, owner->len);
740 sop->so_owner.len = owner->len;
745 return (struct nfs4_stateowner *)NULL;
748 /* should use a slab cache */
750 free_stateowner(struct nfs4_stateowner *sop) {
752 kfree(sop->so_owner.data);
759 static struct nfs4_stateowner *
760 alloc_init_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
761 struct nfs4_stateowner *sop;
762 unsigned int idhashval;
764 if (!(sop = alloc_stateowner(&open->op_owner)))
765 return (struct nfs4_stateowner *)NULL;
766 idhashval = ownerid_hashval(current_ownerid);
767 INIT_LIST_HEAD(&sop->so_idhash);
768 INIT_LIST_HEAD(&sop->so_strhash);
769 INIT_LIST_HEAD(&sop->so_perclient);
770 INIT_LIST_HEAD(&sop->so_peropenstate);
771 list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
772 list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
773 list_add(&sop->so_perclient, &clp->cl_perclient);
775 sop->so_id = current_ownerid++;
776 sop->so_client = clp;
777 sop->so_seqid = open->op_seqid;
778 sop->so_confirmed = 0;
784 release_stateowner(struct nfs4_stateowner *sop)
786 struct nfs4_stateid *stp;
788 list_del_init(&sop->so_idhash);
789 list_del_init(&sop->so_strhash);
790 list_del_init(&sop->so_perclient);
792 while (!list_empty(&sop->so_peropenstate)) {
793 stp = list_entry(sop->so_peropenstate.next,
794 struct nfs4_stateid, st_peropenstate);
795 release_stateid(stp);
797 free_stateowner(sop);
801 init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open) {
802 unsigned int hashval = openstateid_hashval(sop->so_id, fp->fi_id);
804 INIT_LIST_HEAD(&stp->st_hash);
805 INIT_LIST_HEAD(&stp->st_peropenstate);
806 INIT_LIST_HEAD(&stp->st_perfile);
807 list_add(&stp->st_hash, &openstateid_hashtbl[hashval]);
808 list_add(&stp->st_peropenstate, &sop->so_peropenstate);
810 list_add(&stp->st_perfile, &fp->fi_perfile);
811 stp->st_stateowner = sop;
813 stp->st_stateid.si_boot = boot_time;
814 stp->st_stateid.si_stateownerid = sop->so_id;
815 stp->st_stateid.si_fileid = fp->fi_id;
816 stp->st_stateid.si_generation = 0;
817 stp->st_share_access = open->op_share_access;
818 stp->st_share_deny = open->op_share_deny;
822 release_stateid(struct nfs4_stateid *stp) {
824 list_del_init(&stp->st_hash);
826 list_del_init(&stp->st_perfile);
827 list_del_init(&stp->st_peropenstate);
828 if(stp->st_vfs_set) {
829 nfsd_close(&stp->st_vfs_file);
831 dput(stp->st_vfs_file.f_dentry);
832 mntput(stp->st_vfs_file.f_vfsmnt);
834 /* should use a slab cache */
840 release_file(struct nfs4_file *fp)
843 list_del_init(&fp->fi_hash);
848 release_open_state(struct nfs4_stateid *stp)
850 struct nfs4_stateowner *sop = stp->st_stateowner;
851 struct nfs4_file *fp = stp->st_file;
853 dprintk("NFSD: release_open_state\n");
854 release_stateid(stp);
856 * release unused nfs4_stateowners.
857 * XXX will need to be placed on an open_stateid_lru list to be
858 * released by the laundromat service after the lease period
859 * to enable us to handle CLOSE replay
861 if (sop->so_confirmed && list_empty(&sop->so_peropenstate)) {
862 release_stateowner(sop);
864 /* unused nfs4_file's are releseed. XXX slab cache? */
865 if (list_empty(&fp->fi_perfile)) {
871 cmp_owner_str(struct nfs4_stateowner *sop, struct nfsd4_open *open) {
872 return ((sop->so_owner.len == open->op_owner.len) &&
873 !memcmp(sop->so_owner.data, open->op_owner.data, sop->so_owner.len) &&
874 (sop->so_client->cl_clientid.cl_id == open->op_clientid.cl_id));
877 /* search ownerstr_hashtbl[] for owner */
879 find_stateowner_str(unsigned int hashval, struct nfsd4_open *open, struct nfs4_stateowner **op) {
880 struct list_head *pos, *next;
881 struct nfs4_stateowner *local = NULL;
883 list_for_each_safe(pos, next, &ownerstr_hashtbl[hashval]) {
884 local = list_entry(pos, struct nfs4_stateowner, so_strhash);
885 if(!cmp_owner_str(local, open))
893 /* see if clientid is in confirmed hash table */
895 verify_clientid(struct nfs4_client **client, clientid_t *clid) {
897 struct list_head *pos, *next;
898 struct nfs4_client *clp;
899 unsigned int idhashval = clientid_hashval(clid->cl_id);
901 list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
902 clp = list_entry(pos, struct nfs4_client, cl_idhash);
903 if (!cmp_clid(&clp->cl_clientid, clid))
912 /* search file_hashtbl[] for file */
914 find_file(unsigned int hashval, nfs4_ino_desc_t *ino, struct nfs4_file **fp) {
915 struct list_head *pos, *next;
916 struct nfs4_file *local = NULL;
918 list_for_each_safe(pos, next, &file_hashtbl[hashval]) {
919 local = list_entry(pos, struct nfs4_file, fi_hash);
920 if(!memcmp(&local->fi_ino, ino, sizeof(nfs4_ino_desc_t))) {
929 test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
930 if ((stp->st_share_access & open->op_share_deny) ||
931 (stp->st_share_deny & open->op_share_access)) {
938 nfs4_init_ino(nfs4_ino_desc_t *ino, struct svc_fh *fhp)
943 inode = fhp->fh_dentry->d_inode;
946 ino->dev = inode->i_sb->s_dev;
947 ino->ino = inode->i_ino;
948 ino->generation = inode->i_generation;
952 nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
955 unsigned int fi_hashval;
956 struct nfs4_file *fp;
957 struct nfs4_stateid *stp;
958 struct list_head *pos, *next;
960 dprintk("NFSD: nfs4_share_conflict\n");
962 nfs4_init_ino(&ino, current_fh);
963 fi_hashval = file_hashval(&ino);
964 if (find_file(fi_hashval, &ino, &fp)) {
965 /* Search for conflicting share reservations */
966 list_for_each_safe(pos, next, &fp->fi_perfile) {
967 stp = list_entry(pos, struct nfs4_stateid, st_perfile);
968 if (stp->st_share_deny & deny_type)
969 return nfserr_share_denied;
976 nfs4_file_upgrade(struct file *filp, unsigned int share_access)
980 if (share_access & NFS4_SHARE_ACCESS_WRITE) {
981 status = get_write_access(filp->f_dentry->d_inode);
983 filp->f_mode = FMODE_WRITE;
985 return nfserrno(status);
991 nfs4_file_downgrade(struct file *filp, unsigned int share_access)
993 if (share_access & NFS4_SHARE_ACCESS_WRITE) {
994 put_write_access(filp->f_dentry->d_inode);
995 filp->f_mode = FMODE_READ;
1001 * nfsd4_process_open1()
1002 * lookup stateowner.
1015 nfsd4_process_open1(struct nfsd4_open *open)
1018 clientid_t *clientid = &open->op_clientid;
1019 struct nfs4_client *clp = NULL;
1020 unsigned int strhashval;
1021 struct nfs4_stateowner *sop = NULL;
1023 status = nfserr_inval;
1024 if (!check_name(open->op_owner))
1027 status = nfserr_stale_clientid;
1028 if (STALE_CLIENTID(&open->op_clientid))
1031 down(&client_sema); /* XXX need finer grained locking */
1032 strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
1033 if (find_stateowner_str(strhashval, open, &sop)) {
1034 open->op_stateowner = sop;
1035 if (open->op_seqid == sop->so_seqid){
1036 /* XXX retplay: for now, return bad seqid */
1037 status = nfserr_bad_seqid;
1040 if (sop->so_confirmed) {
1041 if (open->op_seqid == sop->so_seqid + 1) {
1045 status = nfserr_bad_seqid;
1048 /* If we get here, we received and OPEN for an unconfirmed
1049 * nfs4_stateowner. If seqid's are the same then this
1051 * If the sequid's are different, then purge the
1052 * existing nfs4_stateowner, and instantiate a new one.
1054 clp = sop->so_client;
1055 release_stateowner(sop);
1056 goto instantiate_new_owner;
1058 /* nfs4_stateowner not found.
1059 * verify clientid and instantiate new nfs4_stateowner
1060 * if verify fails this is presumably the result of the
1061 * client's lease expiring.
1063 * XXX compare clp->cl_addr with rqstp addr?
1065 status = nfserr_expired;
1066 if (!verify_clientid(&clp, clientid))
1068 instantiate_new_owner:
1069 status = nfserr_resource;
1070 if (!(sop = alloc_init_stateowner(strhashval, clp, open)))
1072 open->op_stateowner = sop;
1075 renew_client(sop->so_client);
1077 up(&client_sema); /*XXX need finer grained locking */
1082 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
1085 struct nfs4_stateowner *sop = open->op_stateowner;
1086 struct nfs4_file *fp;
1087 nfs4_ino_desc_t ino;
1088 unsigned int fi_hashval;
1089 struct list_head *pos, *next;
1090 struct nfs4_stateid *stq, *stp = NULL;
1093 status = nfserr_resource;
1097 nfs4_init_ino(&ino, current_fh);
1099 down(&client_sema); /*XXX need finer grained locking */
1100 fi_hashval = file_hashval(&ino);
1101 if (find_file(fi_hashval, &ino, &fp)) {
1102 /* Search for conflicting share reservations */
1103 status = nfserr_share_denied;
1104 list_for_each_safe(pos, next, &fp->fi_perfile) {
1105 stq = list_entry(pos, struct nfs4_stateid, st_perfile);
1106 if(stq->st_stateowner == sop) {
1110 if (!test_share(stq,open))
1114 /* No nfs4_file found; allocate and init a new one */
1115 status = nfserr_resource;
1116 if ((fp = alloc_init_file(fi_hashval, &ino)) == NULL)
1123 status = nfserr_resource;
1124 if ((stp = kmalloc(sizeof(struct nfs4_stateid),
1125 GFP_KERNEL)) == NULL)
1128 if (open->op_share_access && NFS4_SHARE_ACCESS_WRITE)
1132 if ((status = nfsd_open(rqstp, current_fh, S_IFREG,
1134 &stp->st_vfs_file)) != 0)
1138 dget(stp->st_vfs_file.f_dentry);
1139 mntget(stp->st_vfs_file.f_vfsmnt);
1141 init_stateid(stp, fp, sop, open);
1142 stp->st_vfs_set = 1;
1144 /* This is an upgrade of an existing OPEN.
1145 * OR the incoming share with the existing
1146 * nfs4_stateid share */
1147 int share_access = open->op_share_access;
1149 share_access &= ~(stp->st_share_access);
1151 /* update the struct file */
1152 if ((status = nfs4_file_upgrade(&stp->st_vfs_file, share_access)))
1154 stp->st_share_access |= share_access;
1155 stp->st_share_deny |= open->op_share_deny;
1156 /* bump the stateid */
1157 update_stateid(&stp->st_stateid);
1159 dprintk("nfs4_process_open2: stateid=(%08x/%08x/%08x/%08x)\n\n",
1160 stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid,
1161 stp->st_stateid.si_fileid, stp->st_stateid.si_generation);
1163 if (open->op_truncate) {
1164 iattr.ia_valid = ATTR_SIZE;
1166 status = nfsd_setattr(rqstp, current_fh, &iattr, 0, (time_t)0);
1170 memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));
1172 open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
1176 * To finish the open response, we just need to set the rflags.
1178 open->op_rflags = 0;
1179 if (!open->op_stateowner->so_confirmed)
1180 open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
1182 up(&client_sema); /*XXX need finer grained locking */
1188 static struct work_struct laundromat_work;
1189 static void laundromat_main(void *);
1190 static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
1193 nfsd4_renew(clientid_t *clid)
1195 struct nfs4_client *clp;
1196 struct list_head *pos, *next;
1197 unsigned int idhashval;
1201 printk("process_renew(%08x/%08x): starting\n",
1202 clid->cl_boot, clid->cl_id);
1203 status = nfserr_stale_clientid;
1204 if (STALE_CLIENTID(clid))
1207 idhashval = clientid_hashval(clid->cl_id);
1208 list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
1209 clp = list_entry(pos, struct nfs4_client, cl_idhash);
1210 if (!cmp_clid(&clp->cl_clientid, clid))
1215 list_for_each_safe(pos, next, &unconf_id_hashtbl[idhashval]) {
1216 clp = list_entry(pos, struct nfs4_client, cl_idhash);
1217 if (!cmp_clid(&clp->cl_clientid, clid))
1223 * Couldn't find an nfs4_client for this clientid.
1224 * Presumably this is because the client took too long to
1225 * RENEW, so return NFS4ERR_EXPIRED.
1227 printk("nfsd4_renew: clientid not found!\n");
1228 status = nfserr_expired;
1235 nfs4_laundromat(void)
1237 struct nfs4_client *clp;
1238 struct list_head *pos, *next;
1239 time_t cutoff = get_seconds() - NFSD_LEASE_TIME;
1240 time_t t, return_val = NFSD_LEASE_TIME;
1244 dprintk("NFSD: laundromat service - starting, examining clients\n");
1245 list_for_each_safe(pos, next, &client_lru) {
1246 clp = list_entry(pos, struct nfs4_client, cl_lru);
1247 if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
1248 t = clp->cl_time - cutoff;
1253 dprintk("NFSD: purging unused client (clientid %08x)\n",
1254 clp->cl_clientid.cl_id);
1257 if (return_val < NFSD_LAUNDROMAT_MINTIMEOUT)
1258 return_val = NFSD_LAUNDROMAT_MINTIMEOUT;
1264 laundromat_main(void *not_used)
1268 t = nfs4_laundromat();
1269 dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
1270 schedule_delayed_work(&laundromat_work, t*HZ);
1273 /* search openstateid_hashtbl[] for stateid */
1274 struct nfs4_stateid *
1275 find_stateid(stateid_t *stid)
1277 struct list_head *pos, *next;
1278 struct nfs4_stateid *local = NULL;
1279 u32 st_id = stid->si_stateownerid;
1280 u32 f_id = stid->si_fileid;
1281 unsigned int hashval = openstateid_hashval(st_id, f_id);
1283 list_for_each_safe(pos, next, &openstateid_hashtbl[hashval]) {
1284 local = list_entry(pos, struct nfs4_stateid, st_hash);
1285 if((local->st_stateid.si_stateownerid == st_id) &&
1286 (local->st_stateid.si_fileid == f_id))
1292 /* search ownerid_hashtbl[] for stateid owner (stateid->si_stateownerid) */
1293 struct nfs4_stateowner *
1294 find_stateowner_id(u32 st_id) {
1295 struct list_head *pos, *next;
1296 struct nfs4_stateowner *local = NULL;
1297 unsigned int hashval = ownerid_hashval(st_id);
1299 list_for_each_safe(pos, next, &ownerid_hashtbl[hashval]) {
1300 local = list_entry(pos, struct nfs4_stateowner, so_idhash);
1301 if(local->so_id == st_id)
1308 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
1310 return (fhp->fh_dentry != stp->st_vfs_file.f_dentry);
1314 STALE_STATEID(stateid_t *stateid)
1316 if (stateid->si_boot == boot_time)
1318 printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
1319 stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
1320 stateid->si_generation);
1326 * Checks for stateid operations
1329 nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct nfs4_stateid **stpp)
1331 struct nfs4_stateid *stp;
1334 dprintk("NFSD: preprocess_stateid_op:stateid = (%08x/%08x/%08x/%08x)\n",
1335 stateid->si_boot, stateid->si_stateownerid,
1336 stateid->si_fileid, stateid->si_generation);
1341 status = nfserr_stale_stateid;
1342 if (STALE_STATEID(stateid))
1346 status = nfserr_bad_stateid;
1347 if (!(stp = find_stateid(stateid))) {
1348 dprintk("NFSD: process stateid: no open stateid!\n");
1351 if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
1352 dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
1355 if (!stp->st_stateowner->so_confirmed) {
1356 dprintk("process_stateid: lockowner not confirmed yet!\n");
1359 if (stateid->si_generation > stp->st_stateid.si_generation) {
1360 dprintk("process_stateid: future stateid?!\n");
1365 status = nfserr_old_stateid;
1366 if (stateid->si_generation < stp->st_stateid.si_generation) {
1367 dprintk("process_stateid: old stateid!\n");
1372 renew_client(stp->st_stateowner->so_client);
1379 * Checks for sequence id mutating operations.
1381 * XXX need to code replay cache logic
1384 nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp)
1387 struct nfs4_stateid *stp;
1388 struct nfs4_stateowner *sop;
1390 dprintk("NFSD: preprocess_seqid_op: seqid=%d "
1391 "stateid = (%08x/%08x/%08x/%08x)\n", seqid,
1392 stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
1393 stateid->si_generation);
1398 status = nfserr_bad_stateid;
1399 if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
1400 printk("NFSD: preprocess_seqid_op: magic stateid!\n");
1404 status = nfserr_stale_stateid;
1405 if (STALE_STATEID(stateid))
1408 * We return BAD_STATEID if filehandle doesn't match stateid,
1409 * the confirmed flag is incorrecly set, or the generation
1410 * number is incorrect.
1411 * If there is no entry in the openfile table for this id,
1412 * we can't always return BAD_STATEID;
1413 * this might be a retransmitted CLOSE which has arrived after
1414 * the openfile has been released.
1416 if (!(stp = find_stateid(stateid)))
1417 goto no_nfs4_stateid;
1419 status = nfserr_bad_stateid;
1421 if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
1422 printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
1427 *sopp = sop = stp->st_stateowner;
1430 * We now validate the seqid and stateid generation numbers.
1431 * For the moment, we ignore the possibility of
1432 * generation number wraparound.
1434 if (seqid != sop->so_seqid + 1)
1437 if (sop->so_confirmed) {
1438 if (flags & CONFIRM) {
1439 printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");
1444 if (!(flags & CONFIRM)) {
1445 printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");
1449 if (stateid->si_generation > stp->st_stateid.si_generation) {
1450 printk("NFSD: preprocess_seqid_op: future stateid?!\n");
1454 status = nfserr_old_stateid;
1455 if (stateid->si_generation < stp->st_stateid.si_generation) {
1456 printk("NFSD: preprocess_seqid_op: old stateid!\n");
1459 /* XXX renew the client lease here */
1468 * We determine whether this is a bad stateid or a replay,
1469 * starting by trying to look up the stateowner.
1470 * If stateowner is not found - stateid is bad.
1472 if (!(sop = find_stateowner_id(stateid->si_stateownerid))) {
1473 printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
1474 status = nfserr_bad_stateid;
1479 status = nfserr_bad_seqid;
1480 if (seqid == sop->so_seqid) {
1481 printk("NFSD: preprocess_seqid_op: retransmission?\n");
1482 /* XXX will need to indicate replay to calling function here */
1484 printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
1490 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
1493 struct nfs4_stateowner *sop;
1494 struct nfs4_stateid *stp;
1496 dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
1497 current_fh->fh_dentry->d_name.len,
1498 current_fh->fh_dentry->d_name.name);
1499 oc->oc_stateowner = NULL;
1500 down(&client_sema); /* XXX need finer grained locking */
1502 if ((status = nfs4_preprocess_seqid_op(current_fh, oc->oc_seqid,
1503 &oc->oc_req_stateid,
1505 &oc->oc_stateowner, &stp)))
1508 sop = oc->oc_stateowner;
1509 sop->so_confirmed = 1;
1510 update_stateid(&stp->st_stateid);
1511 memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));
1512 /* XXX renew the client lease here */
1513 dprintk("NFSD: nfsd4_open_confirm: success, seqid=%d "
1514 "stateid=(%08x/%08x/%08x/%08x)\n", oc->oc_seqid,
1515 stp->st_stateid.si_boot,
1516 stp->st_stateid.si_stateownerid,
1517 stp->st_stateid.si_fileid,
1518 stp->st_stateid.si_generation);
1525 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
1528 struct nfs4_stateid *stp;
1530 dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n",
1531 current_fh->fh_dentry->d_name.len,
1532 current_fh->fh_dentry->d_name.name);
1534 down(&client_sema); /* XXX need finer grained locking */
1535 if ((status = nfs4_preprocess_seqid_op(current_fh, od->od_seqid,
1537 CHECK_FH, &od->od_stateowner, &stp)))
1540 status = nfserr_inval;
1541 if (od->od_share_access & ~stp->st_share_access) {
1542 dprintk("NFSD:access not a subset current=%08x, desired=%08x\n",
1543 stp->st_share_access, od->od_share_access);
1546 if (od->od_share_deny & ~stp->st_share_deny) {
1547 dprintk("NFSD:deny not a subset current=%08x, desired=%08x\n",
1548 stp->st_share_deny, od->od_share_deny);
1551 nfs4_file_downgrade(&stp->st_vfs_file,
1552 stp->st_share_access & ~od->od_share_access);
1553 stp->st_share_access = od->od_share_access;
1554 stp->st_share_deny = od->od_share_deny;
1555 update_stateid(&stp->st_stateid);
1556 memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
1564 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
1567 struct nfs4_stateid *stp;
1569 dprintk("NFSD: nfsd4_close on file %.*s\n",
1570 current_fh->fh_dentry->d_name.len,
1571 current_fh->fh_dentry->d_name.name);
1573 down(&client_sema); /* XXX need finer grained locking */
1574 if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid,
1577 &close->cl_stateowner, &stp)))
1580 * Return success, but first update the stateid.
1583 update_stateid(&stp->st_stateid);
1584 memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
1586 /* release_open_state() calls nfsd_close() if needed */
1587 release_open_state(stp);
1594 nfs4_state_init(void)
1600 for (i = 0; i < CLIENT_HASH_SIZE; i++) {
1601 INIT_LIST_HEAD(&conf_id_hashtbl[i]);
1602 INIT_LIST_HEAD(&conf_str_hashtbl[i]);
1603 INIT_LIST_HEAD(&unconf_str_hashtbl[i]);
1604 INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
1606 for (i = 0; i < FILE_HASH_SIZE; i++) {
1607 INIT_LIST_HEAD(&file_hashtbl[i]);
1609 for (i = 0; i < OWNER_HASH_SIZE; i++) {
1610 INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
1611 INIT_LIST_HEAD(&ownerid_hashtbl[i]);
1613 for (i = 0; i < OPENSTATEID_HASH_SIZE; i++) {
1614 INIT_LIST_HEAD(&openstateid_hashtbl[i]);
1616 memset(&zerostateid, 0, sizeof(stateid_t));
1617 memset(&onestateid, ~0, sizeof(stateid_t));
1619 INIT_LIST_HEAD(&client_lru);
1620 init_MUTEX(&client_sema);
1621 boot_time = get_seconds();
1622 INIT_WORK(&laundromat_work,laundromat_main, NULL);
1623 schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ);
1629 __nfs4_state_shutdown(void)
1632 struct nfs4_client *clp = NULL;
1634 for (i = 0; i < CLIENT_HASH_SIZE; i++) {
1635 while (!list_empty(&conf_id_hashtbl[i])) {
1636 clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
1639 while (!list_empty(&unconf_str_hashtbl[i])) {
1640 clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash);
1644 release_all_files();
1645 cancel_delayed_work(&laundromat_work);
1646 flush_scheduled_work();
1648 dprintk("NFSD: list_add_perfile %d list_del_perfile %d\n",
1649 list_add_perfile, list_del_perfile);
1650 dprintk("NFSD: add_perclient %d del_perclient %d\n",
1651 add_perclient, del_perclient);
1652 dprintk("NFSD: alloc_file %d free_file %d\n",
1653 alloc_file, free_file);
1654 dprintk("NFSD: alloc_sowner %d free_sowner %d\n",
1655 alloc_sowner, free_sowner);
1656 dprintk("NFSD: vfsopen %d vfsclose %d\n",
1661 nfs4_state_shutdown(void)
1664 __nfs4_state_shutdown();