commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.git] / fs / nfsd / nfs4state.c
1 /*
2 *  linux/fs/nfsd/nfs4state.c
3 *
4 *  Copyright (c) 2001 The Regents of the University of Michigan.
5 *  All rights reserved.
6 *
7 *  Kendrick Smith <kmsmith@umich.edu>
8 *  Andy Adamson <kandros@umich.edu>
9 *
10 *  Redistribution and use in source and binary forms, with or without
11 *  modification, are permitted provided that the following conditions
12 *  are met:
13 *
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.
22 *
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.
34 *
35 */
36
37 #include <linux/param.h>
38 #include <linux/major.h>
39 #include <linux/slab.h>
40
41
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>
50
51 #define NFSDDBG_FACILITY                NFSDDBG_PROC
52
53 /* Globals */
54 time_t boot_time;
55 static u32 current_clientid = 1;
56 static u32 current_ownerid;
57 static u32 current_fileid;
58 static u32 nfs4_init;
59 stateid_t zerostateid;             /* bits all 0 */
60 stateid_t onestateid;              /* bits all 1 */
61
62 /* debug counters */
63 u32 list_add_perfile = 0; 
64 u32 list_del_perfile = 0;
65 u32 add_perclient = 0;
66 u32 del_perclient = 0;
67 u32 alloc_file = 0;
68 u32 free_file = 0;
69 u32 alloc_sowner = 0;
70 u32 free_sowner = 0;
71 u32 vfsopen = 0;
72 u32 vfsclose = 0;
73
74 /* Locking:
75  *
76  * client_sema: 
77  *      protects clientid_hashtbl[], clientstr_hashtbl[],
78  *      unconfstr_hashtbl[], uncofid_hashtbl[].
79  */
80 static struct semaphore client_sema;
81
82 void
83 nfsd4_lock_state(void)
84 {
85         down(&client_sema);
86 }
87
88 void
89 nfsd4_unlock_state(void)
90 {
91         up(&client_sema);
92 }
93
94 static inline u32
95 opaque_hashval(const void *ptr, int nbytes)
96 {
97         unsigned char *cptr = (unsigned char *) ptr;
98
99         u32 x = 0;
100         while (nbytes--) {
101                 x *= 37;
102                 x += *cptr++;
103         }
104         return x;
105 }
106
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);
111
112
113 /* 
114  * SETCLIENTID state 
115  */
116
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)
121
122 #define clientid_hashval(id) \
123         ((id) & CLIENT_HASH_MASK)
124 #define clientstr_hashval(name, namelen) \
125         (opaque_hashval((name), (namelen)) & CLIENT_HASH_MASK)
126
127 /* conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed
128  * setclientid_confirmed info. 
129  *
130  * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed 
131  * setclientid info.
132  *
133  * client_lru holds client queue ordered by nfs4_client.cl_time
134  * for lease renewal.
135  */
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;
141
142 static inline void
143 renew_client(struct nfs4_client *clp)
144 {
145         /*
146         * Move client to the end to the LRU list.
147         */
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();
153 }
154
155 /* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
156 static int
157 STALE_CLIENTID(clientid_t *clid)
158 {
159         if (clid->cl_boot == boot_time)
160                 return 0;
161         dprintk("NFSD stale clientid (%08x/%08x)\n", 
162                         clid->cl_boot, clid->cl_id);
163         return 1;
164 }
165
166 /* 
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.
170  */
171 static inline struct nfs4_client *
172 alloc_client(struct xdr_netobj name)
173 {
174         struct nfs4_client *clp;
175
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;
181                 }
182                 else {
183                         kfree(clp);
184                         clp = NULL;
185                 }
186         }
187         return clp;
188 }
189
190 static inline void
191 free_client(struct nfs4_client *clp)
192 {
193         kfree(clp->cl_name.data);
194         kfree(clp);
195 }
196
197 static void
198 expire_client(struct nfs4_client *clp)
199 {
200         struct nfs4_stateowner *sop;
201
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);
209         }
210         free_client(clp);
211 }
212
213 static struct nfs4_client *
214 create_client(struct xdr_netobj name) {
215         struct nfs4_client *clp;
216
217         if(!(clp = alloc_client(name)))
218                 goto out;
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);
223 out:
224         return clp;
225 }
226
227 static void
228 copy_verf(struct nfs4_client *target, nfs4_verifier source) {
229         memcpy(&target->cl_verifier, source, sizeof(nfs4_verifier));
230 }
231
232 static void
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; 
236 }
237
238 static void
239 copy_cred(struct svc_cred *target, struct svc_cred *source) {
240         int i;
241
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];
246 }
247
248 static int
249 cmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) {
250         if(!n1 || !n2)
251                 return 0;
252         return((n1->len == n2->len) && !memcmp(n1->data, n2->data, n2->len));
253 }
254
255 static int
256 cmp_verf(nfs4_verifier v1, nfs4_verifier v2) {
257         return(!memcmp(v1,v2,sizeof(nfs4_verifier)));
258 }
259
260 static int
261 cmp_clid(clientid_t * cl1, clientid_t * cl2) {
262         return((cl1->cl_boot == cl2->cl_boot) &&
263                 (cl1->cl_id == cl2->cl_id));
264 }
265
266 /* XXX what about NGROUP */
267 static int
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));
271
272 }
273
274 static void
275 gen_clid(struct nfs4_client *clp) {
276         clp->cl_clientid.cl_boot = boot_time;
277         clp->cl_clientid.cl_id = current_clientid++; 
278 }
279
280 static void
281 gen_confirm(struct nfs4_client *clp) {
282         struct timespec         tv;
283         u32 *                   p;
284
285         tv = CURRENT_TIME;
286         p = (u32 *)clp->cl_confirm;
287         *p++ = tv.tv_sec;
288         *p++ = tv.tv_nsec;
289 }
290
291 static int
292 check_name(struct xdr_netobj name) {
293
294         if (name.len == 0) 
295                 return 0;
296         if (name.len > NFS4_OPAQUE_LIMIT) {
297                 printk("NFSD: check_name: name too long(%d)!\n", name.len);
298                 return 0;
299         }
300         return 1;
301 }
302
303 void
304 add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
305 {
306         unsigned int idhashval;
307
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();
313 }
314
315 void
316 move_to_confirmed(struct nfs4_client *clp, unsigned int idhashval)
317 {
318         unsigned int strhashval;
319
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, 
325                         clp->cl_name.len);
326         list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
327         renew_client(clp);
328 }
329
330 /*
331  * RFC 3010 has a complex implmentation description of processing a 
332  * SETCLIENTID request consisting of 5 bullets, labeled as 
333  * CASE0 - CASE4 below.
334  *
335  * NOTES:
336  *      callback information will be processed in a future patch
337  *
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
344  *              name and principal
345  *
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.
354  *
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.
361  *
362  */
363 int
364 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
365 {
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,
370         };
371         char *                  clverifier = setclid->se_verf;
372         unsigned int            strhashval;
373         struct nfs4_client *    conf, * unconf, * new, * clp;
374         int                     status;
375         struct list_head *pos, *next;
376         
377         status = nfserr_inval;
378         if (!check_name(clname))
379                 goto out;
380
381         /* 
382          * XXX The Duplicate Request Cache (DRC) has been checked (??)
383          * We get here on a DRC miss.
384          */
385
386         strhashval = clientstr_hashval(clname.data, clname.len);
387
388         conf = NULL;
389         down(&client_sema);
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))
393                         continue;
394                 /* 
395                  * CASE 0:
396                  * clname match, confirmed, different principal
397                  * or different ip_address
398                  */
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);
404                         goto out;
405                 }
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);
410                         goto out;
411                 }
412
413                 /* 
414                  * cl_name match from a previous SETCLIENTID operation
415                  * XXX check for additional matches?
416                  */
417                 conf = clp;
418                 break;
419         }
420         unconf = NULL;
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))
424                         continue;
425                 /* cl_name match from a previous SETCLIENTID operation */
426                 unconf = clp;
427                 break;
428         }
429         status = nfserr_resource;
430         if (!conf) {
431                 /* 
432                  * CASE 4:
433                  * placed first, because it is the normal case.
434                  */
435                 if (unconf)
436                         expire_client(unconf);
437                 if (!(new = create_client(clname)))
438                         goto out;
439                 copy_verf(new,clverifier);
440                 new->cl_addr = ip_addr;
441                 copy_cred(&new->cl_cred,&rqstp->rq_cred);
442                 gen_clid(new);
443                 gen_confirm(new);
444                 add_to_unconfirmed(new, strhashval);
445         } else if (cmp_verf(conf->cl_verifier, clverifier)) {
446                 /*
447                  * CASE 1:
448                  * cl_name match, confirmed, principal match
449                  * verifier match: probable callback update
450                  *
451                  * remove any unconfirmed nfs4_client with 
452                  * matching cl_name, cl_verifier, and cl_clientid
453                  *
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 
457                  * new cl_confirm
458                  */
459                 if ((unconf) && 
460                     cmp_verf(unconf->cl_verifier, conf->cl_verifier) &&
461                      cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) {
462                                 expire_client(unconf);
463                 }
464                 if (!(new = create_client(clname)))
465                         goto out;
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);
470                 gen_confirm(new);
471                 add_to_unconfirmed(new,strhashval);
472         } else if (!unconf) {
473                 /*
474                  * CASE 2:
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.
480                  */
481                 if (!(new = create_client(clname)))
482                         goto out;
483                 copy_verf(new,clverifier);
484                 new->cl_addr = ip_addr;
485                 copy_cred(&new->cl_cred,&rqstp->rq_cred);
486                 gen_clid(new);
487                 gen_confirm(new);
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)) {
491                 /*      
492                  * CASE3:
493                  * confirmed found (name, principal match)
494                  * confirmed verifier does not match input clverifier
495                  *
496                  * unconfirmed found (name match)
497                  * confirmed->cl_clientid != unconfirmed->cl_clientid and
498                  * confirmed->cl_confirm != unconfirmed->cl_confirm
499                  *
500                  * remove unconfirmed.
501                  *
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
506                  */
507                 expire_client(unconf);
508                 if (!(new = create_client(clname)))
509                         goto out;
510                 copy_verf(new,clverifier);
511                 new->cl_addr = ip_addr;
512                 copy_cred(&new->cl_cred,&rqstp->rq_cred);
513                 gen_clid(new);
514                 gen_confirm(new);
515                 add_to_unconfirmed(new, strhashval);
516         } else {
517                 /* No cases hit !!! */
518                 status = nfserr_inval;
519                 goto out;
520
521         }
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");
526         status = nfs_ok;
527 out:
528         up(&client_sema);
529         return status;
530 }
531
532
533 /*
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.
537  *
538  * NOTE: callback information will be processed here in a future patch
539  */
540 int
541 nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
542 {
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;
549         int status;
550
551         status = nfserr_stale_clientid;
552         if (STALE_CLIENTID(clid))
553                 goto out;
554         /* 
555          * XXX The Duplicate Request Cache (DRC) has been checked (??)
556          * We get here on a DRC miss.
557          */
558
559         idhashval = clientid_hashval(clid->cl_id);
560         down(&client_sema);
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))
564                         continue;
565
566                 status = nfserr_inval;
567                 /* 
568                  * Found a record for this clientid. If the IP addresses
569                  * don't match, return ERR_INVAL just as if the record had
570                  * not been found.
571                  */
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);
576                         goto out;
577                 }
578                 conf = clp;
579                 break;
580         }
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))
584                         continue;
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);
590                         goto out;
591                 }
592                 unconf = clp;
593                 break;
594         }
595         /* CASE 1: 
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 
599         */
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;
607                 else {
608                         expire_client(conf);
609                         move_to_confirmed(unconf, idhashval);
610                         status = nfs_ok;
611                 }
612                 goto out;
613         } 
614         /* CASE 2:
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.
618          */
619         if ((conf && !unconf) || 
620             ((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;
625                 } else {
626                         status = nfs_ok;
627                 }
628                 goto out;
629         }
630         /* CASE 3:
631          * conf record not found.
632          * unconf record found. 
633          * unconf->cl_confirm matches input confirm
634          */ 
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;
638                 } else {
639                         status = nfs_ok;
640                         move_to_confirmed(unconf, idhashval);
641                 }
642                 goto out;
643         }
644         /* CASE 4:
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.
649          */
650         if ((!conf || (conf && !cmp_verf(conf->cl_confirm, confirm))) &&
651             (!unconf || (unconf && !cmp_verf(unconf->cl_confirm, confirm)))) {
652                 status = nfserr_stale_clientid;
653                 goto out;
654         }
655         /* check that we have hit one of the cases...*/
656         status = nfserr_inval;
657         goto out;
658 out:
659         /* XXX if status == nfs_ok, probe callback path */
660         up(&client_sema);
661         return status;
662 }
663
664 /* 
665  * Open owner state (share locks)
666  */
667
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)
672
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)
677
678 static struct list_head ownerid_hashtbl[OWNER_HASH_SIZE];
679 static struct list_head ownerstr_hashtbl[OWNER_HASH_SIZE];
680
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)
689
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)
694
695 static struct list_head file_hashtbl[FILE_HASH_SIZE];
696 static struct list_head openstateid_hashtbl[OPENSTATEID_HASH_SIZE];
697
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++;
708                 alloc_file++;
709                 return fp;
710         }
711         return (struct nfs4_file *)NULL;
712 }
713
714 static void
715 release_all_files(void)
716 {
717         int i;
718         struct nfs4_file *fp;
719
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);
726                         }
727                         release_file(fp);
728                 }
729         }
730 }
731
732 static inline struct nfs4_stateowner *
733 alloc_stateowner(struct xdr_netobj *owner)
734 {
735         struct nfs4_stateowner *sop;
736
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;
741                         return sop;
742                 } 
743                 kfree(sop);
744         }
745         return (struct nfs4_stateowner *)NULL;
746 }
747
748 /* should use a slab cache */
749 static void
750 free_stateowner(struct nfs4_stateowner *sop) {
751         if(sop) {
752                 kfree(sop->so_owner.data);
753                 kfree(sop);
754                 sop = NULL;
755                 free_sowner++;
756         }
757 }
758
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;
763
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);
774         add_perclient++;
775         sop->so_id = current_ownerid++;
776         sop->so_client = clp;
777         sop->so_seqid = open->op_seqid;
778         sop->so_confirmed = 0;
779         alloc_sowner++;
780         return sop;
781 }
782
783 static void
784 release_stateowner(struct nfs4_stateowner *sop)
785 {
786         struct nfs4_stateid *stp;
787
788         list_del_init(&sop->so_idhash);
789         list_del_init(&sop->so_strhash);
790         list_del_init(&sop->so_perclient);
791         del_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);
796         }
797         free_stateowner(sop);
798 }
799
800 static inline void
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);
803
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);
809         list_add_perfile++;
810         list_add(&stp->st_perfile, &fp->fi_perfile);
811         stp->st_stateowner = sop;
812         stp->st_file = fp;
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;
819 }
820
821 static void
822 release_stateid(struct nfs4_stateid *stp) {
823
824         list_del_init(&stp->st_hash);
825         list_del_perfile++;
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);
830                 vfsclose++;
831                 dput(stp->st_vfs_file.f_dentry);
832                 mntput(stp->st_vfs_file.f_vfsmnt);
833         }
834         /* should use a slab cache */
835         kfree(stp);
836         stp = NULL;
837 }
838
839 static void
840 release_file(struct nfs4_file *fp)
841 {
842         free_file++;
843         list_del_init(&fp->fi_hash);
844         kfree(fp);
845 }       
846
847 void
848 release_open_state(struct nfs4_stateid *stp)
849 {
850         struct nfs4_stateowner *sop = stp->st_stateowner;
851         struct nfs4_file *fp = stp->st_file;
852
853         dprintk("NFSD: release_open_state\n");
854         release_stateid(stp);
855         /*
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
860          */
861         if (sop->so_confirmed && list_empty(&sop->so_peropenstate)) {
862                 release_stateowner(sop);
863         }
864         /* unused nfs4_file's are releseed. XXX slab cache? */
865         if (list_empty(&fp->fi_perfile)) {
866                 release_file(fp);
867         }
868 }
869
870 static int
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));
875 }
876
877 /* search ownerstr_hashtbl[] for owner */
878 static int
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;
882
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)) 
886                         continue;
887                 *op = local;
888                 return(1);
889         }
890         return 0;
891 }
892
893 /* see if clientid is in confirmed hash table */
894 static int
895 verify_clientid(struct nfs4_client **client, clientid_t *clid) {
896
897         struct list_head *pos, *next;
898         struct nfs4_client *clp;
899         unsigned int idhashval = clientid_hashval(clid->cl_id);
900
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))
904                         continue;
905                 *client = clp;
906                 return 1;
907         }
908         *client = NULL;
909         return 0;
910 }
911
912 /* search file_hashtbl[] for file */
913 static int
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;
917
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))) {
921                         *fp = local;
922                         return(1);
923                 }
924         }
925         return 0;
926 }
927
928 static int
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)) {
932                 return 0;
933         }
934         return 1;
935 }
936
937 static inline void
938 nfs4_init_ino(nfs4_ino_desc_t *ino, struct svc_fh *fhp)
939 {
940         struct inode *inode;
941         if (!fhp->fh_dentry)
942                 BUG();
943         inode = fhp->fh_dentry->d_inode;
944         if (!inode)
945                 BUG();
946         ino->dev = inode->i_sb->s_dev;
947         ino->ino = inode->i_ino;
948         ino->generation = inode->i_generation;
949 }
950
951 int
952 nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
953 {
954         nfs4_ino_desc_t ino;
955         unsigned int fi_hashval;
956         struct nfs4_file *fp;
957         struct nfs4_stateid *stp;
958         struct list_head *pos, *next;
959
960         dprintk("NFSD: nfs4_share_conflict\n");
961
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;
970                 }
971         }
972         return nfs_ok;
973 }
974
975 static inline int
976 nfs4_file_upgrade(struct file *filp, unsigned int share_access)
977 {
978 int status;
979
980         if (share_access & NFS4_SHARE_ACCESS_WRITE) {
981                 status = get_write_access(filp->f_dentry->d_inode);
982                 if (!status)
983                         filp->f_mode = FMODE_WRITE;
984                 else
985                         return nfserrno(status);
986         }
987         return nfs_ok;
988 }
989
990 static inline void
991 nfs4_file_downgrade(struct file *filp, unsigned int share_access)
992 {
993         if (share_access & NFS4_SHARE_ACCESS_WRITE) {
994                 put_write_access(filp->f_dentry->d_inode);
995                 filp->f_mode = FMODE_READ;
996         }
997 }
998
999
1000 /*
1001  * nfsd4_process_open1()
1002  *      lookup stateowner.
1003  *              found:
1004  *                      check confirmed 
1005  *                              confirmed:
1006  *                                      check seqid
1007  *                              not confirmed:
1008  *                                      delete owner
1009  *                                      create new owner
1010  *              notfound:
1011  *                      verify clientid
1012  *                      create new owner
1013  */
1014 int
1015 nfsd4_process_open1(struct nfsd4_open *open)
1016 {
1017         int status;
1018         clientid_t *clientid = &open->op_clientid;
1019         struct nfs4_client *clp = NULL;
1020         unsigned int strhashval;
1021         struct nfs4_stateowner *sop = NULL;
1022
1023         status = nfserr_inval;
1024         if (!check_name(open->op_owner))
1025                 goto out;
1026
1027         status = nfserr_stale_clientid;
1028         if (STALE_CLIENTID(&open->op_clientid))
1029                 goto out;
1030
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;
1038                         goto out;
1039                 }
1040                 if (sop->so_confirmed) {
1041                         if (open->op_seqid == sop->so_seqid + 1) { 
1042                                 status = nfs_ok;
1043                                 goto renew;
1044                         } 
1045                         status = nfserr_bad_seqid;
1046                         goto out;
1047                 }
1048                 /* If we get here, we received and OPEN for an unconfirmed
1049                  * nfs4_stateowner. If seqid's are the same then this 
1050                  * is a replay.
1051                  * If the sequid's are different, then purge the 
1052                  * existing nfs4_stateowner, and instantiate a new one.
1053                  */
1054                 clp = sop->so_client;
1055                 release_stateowner(sop);
1056                 goto instantiate_new_owner;
1057         } 
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.
1062         *
1063         * XXX compare clp->cl_addr with rqstp addr? 
1064         */
1065         status = nfserr_expired;
1066         if (!verify_clientid(&clp, clientid))
1067                 goto out;
1068 instantiate_new_owner:
1069         status = nfserr_resource;
1070         if (!(sop = alloc_init_stateowner(strhashval, clp, open))) 
1071                 goto out;
1072         open->op_stateowner = sop;
1073         status = nfs_ok;
1074 renew:
1075         renew_client(sop->so_client);
1076 out:
1077         up(&client_sema); /*XXX need finer grained locking */
1078         return status;
1079 }
1080
1081 int
1082 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
1083 {
1084         struct iattr iattr;
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;
1091         int status;
1092
1093         status = nfserr_resource;
1094         if (!sop)
1095                 goto out;
1096
1097         nfs4_init_ino(&ino, current_fh);
1098
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) {
1107                                 stp = stq;
1108                                 continue;
1109                         }
1110                         if (!test_share(stq,open))      
1111                                 goto out;
1112                 }
1113         } else {
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)
1117                         goto out;
1118         }
1119
1120         if (!stp) {
1121                 int flags = 0;
1122
1123                 status = nfserr_resource;
1124                 if ((stp = kmalloc(sizeof(struct nfs4_stateid),
1125                                                 GFP_KERNEL)) == NULL)
1126                         goto out;
1127
1128                 if (open->op_share_access && NFS4_SHARE_ACCESS_WRITE)
1129                         flags = MAY_WRITE;
1130                 else
1131                         flags = MAY_READ;
1132                 if ((status = nfsd_open(rqstp, current_fh,  S_IFREG,
1133                                               flags,
1134                                               &stp->st_vfs_file)) != 0)
1135                         goto out_free;
1136
1137                 vfsopen++;
1138                 dget(stp->st_vfs_file.f_dentry);
1139                 mntget(stp->st_vfs_file.f_vfsmnt);
1140
1141                 init_stateid(stp, fp, sop, open);
1142                 stp->st_vfs_set = 1;
1143         } else {
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;
1148
1149                 share_access &= ~(stp->st_share_access);
1150
1151                 /* update the struct file */
1152                 if ((status = nfs4_file_upgrade(&stp->st_vfs_file, share_access)))
1153                         goto out;
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);
1158         }
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);
1162
1163         if (open->op_truncate) {
1164                 iattr.ia_valid = ATTR_SIZE;
1165                 iattr.ia_size = 0;
1166                 status = nfsd_setattr(rqstp, current_fh, &iattr, 0, (time_t)0);
1167                 if (status)
1168                         goto out;
1169         }
1170         memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));
1171
1172         open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
1173         status = nfs_ok;
1174 out:
1175         /*
1176         * To finish the open response, we just need to set the rflags.
1177         */
1178         open->op_rflags = 0;
1179         if (!open->op_stateowner->so_confirmed)
1180                 open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
1181
1182         up(&client_sema); /*XXX need finer grained locking */
1183         return status;
1184 out_free:
1185         kfree(stp);
1186         goto out;
1187 }
1188 static struct work_struct laundromat_work;
1189 static void laundromat_main(void *);
1190 static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
1191
1192 int 
1193 nfsd4_renew(clientid_t *clid)
1194 {
1195         struct nfs4_client *clp;
1196         struct list_head *pos, *next;
1197         unsigned int idhashval;
1198         int status;
1199
1200         down(&client_sema);
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))
1205                 goto out;
1206         status = nfs_ok;
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))
1211                         continue;
1212                 renew_client(clp);
1213                 goto out;
1214         }
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))
1218                         continue;
1219                 renew_client(clp);
1220         goto out;
1221         }
1222         /*
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.
1226         */
1227         printk("nfsd4_renew: clientid not found!\n");
1228         status = nfserr_expired;
1229 out:
1230         up(&client_sema);
1231         return status;
1232 }
1233
1234 time_t
1235 nfs4_laundromat(void)
1236 {
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;
1241
1242         down(&client_sema);
1243
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;
1249                         if (return_val > t)
1250                                 return_val = t;
1251                         break;
1252                 }
1253                 dprintk("NFSD: purging unused client (clientid %08x)\n",
1254                         clp->cl_clientid.cl_id);
1255                 expire_client(clp);
1256         }
1257         if (return_val < NFSD_LAUNDROMAT_MINTIMEOUT)
1258                 return_val = NFSD_LAUNDROMAT_MINTIMEOUT;
1259         up(&client_sema); 
1260         return return_val;
1261 }
1262
1263 void
1264 laundromat_main(void *not_used)
1265 {
1266         time_t t;
1267
1268         t = nfs4_laundromat();
1269         dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
1270         schedule_delayed_work(&laundromat_work, t*HZ);
1271 }
1272
1273 /* search openstateid_hashtbl[] for stateid */
1274 struct nfs4_stateid *
1275 find_stateid(stateid_t *stid)
1276 {
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);
1282
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))
1287                         return local;
1288         }
1289         return NULL;
1290 }
1291
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);
1298
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)
1302                         return local;
1303         }
1304         return NULL;
1305 }
1306
1307 static inline int
1308 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
1309 {
1310         return (fhp->fh_dentry != stp->st_vfs_file.f_dentry);
1311 }
1312
1313 static int
1314 STALE_STATEID(stateid_t *stateid)
1315 {
1316         if (stateid->si_boot == boot_time)
1317                 return 0;
1318         printk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n",
1319                 stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
1320                 stateid->si_generation);
1321         return 1;
1322 }
1323
1324
1325 /*
1326 * Checks for stateid operations
1327 */
1328 int
1329 nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct nfs4_stateid **stpp)
1330 {
1331         struct nfs4_stateid *stp;
1332         int status;
1333
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); 
1337
1338         *stpp = NULL;
1339
1340         /* STALE STATEID */
1341         status = nfserr_stale_stateid;
1342         if (STALE_STATEID(stateid)) 
1343                 goto out;
1344
1345         /* BAD STATEID */
1346         status = nfserr_bad_stateid;
1347         if (!(stp = find_stateid(stateid))) {
1348                 dprintk("NFSD: process stateid: no open stateid!\n");
1349                 goto out;
1350         }
1351         if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
1352                 dprintk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
1353                 goto out;
1354         }
1355         if (!stp->st_stateowner->so_confirmed) {
1356                 dprintk("process_stateid: lockowner not confirmed yet!\n");
1357                 goto out;
1358         }
1359         if (stateid->si_generation > stp->st_stateid.si_generation) {
1360                 dprintk("process_stateid: future stateid?!\n");
1361                 goto out;
1362         }
1363
1364         /* OLD STATEID */
1365         status = nfserr_old_stateid;
1366         if (stateid->si_generation < stp->st_stateid.si_generation) {
1367                 dprintk("process_stateid: old stateid!\n");
1368                 goto out;
1369         }
1370         *stpp = stp;
1371         status = nfs_ok;
1372         renew_client(stp->st_stateowner->so_client);
1373 out:
1374         return status;
1375 }
1376
1377
1378 /* 
1379  * Checks for sequence id mutating operations. 
1380  *
1381  * XXX need to code replay cache logic
1382  */
1383 int
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)
1385 {
1386         int status;
1387         struct nfs4_stateid *stp;
1388         struct nfs4_stateowner *sop;
1389
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);
1394                                 
1395         *stpp = NULL;
1396         *sopp = NULL;
1397
1398         status = nfserr_bad_stateid;
1399         if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
1400                 printk("NFSD: preprocess_seqid_op: magic stateid!\n");
1401                 goto out;
1402         }
1403
1404         status = nfserr_stale_stateid;
1405         if (STALE_STATEID(stateid))
1406                 goto out;
1407         /*
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.
1415         */
1416         if (!(stp = find_stateid(stateid)))
1417                 goto no_nfs4_stateid;
1418
1419         status = nfserr_bad_stateid;
1420
1421         if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
1422                 printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
1423                 goto out;
1424         }
1425
1426         *stpp = stp;
1427         *sopp = sop = stp->st_stateowner;
1428
1429         /*
1430         *  We now validate the seqid and stateid generation numbers.
1431         *  For the moment, we ignore the possibility of 
1432         *  generation number wraparound.
1433         */
1434         if (seqid != sop->so_seqid + 1)
1435                 goto check_replay;
1436
1437         if (sop->so_confirmed) {
1438                 if (flags & CONFIRM) {
1439                         printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");
1440                         goto out;
1441                 }
1442         }
1443         else {
1444                 if (!(flags & CONFIRM)) {
1445                         printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");
1446                         goto out;
1447                 }
1448         }
1449         if (stateid->si_generation > stp->st_stateid.si_generation) {
1450                 printk("NFSD: preprocess_seqid_op: future stateid?!\n");
1451                 goto out;
1452         }
1453
1454         status = nfserr_old_stateid;
1455         if (stateid->si_generation < stp->st_stateid.si_generation) {
1456                 printk("NFSD: preprocess_seqid_op: old stateid!\n");
1457                 goto out;
1458         }
1459         /* XXX renew the client lease here */
1460         status = nfs_ok;
1461
1462 out:
1463         return status;
1464
1465 no_nfs4_stateid:
1466
1467         /*
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.
1471         */
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;
1475                 goto out;
1476         }
1477
1478 check_replay:
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 */
1483         } else 
1484                 printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
1485
1486         goto out;
1487 }
1488
1489 int
1490 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
1491 {
1492         int status;
1493         struct nfs4_stateowner *sop;
1494         struct nfs4_stateid *stp;
1495
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 */
1501
1502         if ((status = nfs4_preprocess_seqid_op(current_fh, oc->oc_seqid,
1503                                         &oc->oc_req_stateid,
1504                                         CHECK_FH | CONFIRM,
1505                                         &oc->oc_stateowner, &stp)))
1506                 goto out; 
1507
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);
1519         status = nfs_ok;
1520 out:
1521         up(&client_sema);
1522         return status;
1523 }
1524 int
1525 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
1526 {
1527         int status;
1528         struct nfs4_stateid *stp;
1529
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);
1533
1534         down(&client_sema); /* XXX need finer grained locking */
1535         if ((status = nfs4_preprocess_seqid_op(current_fh, od->od_seqid, 
1536                                         &od->od_stateid, 
1537                                         CHECK_FH, &od->od_stateowner, &stp)))
1538                 goto out; 
1539
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); 
1544                 goto out;
1545         }
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);
1549                 goto out;
1550         }
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));
1557         status = nfs_ok;
1558 out:
1559         up(&client_sema);
1560         return status;
1561 }
1562
1563 int
1564 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
1565 {
1566         int status;
1567         struct nfs4_stateid *stp;
1568
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);
1572
1573         down(&client_sema); /* XXX need finer grained locking */
1574         if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid, 
1575                                         &close->cl_stateid, 
1576                                         CHECK_FH, 
1577                                         &close->cl_stateowner, &stp)))
1578                 goto out; 
1579         /*
1580         *  Return success, but first update the stateid.
1581         */
1582         status = nfs_ok;
1583         update_stateid(&stp->st_stateid);
1584         memcpy(&close->cl_stateid, &stp->st_stateid, sizeof(stateid_t));
1585
1586         /* release_open_state() calls nfsd_close() if needed */
1587         release_open_state(stp);
1588 out:
1589         up(&client_sema);
1590         return status;
1591 }
1592
1593 void 
1594 nfs4_state_init(void)
1595 {
1596         int i;
1597
1598         if (nfs4_init)
1599                 return;
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]);
1605         }
1606         for (i = 0; i < FILE_HASH_SIZE; i++) {
1607                 INIT_LIST_HEAD(&file_hashtbl[i]);
1608         }
1609         for (i = 0; i < OWNER_HASH_SIZE; i++) {
1610                 INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
1611                 INIT_LIST_HEAD(&ownerid_hashtbl[i]);
1612         }
1613         for (i = 0; i < OPENSTATEID_HASH_SIZE; i++) {
1614                 INIT_LIST_HEAD(&openstateid_hashtbl[i]);
1615         }
1616         memset(&zerostateid, 0, sizeof(stateid_t));
1617         memset(&onestateid, ~0, sizeof(stateid_t));
1618
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);
1624         nfs4_init = 1;
1625
1626 }
1627
1628 static void
1629 __nfs4_state_shutdown(void)
1630 {
1631         int i;
1632         struct nfs4_client *clp = NULL;
1633
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);
1637                         expire_client(clp);
1638                 }
1639                 while (!list_empty(&unconf_str_hashtbl[i])) {
1640                         clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash);
1641                         expire_client(clp);
1642                 }
1643         }
1644         release_all_files();
1645         cancel_delayed_work(&laundromat_work);
1646         flush_scheduled_work();
1647         nfs4_init = 0;
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",
1657                         vfsopen, vfsclose);
1658 }
1659
1660 void
1661 nfs4_state_shutdown(void)
1662 {
1663         down(&client_sema);
1664         __nfs4_state_shutdown();
1665         up(&client_sema);
1666 }