Whamcloud - gitweb
Branch: HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / linux-2.6.7-CITI_NFS4_ALL-7-lsec.patch
1 --- linux-2.6.7/Documentation/filesystems/00-INDEX.lsec 2004-06-15 23:20:26.000000000 -0600
2 +++ linux-2.6.7/Documentation/filesystems/00-INDEX      2005-03-23 14:28:24.576313528 -0700
3 @@ -28,6 +28,8 @@ jfs.txt
4         - info and mount options for the JFS filesystem.
5  ncpfs.txt
6         - info on Novell Netware(tm) filesystem using NCP protocol.
7 +nfs4.txt
8 +       - info and mount options for the nfs4 filesystem.
9  ntfs.txt
10         - info and mount options for the NTFS filesystem (Windows NT).
11  proc.txt
12 --- linux-2.6.7/Documentation/filesystems/nfs4.txt.lsec 2005-03-23 14:28:24.576313528 -0700
13 +++ linux-2.6.7/Documentation/filesystems/nfs4.txt      2005-03-23 14:28:24.576313528 -0700
14 @@ -0,0 +1,20 @@
15 +NFS version 4
16 +=============
17 +
18 +NFS version 4 is specified by RFC3530.  Compared to earlier NFS versions,
19 +it provides enhanced security and better client caching, among other features.
20 +
21 +In addition to basic file operations, the NFS client supports locking, kerberos
22 +(basic authentication and integrity), and reboot recovery.
23 +
24 +As this writing (July 2004), patches to nfs-utils and util-linux are required
25 +for NFSv4 support; see http://www.citi.umich.edu/projects/nfsv4/linux/ for
26 +patches and instructions.
27 +
28 +The kernel treats NFS version 4 as a separate filesystem type, nfs4, so it is
29 +mounted using "mount -tnfs4 server:/path /mntpoint", not by mounting the nfs
30 +filesystem with -onfsver=4.
31 +
32 +Mount options:
33 +
34 +XXX?
35 --- linux-2.6.7/fs/locks.c.lsec 2004-06-15 23:20:03.000000000 -0600
36 +++ linux-2.6.7/fs/locks.c      2005-03-23 14:28:22.425640480 -0700
37 @@ -317,7 +317,7 @@ static int flock_to_posix_lock(struct fi
38         if (l->l_len == 0)
39                 fl->fl_end = OFFSET_MAX;
40         
41 -       fl->fl_owner = current->files;
42 +       fl->fl_owner = 0;
43         fl->fl_pid = current->tgid;
44         fl->fl_file = filp;
45         fl->fl_flags = FL_POSIX;
46 @@ -357,7 +357,7 @@ static int flock64_to_posix_lock(struct 
47         if (l->l_len == 0)
48                 fl->fl_end = OFFSET_MAX;
49         
50 -       fl->fl_owner = current->files;
51 +       fl->fl_owner = 0;
52         fl->fl_pid = current->tgid;
53         fl->fl_file = filp;
54         fl->fl_flags = FL_POSIX;
55 @@ -920,7 +920,7 @@ int posix_lock_file(struct file *filp, s
56   */
57  int locks_mandatory_locked(struct inode *inode)
58  {
59 -       fl_owner_t owner = current->files;
60 +       unsigned int pid = current->tgid;
61         struct file_lock *fl;
62  
63         /*
64 @@ -930,7 +930,9 @@ int locks_mandatory_locked(struct inode 
65         for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
66                 if (!IS_POSIX(fl))
67                         continue;
68 -               if (fl->fl_owner != owner)
69 +               if (fl->fl_owner != 0)
70 +                       break;
71 +               if (fl->fl_pid != pid)
72                         break;
73         }
74         unlock_kernel();
75 @@ -958,7 +960,7 @@ int locks_mandatory_area(int read_write,
76         int error;
77  
78         locks_init_lock(&fl);
79 -       fl.fl_owner = current->files;
80 +       fl.fl_owner = 0;
81         fl.fl_pid = current->tgid;
82         fl.fl_file = filp;
83         fl.fl_flags = FL_POSIX | FL_ACCESS;
84 @@ -1684,7 +1686,7 @@ void locks_remove_posix(struct file *fil
85         lock_kernel();
86         while (*before != NULL) {
87                 struct file_lock *fl = *before;
88 -               if (IS_POSIX(fl) && (fl->fl_owner == owner)) {
89 +               if (IS_POSIX(fl) && posix_same_owner(fl, &lock)) {
90                         locks_delete_lock(before);
91                         continue;
92                 }
93 @@ -1982,18 +1984,6 @@ int lock_may_write(struct inode *inode, 
94  
95  EXPORT_SYMBOL(lock_may_write);
96  
97 -static inline void __steal_locks(struct file *file, fl_owner_t from)
98 -{
99 -       struct inode *inode = file->f_dentry->d_inode;
100 -       struct file_lock *fl = inode->i_flock;
101 -
102 -       while (fl) {
103 -               if (fl->fl_file == file && fl->fl_owner == from)
104 -                       fl->fl_owner = current->files;
105 -               fl = fl->fl_next;
106 -       }
107 -}
108 -
109  /* When getting ready for executing a binary, we make sure that current
110   * has a files_struct on its own. Before dropping the old files_struct,
111   * we take over ownership of all locks for all file descriptors we own.
112 @@ -2002,31 +1992,6 @@ static inline void __steal_locks(struct 
113   */
114  void steal_locks(fl_owner_t from)
115  {
116 -       struct files_struct *files = current->files;
117 -       int i, j;
118 -
119 -       if (from == files)
120 -               return;
121 -
122 -       lock_kernel();
123 -       j = 0;
124 -       for (;;) {
125 -               unsigned long set;
126 -               i = j * __NFDBITS;
127 -               if (i >= files->max_fdset || i >= files->max_fds)
128 -                       break;
129 -               set = files->open_fds->fds_bits[j++];
130 -               while (set) {
131 -                       if (set & 1) {
132 -                               struct file *file = files->fd[i];
133 -                               if (file)
134 -                                       __steal_locks(file, from);
135 -                       }
136 -                       i++;
137 -                       set >>= 1;
138 -               }
139 -       }
140 -       unlock_kernel();
141  }
142  EXPORT_SYMBOL(steal_locks);
143  
144 --- linux-2.6.7/fs/hostfs/hostfs_kern.c.lsec    2005-03-23 14:25:58.982447160 -0700
145 +++ linux-2.6.7/fs/hostfs/hostfs_kern.c 2005-03-23 14:33:11.946626600 -0700
146 @@ -290,7 +290,6 @@ static void hostfs_delete_inode(struct i
147  {
148         if(HOSTFS_I(inode)->fd != -1) {
149                 close_file(&HOSTFS_I(inode)->fd);
150 -               printk("Closing host fd in .delete_inode\n");
151                 HOSTFS_I(inode)->fd = -1;
152         }
153         clear_inode(inode);
154 @@ -303,7 +302,6 @@ static void hostfs_destroy_inode(struct 
155  
156         if(HOSTFS_I(inode)->fd != -1) {
157                 close_file(&HOSTFS_I(inode)->fd);
158 -               printk("Closing host fd in .destroy_inode\n");
159         }
160  
161         kfree(HOSTFS_I(inode));
162 --- linux-2.6.7/fs/open.c.lsec  2005-03-23 14:26:01.774022776 -0700
163 +++ linux-2.6.7/fs/open.c       2005-03-23 14:28:23.226518728 -0700
164 @@ -1025,7 +1025,7 @@ int filp_close(struct file *filp, fl_own
165         }
166  
167         dnotify_flush(filp, id);
168 -       locks_remove_posix(filp, id);
169 +       locks_remove_posix(filp, 0);
170         fput(filp);
171         return retval;
172  }
173 --- linux-2.6.7/fs/nfsd/export.c.lsec   2004-06-15 23:19:36.000000000 -0600
174 +++ linux-2.6.7/fs/nfsd/export.c        2005-03-23 14:28:24.686296808 -0700
175 @@ -255,7 +255,7 @@ static inline void svc_expkey_update(str
176         new->ek_export = item->ek_export;
177  }
178  
179 -static DefineSimpleCacheLookup(svc_expkey,0) /* no inplace updates */
180 +static DefineSimpleCacheLookup(svc_expkey)
181  
182  #define        EXPORT_HASHBITS         8
183  #define        EXPORT_HASHMAX          (1<< EXPORT_HASHBITS)
184 @@ -487,8 +487,72 @@ static inline void svc_export_update(str
185         new->ex_fsid = item->ex_fsid;
186  }
187  
188 -static DefineSimpleCacheLookup(svc_export,1) /* allow inplace updates */
189 +struct svc_export *
190 +svc_export_lookup(struct svc_export *item, int set)
191 +{
192 +       struct svc_export *tmp, *new = NULL;
193 +       struct cache_head **hp, **head;
194  
195 +       head = &svc_export_cache.hash_table[svc_export_hash(item)];
196 +retry:
197 +       if (set||new)
198 +               write_lock(&svc_export_cache.hash_lock);
199 +       else
200 +               read_lock(&svc_export_cache.hash_lock);
201 +       for(hp=head; *hp != NULL; hp = &tmp->h.next) {
202 +               tmp = container_of(*hp, struct svc_export, h);
203 +               if (svc_export_match(item, tmp)) { /* found a match */
204 +                       cache_get(&tmp->h);
205 +                       if (set) {
206 +                               if (test_bit(CACHE_NEGATIVE,  &item->h.flags))
207 +                                        set_bit(CACHE_NEGATIVE, &tmp->h.flags);
208 +                               else {
209 +                                       clear_bit(CACHE_NEGATIVE, &tmp->h.flags);
210 +                                       svc_export_update(tmp, item);
211 +                               }
212 +                       }
213 +                       if (set||new)
214 +                               write_unlock(&svc_export_cache.hash_lock);
215 +                       else
216 +                               read_unlock(&svc_export_cache.hash_lock);
217 +                       if (set)
218 +                               cache_fresh(&svc_export_cache, &tmp->h,
219 +                                               item->h.expiry_time);
220 +                       if (new)
221 +                               svc_export_put(&new->h, &svc_export_cache);
222 +                       return tmp;
223 +               }
224 +       }
225 +       /* Didn't find anything */
226 +       if (new) {
227 +               svc_export_init(new, item);
228 +               new->h.next = *head;
229 +               *head = &new->h;
230 +               set_bit(CACHE_HASHED, &new->h.flags);
231 +               svc_export_cache.entries++;
232 +               if (set) {
233 +                       tmp = new;
234 +                       if (test_bit(CACHE_NEGATIVE, &item->h.flags))
235 +                               set_bit(CACHE_NEGATIVE, &tmp->h.flags);
236 +                       else
237 +                               svc_export_update(tmp, item);
238 +               }
239 +       }
240 +       if (set||new)
241 +               write_unlock(&svc_export_cache.hash_lock);
242 +       else
243 +               read_unlock(&svc_export_cache.hash_lock);
244 +       if (new && set)
245 +               cache_fresh(&svc_export_cache, &new->h, item->h.expiry_time);
246 +       if (new)
247 +               return new;
248 +       new = kmalloc(sizeof(*new), GFP_KERNEL);
249 +       if (new) {
250 +               cache_init(&new->h);
251 +               goto retry;
252 +       }
253 +       return NULL;
254 +}
255  
256  struct svc_expkey *
257  exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
258 --- linux-2.6.7/fs/nfsd/nfs4callback.c.lsec     2005-03-23 14:28:24.578313224 -0700
259 +++ linux-2.6.7/fs/nfsd/nfs4callback.c  2005-03-23 14:28:24.578313224 -0700
260 @@ -0,0 +1,631 @@
261 +/*
262 + *  linux/fs/nfsd/nfs4callback.c
263 + *
264 + *  Copyright (c) 2001 The Regents of the University of Michigan.
265 + *  All rights reserved.
266 + *
267 + *  Kendrick Smith <kmsmith@umich.edu>
268 + *  Andy Adamson <andros@umich.edu>
269 + *
270 + *  Redistribution and use in source and binary forms, with or without
271 + *  modification, are permitted provided that the following conditions
272 + *  are met:
273 + *
274 + *  1. Redistributions of source code must retain the above copyright
275 + *     notice, this list of conditions and the following disclaimer.
276 + *  2. Redistributions in binary form must reproduce the above copyright
277 + *     notice, this list of conditions and the following disclaimer in the
278 + *     documentation and/or other materials provided with the distribution.
279 + *  3. Neither the name of the University nor the names of its
280 + *     contributors may be used to endorse or promote products derived
281 + *     from this software without specific prior written permission.
282 + *
283 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
284 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
285 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
286 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
287 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
288 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
289 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
290 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
291 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
292 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
293 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
294 + */
295 +
296 +#include <linux/config.h>
297 +#include <linux/module.h>
298 +#include <linux/list.h>
299 +#include <linux/inet.h>
300 +#include <linux/errno.h>
301 +#include <linux/sunrpc/xdr.h>
302 +#include <linux/sunrpc/svc.h>
303 +#include <linux/sunrpc/clnt.h>
304 +#include <linux/nfsd/nfsd.h>
305 +#include <linux/nfsd/state.h>
306 +#include <linux/sunrpc/sched.h>
307 +#include <linux/nfs4.h>
308 +
309 +#define NFSDDBG_FACILITY                NFSDDBG_PROC
310 +
311 +#define NFSPROC4_CB_NULL 0
312 +#define NFSPROC4_CB_COMPOUND 1
313 +
314 +/* forward declarations */
315 +static void nfs4_cb_null(struct rpc_task *task);
316 +
317 +/* Index of predefined Linux callback client operations */
318 +
319 +enum {
320 +        NFSPROC4_CLNT_CB_NULL = 0,
321 +        NFSPROC4_CLNT_CB_GETATTR,
322 +        NFSPROC4_CLNT_CB_RECALL,
323 +};
324 +
325 +enum nfs_cb_opnum4 {
326 +       OP_CB_GETATTR           = 3,
327 +       OP_CB_RECALL            = 4,
328 +       OP_CB_ILLEGAL           = 10044
329 +};
330 +
331 +
332 +#define NFS4_MAXTAGLEN         20
333 +
334 +#define cb_compound_enc_hdr_sz         4
335 +#define cb_compound_dec_hdr_sz         (3 + (NFS4_MAXTAGLEN >> 2))
336 +#define op_enc_sz                      1
337 +#define op_dec_sz                      2
338 +#define enc_nfs4_fh_sz                 (1 + (NFS4_FHSIZE >> 2))
339 +#define enc_stateid_sz                 16
340 +
341 +#define NFS4_enc_cb_getattr_sz         (cb_compound_enc_hdr_sz +       \
342 +                                       op_enc_sz  +                    \
343 +                                       enc_nfs4_fh_sz + 4)
344 +
345 +#define NFS4_dec_cb_getattr_sz         (cb_compound_dec_hdr_sz +       \
346 +                                       op_dec_sz          +            \
347 +                                       11)
348 +
349 +#define NFS4_enc_cb_recall_sz          (cb_compound_enc_hdr_sz +       \
350 +                                       1 + enc_stateid_sz +            \
351 +                                       enc_nfs4_fh_sz)
352 +
353 +#define NFS4_dec_cb_recall_sz          (cb_compound_dec_hdr_sz  +      \
354 +                                        op_dec_sz)
355 +
356 +/*
357 +* Generic encode routines from fs/nfs/nfs4xdr.c
358 +*/
359 +static inline u32 *
360 +xdr_writemem(u32 *p, const void *ptr, int nbytes)
361 +{
362 +       int tmp = XDR_QUADLEN(nbytes);
363 +       if (!tmp)
364 +               return p;
365 +       p[tmp-1] = 0;
366 +       memcpy(p, ptr, nbytes);
367 +       return p + tmp;
368 +}
369 +
370 +#define WRITE32(n)               *p++ = htonl(n)
371 +#define WRITEMEM(ptr,nbytes)     do {                           \
372 +        p = xdr_writemem(p, ptr, nbytes);                       \
373 +} while (0)
374 +#define RESERVE_SPACE(nbytes)   do {                            \
375 +       p = xdr_reserve_space(xdr, nbytes);                     \
376 +       if (!p) dprintk("NFSD: RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __FUNCTION__); \
377 +       BUG_ON(!p);                                             \
378 +} while (0)
379 +
380 +/*
381 + * Generic decode routines from fs/nfs/nfs4xdr.c
382 + */
383 +#define DECODE_TAIL                             \
384 +       status = 0;                             \
385 +out:                                            \
386 +       return status;                          \
387 +xdr_error:                                      \
388 +       dprintk("NFSD: xdr error! (%s:%d)\n", __FILE__, __LINE__); \
389 +       status = -EIO;                          \
390 +       goto out
391 +
392 +#define READ32(x)         (x) = ntohl(*p++)
393 +#define READ64(x)         do {                  \
394 +       (x) = (u64)ntohl(*p++) << 32;           \
395 +       (x) |= ntohl(*p++);                     \
396 +} while (0)
397 +#define READTIME(x)       do {                  \
398 +       p++;                                    \
399 +       (x.tv_sec) = ntohl(*p++);               \
400 +       (x.tv_nsec) = ntohl(*p++);              \
401 +} while (0)
402 +#define READ_BUF(nbytes)  do { \
403 +       p = xdr_inline_decode(xdr, nbytes); \
404 +       if (!p) { \
405 +               dprintk("NFSD: %s: reply buffer overflowed in line %d.", \
406 +                         __FUNCTION__, __LINE__); \
407 +               return -EIO; \
408 +       } \
409 +} while (0)
410 +
411 +struct nfs4_cb_compound_hdr {
412 +       int    status;
413 +       u32    ident;
414 +       u32    nops;
415 +       u32    taglen;
416 +       char * tag;
417 +};
418 +
419 +struct nfs4_cb_getattr {
420 +       struct nfs_fh   fh;
421 +       u32             bm0;
422 +       u32             bm1;
423 +       __u64           change_attr;
424 +       __u64           size;
425 +       struct timespec mtime;
426 +};
427 +
428 +struct nfs4_cb_recall {
429 +       nfs4_stateid  stateid;
430 +       int           trunc;
431 +       struct nfs_fh fh;
432 +};
433 +
434 +static struct {
435 +        int stat;
436 +        int errno;
437 +} nfs_cb_errtbl[] = {
438 +       { NFS4_OK,              0               },
439 +       { NFS4ERR_PERM,         EPERM           },
440 +       { NFS4ERR_NOENT,        ENOENT          },
441 +       { NFS4ERR_IO,           EIO             },
442 +       { NFS4ERR_NXIO,         ENXIO           },
443 +       { NFS4ERR_ACCESS,       EACCES          },
444 +       { NFS4ERR_EXIST,        EEXIST          },
445 +       { NFS4ERR_XDEV,         EXDEV           },
446 +       { NFS4ERR_NOTDIR,       ENOTDIR         },
447 +       { NFS4ERR_ISDIR,        EISDIR          },
448 +       { NFS4ERR_INVAL,        EINVAL          },
449 +       { NFS4ERR_FBIG,         EFBIG           },
450 +       { NFS4ERR_NOSPC,        ENOSPC          },
451 +       { NFS4ERR_ROFS,         EROFS           },
452 +       { NFS4ERR_MLINK,        EMLINK          },
453 +       { NFS4ERR_NAMETOOLONG,  ENAMETOOLONG    },
454 +       { NFS4ERR_NOTEMPTY,     ENOTEMPTY       },
455 +       { NFS4ERR_DQUOT,        EDQUOT          },
456 +       { NFS4ERR_STALE,        ESTALE          },
457 +       { NFS4ERR_BADHANDLE,    EBADHANDLE      },
458 +       { NFS4ERR_BAD_COOKIE,   EBADCOOKIE      },
459 +       { NFS4ERR_NOTSUPP,      ENOTSUPP        },
460 +       { NFS4ERR_TOOSMALL,     ETOOSMALL       },
461 +       { NFS4ERR_SERVERFAULT,  ESERVERFAULT    },
462 +       { NFS4ERR_BADTYPE,      EBADTYPE        },
463 +       { NFS4ERR_LOCKED,       EAGAIN          },
464 +       { NFS4ERR_RESOURCE,     EREMOTEIO       },
465 +       { NFS4ERR_SYMLINK,      ELOOP           },
466 +       { NFS4ERR_OP_ILLEGAL,   EOPNOTSUPP      },
467 +       { NFS4ERR_DEADLOCK,     EDEADLK         },
468 +       { -1,                   EIO             }
469 +};
470 +
471 +static int
472 +nfs_cb_stat_to_errno(int stat)
473 +{
474 +        int i;
475 +        for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) {
476 +                if (nfs_cb_errtbl[i].stat == stat)
477 +                        return nfs_cb_errtbl[i].errno;
478 +        }
479 +        /* If we cannot translate the error, the recovery routines should
480 +         * handle it.
481 +         * Note: remaining NFSv4 error codes have values > 10000, so should
482 +         * not conflict with native Linux error codes.
483 +         */
484 +        return stat;
485 +}
486 +
487 +/*
488 + * XDR encode
489 + */
490 +
491 +static int
492 +encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
493 +{
494 +       u32 * p;
495 +
496 +       RESERVE_SPACE(16);
497 +       WRITE32(0);            /* tag length is always 0 */
498 +       WRITE32(NFS4_MINOR_VERSION);
499 +       WRITE32(hdr->ident);
500 +       WRITE32(hdr->nops);
501 +       return 0;
502 +}
503 +
504 +static int
505 +encode_cb_getattr(struct xdr_stream *xdr, struct nfs4_cb_getattr *cb_get)
506 +{
507 +        u32 *p;
508 +       int len = cb_get->fh.size;
509 +
510 +       RESERVE_SPACE(20 + len);
511 +       WRITE32(OP_CB_GETATTR);
512 +       WRITE32(len);
513 +       WRITEMEM(cb_get->fh.data, len);
514 +       WRITE32(2);
515 +       WRITE32(cb_get->bm0);
516 +       WRITE32(cb_get->bm1);
517 +       return 0;
518 +}
519 +
520 +static int
521 +encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
522 +{
523 +       u32 *p;
524 +       int len = cb_rec->fh.size;
525 +
526 +        RESERVE_SPACE(8+sizeof(cb_rec->stateid.data));
527 +        WRITE32(OP_CB_RECALL);
528 +        WRITEMEM(cb_rec->stateid.data, sizeof(cb_rec->stateid.data));
529 +       WRITE32(cb_rec->trunc);
530 +       WRITE32(len);
531 +       WRITEMEM(cb_rec->fh.data, len);
532 +       return 0;
533 +}
534 +
535 +static int
536 +nfs4_xdr_enc_cb_getattr(struct rpc_rqst *req, u32 *p, struct nfs4_cb_getattr *args)
537 +{
538 +       struct xdr_stream xdr;
539 +       struct nfs4_cb_compound_hdr hdr = {
540 +               .nops   = 1,
541 +       };
542 +
543 +        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
544 +        encode_cb_compound_hdr(&xdr, &hdr);
545 +        return (encode_cb_getattr(&xdr, args));
546 +}
547 +
548 +static int
549 +nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args)
550 +{
551 +       struct xdr_stream xdr;
552 +       struct nfs4_cb_compound_hdr hdr = {
553 +               .nops   = 1,
554 +       };
555 +
556 +        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
557 +        encode_cb_compound_hdr(&xdr, &hdr);
558 +        return (encode_cb_recall(&xdr, args));
559 +}
560 +
561 +
562 +static int
563 +decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
564 +        u32 *p;
565 +
566 +        READ_BUF(8);
567 +        READ32(hdr->status);
568 +        READ32(hdr->taglen);
569 +        READ_BUF(hdr->taglen + 4);
570 +        hdr->tag = (char *)p;
571 +        p += XDR_QUADLEN(hdr->taglen);
572 +        READ32(hdr->nops);
573 +        return 0;
574 +}
575 +
576 +static int
577 +decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
578 +{
579 +       u32 *p;
580 +       u32 op;
581 +       int32_t nfserr;
582 +
583 +       READ_BUF(8);
584 +       READ32(op);
585 +       if (op != expected) {
586 +               dprintk("NFSD: decode_cb_op_hdr: Callback server returned operation"
587 +                       " %d but we issued a request for %d\n",
588 +                       op, expected);
589 +               return -EIO;
590 +       }
591 +       READ32(nfserr);
592 +       if (nfserr != NFS_OK)
593 +               return -nfs_cb_stat_to_errno(nfserr);
594 +       return 0;
595 +}
596 +
597 +static int
598 +decode_cb_getattr(struct xdr_stream *xdr, struct nfs4_cb_getattr *cb_get)
599 +{
600 +       int status;
601 +       u32 bmlen,
602 +               attrlen =0,
603 +               bmval0 =0,
604 +               bmval1 =0,
605 +               len = 0;
606 +       u32 *p;
607 +
608 +       status = decode_cb_op_hdr(xdr, OP_CB_GETATTR);
609 +       if (status)
610 +               return status;
611 +       READ_BUF(4);
612 +       READ32(bmlen);
613 +       if( (bmlen < 1) || (bmlen > 2))
614 +               goto xdr_error;
615 +       READ_BUF((bmlen << 2) + 4);
616 +       READ32(bmval0);
617 +       if (bmval0 & ~(FATTR4_WORD0_CHANGE | FATTR4_WORD0_SIZE))
618 +               goto out_bad_bitmap;
619 +       if (bmlen == 2) {
620 +               READ32(bmval1);
621 +               if (bmval1 & ~ FATTR4_WORD1_TIME_MODIFY)
622 +                       goto out_bad_bitmap;
623 +       }
624 +       READ32(attrlen);
625 +       if (bmval0 & FATTR4_WORD0_CHANGE) {
626 +               READ_BUF(8);
627 +               len += 8;
628 +               READ64(cb_get->change_attr);
629 +               dprintk("decode_cb_getattr: changeid=%Ld\n",
630 +                                    (long long)cb_get->change_attr);
631 +       }
632 +       if (bmval0 & FATTR4_WORD0_SIZE) {
633 +               READ_BUF(8);
634 +               len += 8;
635 +               READ64(cb_get->size);
636 +               dprintk("decode_cb_getattr: size=%Ld\n",
637 +                                    (long long)cb_get->size);
638 +       }
639 +       if (bmval1 & FATTR4_WORD1_TIME_MODIFY) {
640 +               READ_BUF(12);
641 +               len += 12;
642 +               READTIME(cb_get->mtime);
643 +               dprintk("decode_cb_gatattr: mtime=%ld\n",
644 +                                     (long)cb_get->mtime.tv_sec);
645 +       }
646 +       if (len != attrlen)
647 +               goto xdr_error;
648 +
649 +       DECODE_TAIL;
650 +
651 +out_bad_bitmap:
652 +        dprintk("NFSD: %s Callback server returned bad attribute bitmap\n",
653 +                __FUNCTION__);
654 +        return -EIO;
655 +
656 +}
657 +
658 +static int
659 +nfs4_xdr_dec_cb_getattr(struct rpc_rqst *rqstp, u32 *p, struct nfs4_cb_getattr *res)
660 +{
661 +       struct xdr_stream xdr;
662 +       struct nfs4_cb_compound_hdr hdr;
663 +       int status;
664 +
665 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
666 +       status = decode_cb_compound_hdr(&xdr, &hdr);
667 +       if (status)
668 +               goto out;
669 +       status = decode_cb_getattr(&xdr, res);
670 +out:
671 +       return status;
672 +}
673 +
674 +static int
675 +nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p)
676 +{
677 +       struct xdr_stream xdr;
678 +       struct nfs4_cb_compound_hdr hdr;
679 +       int status;
680 +
681 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
682 +       status = decode_cb_compound_hdr(&xdr, &hdr);
683 +       if (status)
684 +               goto out;
685 +       status = decode_cb_op_hdr(&xdr, OP_CB_RECALL);
686 +out:
687 +       return status;
688 +}
689 +
690 +static int
691 +nfs4_xdr_enc_null(struct rpc_rqst *req, u32 *p)
692 +{
693 +       struct xdr_stream xdrs, *xdr = &xdrs;
694 +
695 +       xdr_init_encode(&xdrs, &req->rq_snd_buf, p);
696 +        RESERVE_SPACE(0);
697 +       return 0;
698 +}
699 +
700 +static int
701 +nfs4_xdr_dec_null(struct rpc_rqst *req, u32 *p)
702 +{
703 +       return 0;
704 +}
705 +
706 +/*
707 + * RPC procedure tables
708 + */
709 +#ifndef MAX
710 +# define MAX(a, b)      (((a) > (b))? (a) : (b))
711 +#endif
712 +
713 +#define PROC(proc, argtype, restype)                                   \
714 +[NFSPROC4_CLNT_##proc] = {                                             \
715 +        .p_proc   = NFSPROC4_CB_COMPOUND,                              \
716 +        .p_encode = (kxdrproc_t) nfs4_xdr_##argtype,                   \
717 +        .p_decode = (kxdrproc_t) nfs4_xdr_##restype,                   \
718 +        .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2,  \
719 +}
720 +
721 +struct rpc_procinfo     nfs4_cb_procedures[] = {
722 +  PROC(CB_GETATTR,      enc_cb_getattr,     dec_cb_getattr),
723 +  PROC(CB_RECALL,       enc_cb_recall,      dec_cb_recall),
724 +};
725 +
726 +struct rpc_version              nfs_cb_version4 = {
727 +        .number                 = 1,
728 +        .nrprocs                = sizeof(nfs4_cb_procedures)/sizeof(nfs4_cb_procedures[0]),
729 +        .procs                  = nfs4_cb_procedures
730 +};
731 +
732 +static struct rpc_version *    nfs_cb_version[] = {
733 +       NULL,
734 +       &nfs_cb_version4,
735 +};
736 +
737 +struct rpc_procinfo  nfs4_cb_null_proc= {
738 +       .p_proc = NFSPROC4_CB_NULL,
739 +       .p_encode = (kxdrproc_t)nfs4_xdr_enc_null,
740 +        .p_decode = (kxdrproc_t) nfs4_xdr_dec_null,
741 +        .p_bufsiz = 0,
742 +};
743 +
744 +/*
745 + * Use the SETCLIENTID credential
746 + */
747 +struct rpc_cred *
748 +nfsd4_lookupcred(struct nfs4_client *clp, int taskflags)
749 +{
750 +        struct auth_cred acred;
751 +       struct rpc_clnt *clnt = clp->cl_callback.cb_client;
752 +        struct rpc_cred *ret = NULL;
753 +
754 +       if (!clnt)
755 +               goto out;
756 +        get_group_info(clp->cl_cred.cr_group_info);
757 +        acred.uid = clp->cl_cred.cr_uid;
758 +        acred.gid = clp->cl_cred.cr_gid;
759 +        acred.group_info = clp->cl_cred.cr_group_info;
760 +
761 +        dprintk("NFSD:     looking up %s cred\n",
762 +                clnt->cl_auth->au_ops->au_name);
763 +        ret = rpcauth_lookup_credcache(clnt->cl_auth, &acred, taskflags);
764 +        put_group_info(clp->cl_cred.cr_group_info);
765 +out:
766 +        return ret;
767 +}
768 +
769 +/*
770 + * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
771 + */
772 +void
773 +nfsd4_probe_callback(struct nfs4_client *clp)
774 +{
775 +       struct sockaddr_in      addr;
776 +       struct nfs4_callback    *cb = &clp->cl_callback;
777 +       struct rpc_timeout      timeparms;
778 +       struct rpc_xprt *       xprt;
779 +       struct rpc_program *    program = &cb->cb_program;
780 +       struct rpc_stat *       stat = &cb->cb_stat;
781 +       struct rpc_clnt *       clnt;
782 +        struct rpc_message msg = {
783 +                .rpc_proc       = &nfs4_cb_null_proc,
784 +                .rpc_argp       = clp,
785 +        };
786 +       char                    hostname[32];
787 +       int status;
788 +
789 +       dprintk("NFSD: probe_callback. cb_parsed %d cb_set %d 1\n",
790 +                cb->cb_parsed, cb->cb_set);
791 +       if (!cb->cb_parsed || cb->cb_set)
792 +               goto out_err;
793 +
794 +       /* Currently, we only support tcp for the callback channel */
795 +       if (cb->cb_netid.len !=3 || memcmp((char *)cb->cb_netid.data, "tcp", 3))
796 +               goto out_err;
797 +
798 +       /* Initialize address */
799 +       memset(&addr, 0, sizeof(addr));
800 +       addr.sin_family = AF_INET;
801 +       addr.sin_port = htons(cb->cb_port);
802 +       addr.sin_addr.s_addr = htonl(cb->cb_addr);
803 +
804 +       /* Initialize timeout */
805 +       timeparms.to_initval = HZ;
806 +       timeparms.to_retries = 5;
807 +       timeparms.to_maxval = NFSD_LEASE_TIME*HZ;
808 +       timeparms.to_exponential = 1;
809 +
810 +       /* Create RPC transport */
811 +       if (!(xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms))) {
812 +               dprintk("NFSD: couldn't create callback transport!\n");
813 +               goto out_err;
814 +       }
815 +
816 +       /* Initialize rpc_program */
817 +       program->name = "nfs4_cb";
818 +       program->number = cb->cb_prog;
819 +       program->nrvers = sizeof(nfs_cb_version)/sizeof(nfs_cb_version[0]);
820 +       program->version = nfs_cb_version;
821 +       program->stats = stat;
822 +
823 +       /* Initialize rpc_stat */
824 +       memset(stat, 0, sizeof(struct rpc_stat));
825 +       stat->program = program;
826 +
827 +       /* Create RPC client
828 +        *
829 +        * XXX AUTH_UNIX only - need AUTH_GSS....
830 +        */
831 +       sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr));
832 +       if (!(clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX))) {
833 +               dprintk("NFSD: couldn't create callback client\n");
834 +               goto out_xprt;
835 +       }
836 +       clnt->cl_intr = 1;
837 +       clnt->cl_softrtry = 1;
838 +       clnt->cl_chatty = 1;
839 +       cb->cb_client = clnt;
840 +
841 +       /* Kick rpciod, put the call on the wire. */
842 +
843 +       if (rpciod_up() != 0) {
844 +               dprintk("nfsd: couldn't start rpciod for callbacks!\n");
845 +               goto out_clnt;
846 +       }
847 +
848 +       /* the task holds a reference to the nfs4_client struct */
849 +       atomic_inc(&clp->cl_count);
850 +
851 +       msg.rpc_cred = nfsd4_lookupcred(clp,0);
852 +       status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, nfs4_cb_null, 0);
853 +
854 +       if (status != 0) {
855 +               dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n");
856 +               goto out_rpciod;
857 +       }
858 +       return;
859 +
860 +out_rpciod:
861 +       rpciod_down();
862 +out_clnt:
863 +       rpc_shutdown_client(clnt);
864 +       goto out_err;
865 +out_xprt:
866 +       xprt_destroy(xprt);
867 +out_err:
868 +       dprintk("NFSD: warning: no callback path to client %.*s\n",
869 +               clp->cl_name.len, clp->cl_name.data);
870 +       cb->cb_client = NULL;
871 +}
872 +
873 +static void
874 +nfs4_cb_null(struct rpc_task *task)
875 +{
876 +       struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
877 +       struct nfs4_callback *cb = &clp->cl_callback;
878 +       u32 addr = htonl(cb->cb_addr);
879 +
880 +       dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status);
881 +
882 +       if (task->tk_status < 0) {
883 +               dprintk("NFSD: callback establishment to client %.*s failed\n",
884 +                       clp->cl_name.len, clp->cl_name.data);
885 +               goto out;
886 +       }
887 +       cb->cb_set = 1;
888 +       dprintk("NFSD: callback set to client %u.%u.%u.%u\n", NIPQUAD(addr));
889 +out:
890 +       put_nfs4_client(clp);
891 +}
892 --- linux-2.6.7/fs/nfsd/nfs4xdr.c.lsec  2004-06-15 23:19:52.000000000 -0600
893 +++ linux-2.6.7/fs/nfsd/nfs4xdr.c       2005-03-23 14:28:23.924412632 -0700
894 @@ -55,6 +55,8 @@
895  #include <linux/nfsd/state.h>
896  #include <linux/nfsd/xdr4.h>
897  #include <linux/nfsd_idmap.h>
898 +#include <linux/nfs4.h>
899 +#include <linux/nfs4_acl.h>
900  
901  #define NFSDDBG_FACILITY               NFSDDBG_XDR
902  
903 @@ -287,27 +289,40 @@ u32 *read_buf(struct nfsd4_compoundargs 
904         return p;
905  }
906  
907 -char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
908 +static int
909 +defer_free(struct nfsd4_compoundargs *argp,
910 +               void (*release)(const void *), void *p)
911  {
912         struct tmpbuf *tb;
913 +
914 +       tb = kmalloc(sizeof(*tb), GFP_KERNEL);
915 +       if (!tb)
916 +               return -ENOMEM;
917 +       tb->buf = p;
918 +       tb->release = release;
919 +       tb->next = argp->to_free;
920 +       argp->to_free = tb;
921 +       return 0;
922 +}
923 +
924 +char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
925 +{
926 +       void *new = NULL;
927         if (p == argp->tmp) {
928 -               p = kmalloc(nbytes, GFP_KERNEL);
929 -               if (!p) return NULL;
930 +               new = kmalloc(nbytes, GFP_KERNEL);
931 +               if (!new) return NULL;
932 +               p = new;
933                 memcpy(p, argp->tmp, nbytes);
934         } else {
935                 if (p != argp->tmpp)
936                         BUG();
937                 argp->tmpp = NULL;
938         }
939 -       tb = kmalloc(sizeof(*tb), GFP_KERNEL);
940 -       if (!tb) {
941 -               kfree(p);
942 +       if (defer_free(argp, kfree, p)) {
943 +               kfree(new);
944                 return NULL;
945 -       }
946 -       tb->buf = p;
947 -       tb->next = argp->to_free;
948 -       argp->to_free = tb;
949 -       return (char*)p;
950 +       } else
951 +               return (char *)p;
952  }
953  
954  
955 @@ -335,7 +350,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoun
956  }
957  
958  static int
959 -nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr)
960 +nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr,
961 +    struct nfs4_acl **acl)
962  {
963         int expected_len, len = 0;
964         u32 dummy32;
965 @@ -364,6 +380,51 @@ nfsd4_decode_fattr(struct nfsd4_compound
966                 READ64(iattr->ia_size);
967                 iattr->ia_valid |= ATTR_SIZE;
968         }
969 +       if (bmval[0] & FATTR4_WORD0_ACL) {
970 +               int nace, i;
971 +               struct nfs4_ace ace;
972 +
973 +               READ_BUF(4); len += 4;
974 +               READ32(nace);
975 +
976 +               *acl = nfs4_acl_new();
977 +               if (*acl == NULL) {
978 +                       status = -ENOMEM;
979 +                       goto out_nfserr;
980 +               }
981 +               defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl);
982 +
983 +               for (i = 0; i < nace; i++) {
984 +                       READ_BUF(16); len += 16;
985 +                       READ32(ace.type);
986 +                       READ32(ace.flag);
987 +                       READ32(ace.access_mask);
988 +                       READ32(dummy32);
989 +                       READ_BUF(dummy32);
990 +                       len += XDR_QUADLEN(dummy32) << 2;
991 +                       READMEM(buf, dummy32);
992 +                       if (check_utf8(buf, dummy32))
993 +                               return nfserr_inval;
994 +                       ace.whotype = nfs4_acl_get_whotype(buf, dummy32);
995 +                       status = 0;
996 +                       if (ace.whotype != NFS4_ACL_WHO_NAMED)
997 +                               ace.who = 0;
998 +                       else if (ace.flag & NFS4_ACE_IDENTIFIER_GROUP)
999 +                               status = nfsd_map_name_to_gid(argp->rqstp,
1000 +                                               buf, dummy32, &ace.who);
1001 +                       else
1002 +                               status = nfsd_map_name_to_uid(argp->rqstp,
1003 +                                               buf, dummy32, &ace.who);
1004 +                       if (status)
1005 +                               goto out_nfserr;
1006 +                       if (nfs4_acl_add_ace(*acl, ace.type, ace.flag,
1007 +                                ace.access_mask, ace.whotype, ace.who) != 0) {
1008 +                               status = -ENOMEM;
1009 +                               goto out_nfserr;
1010 +                       }
1011 +               }
1012 +       } else
1013 +               *acl = NULL;
1014         if (bmval[1] & FATTR4_WORD1_MODE) {
1015                 READ_BUF(4);
1016                 len += 4;
1017 @@ -549,7 +610,7 @@ nfsd4_decode_create(struct nfsd4_compoun
1018         if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
1019                 return status;
1020  
1021 -       if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr)))
1022 +       if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl)))
1023                 goto out;
1024  
1025         DECODE_TAIL;
1026 @@ -698,7 +759,7 @@ nfsd4_decode_open(struct nfsd4_compounda
1027                 switch (open->op_createmode) {
1028                 case NFS4_CREATE_UNCHECKED:
1029                 case NFS4_CREATE_GUARDED:
1030 -                       if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr)))
1031 +                       if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl)))
1032                                 goto out;
1033                         break;
1034                 case NFS4_CREATE_EXCLUSIVE:
1035 @@ -875,7 +936,7 @@ nfsd4_decode_setattr(struct nfsd4_compou
1036         READ_BUF(sizeof(stateid_t));
1037         READ32(setattr->sa_stateid.si_generation);
1038         COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
1039 -       if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr)))
1040 +       if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl)))
1041                 goto out;
1042  
1043         DECODE_TAIL;
1044 @@ -1288,32 +1349,24 @@ static u32 nfs4_ftypes[16] = {
1045          NF4SOCK, NF4BAD,  NF4LNK, NF4BAD,
1046  };
1047  
1048 -static inline int
1049 -xdr_padding(int l)
1050 -{
1051 -       return 3 - ((l - 1) & 3); /* smallest i>=0 such that (l+i)%4 = 0 */
1052 -}
1053 -
1054  static int
1055 -nfsd4_encode_name(struct svc_rqst *rqstp, int group, uid_t id,
1056 +nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
1057                         u32 **p, int *buflen)
1058  {
1059         int status;
1060 -       u32 len;
1061  
1062         if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4)
1063                 return nfserr_resource;
1064 -       if (group)
1065 +       if (whotype != NFS4_ACL_WHO_NAMED)
1066 +               status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1));
1067 +       else if (group)
1068                 status = nfsd_map_gid_to_name(rqstp, id, (u8 *)(*p + 1));
1069         else
1070                 status = nfsd_map_uid_to_name(rqstp, id, (u8 *)(*p + 1));
1071         if (status < 0)
1072                 return nfserrno(status);
1073 -       len = (unsigned)status;
1074 -       *(*p)++ = htonl(len);
1075 -       memset((u8 *)*p + len, 0, xdr_padding(len));
1076 -       *p += XDR_QUADLEN(len);
1077 -       *buflen -= (XDR_QUADLEN(len) << 2) + 4;
1078 +       *p = xdr_encode_opaque(*p, NULL, status);
1079 +       *buflen -= (XDR_QUADLEN(status) << 2) + 4;
1080         BUG_ON(*buflen < 0);
1081         return 0;
1082  }
1083 @@ -1321,13 +1374,20 @@ nfsd4_encode_name(struct svc_rqst *rqstp
1084  static inline int
1085  nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen)
1086  {
1087 -       return nfsd4_encode_name(rqstp, uid, 0, p, buflen);
1088 +       return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen);
1089  }
1090  
1091  static inline int
1092  nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen)
1093  {
1094 -       return nfsd4_encode_name(rqstp, gid, 1, p, buflen);
1095 +       return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen);
1096 +}
1097 +
1098 +static inline int
1099 +nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
1100 +               u32 **p, int *buflen)
1101 +{
1102 +       return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
1103  }
1104  
1105  
1106 @@ -1354,6 +1414,8 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
1107         u64 dummy64;
1108         u32 *p = buffer;
1109         int status;
1110 +       int aclsupport = 0;
1111 +       struct nfs4_acl *acl = NULL;
1112  
1113         BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
1114         BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
1115 @@ -1376,6 +1438,17 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
1116                         goto out;
1117                 fhp = &tempfh;
1118         }
1119 +       if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
1120 +                       | FATTR4_WORD0_SUPPORTED_ATTRS)) {
1121 +               status = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
1122 +               aclsupport = (status == 0);
1123 +               if (bmval0 & FATTR4_WORD0_ACL) {
1124 +                       if (status == -EOPNOTSUPP)
1125 +                               bmval0 &= ~FATTR4_WORD0_ACL;
1126 +                       else if (status != 0)
1127 +                               goto out_nfserr;
1128 +               }
1129 +       }
1130         if ((buflen -= 16) < 0)
1131                 goto out_resource;
1132  
1133 @@ -1388,7 +1461,9 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
1134                 if ((buflen -= 12) < 0)
1135                         goto out_resource;
1136                 WRITE32(2);
1137 -               WRITE32(NFSD_SUPPORTED_ATTRS_WORD0);
1138 +               WRITE32(aclsupport ?
1139 +                       NFSD_SUPPORTED_ATTRS_WORD0 :
1140 +                       NFSD_SUPPORTED_ATTRS_WORD0 & ~FATTR4_WORD0_ACL);
1141                 WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
1142         }
1143         if (bmval0 & FATTR4_WORD0_TYPE) {
1144 @@ -1459,10 +1534,44 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
1145                         goto out_resource;
1146                 WRITE32(0);
1147         }
1148 +       if (bmval0 & FATTR4_WORD0_ACL) {
1149 +               struct nfs4_ace *ace;
1150 +               struct list_head *h;
1151 +
1152 +               if (acl == NULL) {
1153 +                       if ((buflen -= 4) < 0)
1154 +                               goto out_resource;
1155 +
1156 +                       WRITE32(0);
1157 +                       goto out_acl;
1158 +               }
1159 +               if ((buflen -= 4) < 0)
1160 +                       goto out_resource;
1161 +               WRITE32(acl->naces);
1162 +
1163 +               list_for_each(h, &acl->ace_head) {
1164 +                       ace = list_entry(h, struct nfs4_ace, l_ace);
1165 +
1166 +                       if ((buflen -= 4*3) < 0)
1167 +                               goto out_resource;
1168 +                       WRITE32(ace->type);
1169 +                       WRITE32(ace->flag);
1170 +                       WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL);
1171 +                       status = nfsd4_encode_aclname(rqstp, ace->whotype,
1172 +                               ace->who, ace->flag & NFS4_ACE_IDENTIFIER_GROUP,
1173 +                               &p, &buflen);
1174 +                       if (status == nfserr_resource)
1175 +                               goto out_resource;
1176 +                       if (status)
1177 +                               goto out;
1178 +               }
1179 +       }
1180 +out_acl:
1181         if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
1182                 if ((buflen -= 4) < 0)
1183                         goto out_resource;
1184 -               WRITE32(0);
1185 +               WRITE32(aclsupport ?
1186 +                       ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL : 0);
1187         }
1188         if (bmval0 & FATTR4_WORD0_CANSETTIME) {
1189                 if ((buflen -= 4) < 0)
1190 @@ -1645,6 +1754,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
1191         status = nfs_ok;
1192  
1193  out:
1194 +       nfs4_acl_free(acl);
1195         if (fhp == &tempfh)
1196                 fh_put(&tempfh);
1197         return status;
1198 @@ -2471,6 +2581,24 @@ nfs4svc_encode_voidres(struct svc_rqst *
1199          return xdr_ressize_check(rqstp, p);
1200  }
1201  
1202 +void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args)
1203 +{
1204 +       if (args->ops != args->iops) {
1205 +               kfree(args->ops);
1206 +               args->ops = args->iops;
1207 +       }
1208 +       if (args->tmpp) {
1209 +               kfree(args->tmpp);
1210 +               args->tmpp = NULL;
1211 +       }
1212 +       while (args->to_free) {
1213 +               struct tmpbuf *tb = args->to_free;
1214 +               args->to_free = tb->next;
1215 +               tb->release(tb->buf);
1216 +               kfree(tb);
1217 +       }
1218 +}
1219 +
1220  int
1221  nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args)
1222  {
1223 @@ -2487,20 +2615,7 @@ nfs4svc_decode_compoundargs(struct svc_r
1224  
1225         status = nfsd4_decode_compound(args);
1226         if (status) {
1227 -               if (args->ops != args->iops) {
1228 -                       kfree(args->ops);
1229 -                       args->ops = args->iops;
1230 -               }
1231 -               if (args->tmpp) {
1232 -                       kfree(args->tmpp);
1233 -                       args->tmpp = NULL;
1234 -               }
1235 -               while (args->to_free) {
1236 -                       struct tmpbuf *tb = args->to_free;
1237 -                       args->to_free = tb->next;
1238 -                       kfree(tb->buf);
1239 -                       kfree(tb);
1240 -               }
1241 +               nfsd4_release_compoundargs(args);
1242         }
1243         return !status;
1244  }
1245 --- linux-2.6.7/fs/nfsd/nfs4proc.c.lsec 2004-06-15 23:20:26.000000000 -0600
1246 +++ linux-2.6.7/fs/nfsd/nfs4proc.c      2005-03-23 14:28:24.080388920 -0700
1247 @@ -52,6 +52,7 @@
1248  #include <linux/nfs4.h>
1249  #include <linux/nfsd/state.h>
1250  #include <linux/nfsd/xdr4.h>
1251 +#include <linux/nfs4_acl.h>
1252  
1253  #define NFSDDBG_FACILITY               NFSDDBG_PROC
1254  
1255 @@ -135,9 +136,11 @@ do_open_fhandle(struct svc_rqst *rqstp, 
1256  {
1257         int status;
1258  
1259 -       dprintk("NFSD: do_open_fhandle\n");
1260 +       /* Only reclaims from previously confirmed clients are valid */
1261 +       if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
1262 +               return status;
1263  
1264 -       /* we don't know the target directory, and therefore can not
1265 +       /* We don't know the target directory, and therefore can not
1266         * set the change info
1267         */
1268  
1269 @@ -172,8 +175,7 @@ nfsd4_open(struct svc_rqst *rqstp, struc
1270         if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
1271                 return nfserr_grace;
1272  
1273 -       if (nfs4_in_no_grace() &&
1274 -                          open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
1275 +       if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
1276                 return nfserr_no_grace;
1277  
1278         /* This check required by spec. */
1279 @@ -318,7 +320,7 @@ nfsd4_commit(struct svc_rqst *rqstp, str
1280         return status;
1281  }
1282  
1283 -static inline int
1284 +static int
1285  nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create)
1286  {
1287         struct svc_fh resfh;
1288 @@ -435,7 +437,7 @@ nfsd4_link(struct svc_rqst *rqstp, struc
1289         return status;
1290  }
1291  
1292 -static inline int
1293 +static int
1294  nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
1295  {
1296         struct svc_fh tmp_fh;
1297 @@ -619,7 +621,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, st
1298                 status = nfserr_bad_stateid;
1299                 if (ZERO_STATEID(&setattr->sa_stateid) || ONE_STATEID(&setattr->sa_stateid)) {
1300                         dprintk("NFSD: nfsd4_setattr: magic stateid!\n");
1301 -                       return status;
1302 +                       goto out;
1303                 }
1304  
1305                 nfs4_lock_state();
1306 @@ -627,17 +629,25 @@ nfsd4_setattr(struct svc_rqst *rqstp, st
1307                                                 &setattr->sa_stateid, 
1308                                                 CHECK_FH | RDWR_STATE, &stp))) {
1309                         dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
1310 -                       goto out;
1311 +                       goto out_unlock;
1312                 }
1313                 status = nfserr_openmode;
1314                 if (!access_bits_permit_write(stp->st_access_bmap)) {
1315                         dprintk("NFSD: nfsd4_setattr: not opened for write!\n");
1316 -                       goto out;
1317 +                       goto out_unlock;
1318                 }
1319                 nfs4_unlock_state();
1320         }
1321 -       return (nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 0, (time_t)0));
1322 +       status = nfs_ok;
1323 +       if (setattr->sa_acl != NULL)
1324 +               status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl);
1325 +       if (status)
1326 +               goto out;
1327 +       status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr,
1328 +                               0, (time_t)0);
1329  out:
1330 +       return status;
1331 +out_unlock:
1332         nfs4_unlock_state();
1333         return status;
1334  }
1335 @@ -773,13 +783,20 @@ nfsd4_proc_compound(struct svc_rqst *rqs
1336                     struct nfsd4_compoundres *resp)
1337  {
1338         struct nfsd4_op *op;
1339 -       struct svc_fh   current_fh;
1340 -       struct svc_fh   save_fh;
1341 +       struct svc_fh   *current_fh = NULL;
1342 +       struct svc_fh   *save_fh = NULL;
1343         int             slack_space;    /* in words, not bytes! */
1344         int             status;
1345  
1346 -       fh_init(&current_fh, NFS4_FHSIZE);
1347 -       fh_init(&save_fh, NFS4_FHSIZE);
1348 +       status = nfserr_resource;
1349 +       current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL);
1350 +       if (current_fh == NULL)
1351 +               goto out;
1352 +       fh_init(current_fh, NFS4_FHSIZE);
1353 +       save_fh = kmalloc(sizeof(*save_fh), GFP_KERNEL);
1354 +       if (save_fh == NULL)
1355 +               goto out;
1356 +       fh_init(save_fh, NFS4_FHSIZE);
1357  
1358         resp->xbuf = &rqstp->rq_res;
1359         resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len;
1360 @@ -831,7 +848,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
1361                 * SETATTR NOFILEHANDLE error handled in nfsd4_setattr
1362                 * due to required returned bitmap argument
1363                 */
1364 -               if ((!current_fh.fh_dentry) &&
1365 +               if ((!current_fh->fh_dentry) &&
1366                    !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
1367                    (op->opnum == OP_SETCLIENTID) ||
1368                    (op->opnum == OP_SETCLIENTID_CONFIRM) ||
1369 @@ -843,105 +860,105 @@ nfsd4_proc_compound(struct svc_rqst *rqs
1370                 }
1371                 switch (op->opnum) {
1372                 case OP_ACCESS:
1373 -                       op->status = nfsd4_access(rqstp, &current_fh, &op->u.access);
1374 +                       op->status = nfsd4_access(rqstp, current_fh, &op->u.access);
1375                         break;
1376                 case OP_CLOSE:
1377 -                       op->status = nfsd4_close(rqstp, &current_fh, &op->u.close);
1378 +                       op->status = nfsd4_close(rqstp, current_fh, &op->u.close);
1379                         if (op->u.close.cl_stateowner)
1380                                 op->replay =
1381                                         &op->u.close.cl_stateowner->so_replay;
1382                         break;
1383                 case OP_COMMIT:
1384 -                       op->status = nfsd4_commit(rqstp, &current_fh, &op->u.commit);
1385 +                       op->status = nfsd4_commit(rqstp, current_fh, &op->u.commit);
1386                         break;
1387                 case OP_CREATE:
1388 -                       op->status = nfsd4_create(rqstp, &current_fh, &op->u.create);
1389 +                       op->status = nfsd4_create(rqstp, current_fh, &op->u.create);
1390                         break;
1391                 case OP_GETATTR:
1392 -                       op->status = nfsd4_getattr(rqstp, &current_fh, &op->u.getattr);
1393 +                       op->status = nfsd4_getattr(rqstp, current_fh, &op->u.getattr);
1394                         break;
1395                 case OP_GETFH:
1396 -                       op->status = nfsd4_getfh(&current_fh, &op->u.getfh);
1397 +                       op->status = nfsd4_getfh(current_fh, &op->u.getfh);
1398                         break;
1399                 case OP_LINK:
1400 -                       op->status = nfsd4_link(rqstp, &current_fh, &save_fh, &op->u.link);
1401 +                       op->status = nfsd4_link(rqstp, current_fh, save_fh, &op->u.link);
1402                         break;
1403                 case OP_LOCK:
1404 -                       op->status = nfsd4_lock(rqstp, &current_fh, &op->u.lock);
1405 +                       op->status = nfsd4_lock(rqstp, current_fh, &op->u.lock);
1406                         if (op->u.lock.lk_stateowner)
1407                                 op->replay =
1408                                         &op->u.lock.lk_stateowner->so_replay;
1409                         break;
1410                 case OP_LOCKT:
1411 -                       op->status = nfsd4_lockt(rqstp, &current_fh, &op->u.lockt);
1412 +                       op->status = nfsd4_lockt(rqstp, current_fh, &op->u.lockt);
1413                         break;
1414                 case OP_LOCKU:
1415 -                       op->status = nfsd4_locku(rqstp, &current_fh, &op->u.locku);
1416 +                       op->status = nfsd4_locku(rqstp, current_fh, &op->u.locku);
1417                         if (op->u.locku.lu_stateowner)
1418                                 op->replay =
1419                                         &op->u.locku.lu_stateowner->so_replay;
1420                         break;
1421                 case OP_LOOKUP:
1422 -                       op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup);
1423 +                       op->status = nfsd4_lookup(rqstp, current_fh, &op->u.lookup);
1424                         break;
1425                 case OP_LOOKUPP:
1426 -                       op->status = nfsd4_lookupp(rqstp, &current_fh);
1427 +                       op->status = nfsd4_lookupp(rqstp, current_fh);
1428                         break;
1429                 case OP_NVERIFY:
1430 -                       op->status = nfsd4_verify(rqstp, &current_fh, &op->u.nverify);
1431 +                       op->status = nfsd4_verify(rqstp, current_fh, &op->u.nverify);
1432                         if (op->status == nfserr_not_same)
1433                                 op->status = nfs_ok;
1434                         break;
1435                 case OP_OPEN:
1436 -                       op->status = nfsd4_open(rqstp, &current_fh, &op->u.open);
1437 +                       op->status = nfsd4_open(rqstp, current_fh, &op->u.open);
1438                         if (op->u.open.op_stateowner)
1439                                 op->replay =
1440                                         &op->u.open.op_stateowner->so_replay;
1441                         break;
1442                 case OP_OPEN_CONFIRM:
1443 -                       op->status = nfsd4_open_confirm(rqstp, &current_fh, &op->u.open_confirm);
1444 +                       op->status = nfsd4_open_confirm(rqstp, current_fh, &op->u.open_confirm);
1445                         if (op->u.open_confirm.oc_stateowner)
1446                                 op->replay =
1447                                         &op->u.open_confirm.oc_stateowner->so_replay;
1448                         break;
1449                 case OP_OPEN_DOWNGRADE:
1450 -                       op->status = nfsd4_open_downgrade(rqstp, &current_fh, &op->u.open_downgrade);
1451 +                       op->status = nfsd4_open_downgrade(rqstp, current_fh, &op->u.open_downgrade);
1452                         if (op->u.open_downgrade.od_stateowner)
1453                                 op->replay =
1454                                         &op->u.open_downgrade.od_stateowner->so_replay;
1455                         break;
1456                 case OP_PUTFH:
1457 -                       op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh);
1458 +                       op->status = nfsd4_putfh(rqstp, current_fh, &op->u.putfh);
1459                         break;
1460                 case OP_PUTROOTFH:
1461 -                       op->status = nfsd4_putrootfh(rqstp, &current_fh);
1462 +                       op->status = nfsd4_putrootfh(rqstp, current_fh);
1463                         break;
1464                 case OP_READ:
1465 -                       op->status = nfsd4_read(rqstp, &current_fh, &op->u.read);
1466 +                       op->status = nfsd4_read(rqstp, current_fh, &op->u.read);
1467                         break;
1468                 case OP_READDIR:
1469 -                       op->status = nfsd4_readdir(rqstp, &current_fh, &op->u.readdir);
1470 +                       op->status = nfsd4_readdir(rqstp, current_fh, &op->u.readdir);
1471                         break;
1472                 case OP_READLINK:
1473 -                       op->status = nfsd4_readlink(rqstp, &current_fh, &op->u.readlink);
1474 +                       op->status = nfsd4_readlink(rqstp, current_fh, &op->u.readlink);
1475                         break;
1476                 case OP_REMOVE:
1477 -                       op->status = nfsd4_remove(rqstp, &current_fh, &op->u.remove);
1478 +                       op->status = nfsd4_remove(rqstp, current_fh, &op->u.remove);
1479                         break;
1480                 case OP_RENAME:
1481 -                       op->status = nfsd4_rename(rqstp, &current_fh, &save_fh, &op->u.rename);
1482 +                       op->status = nfsd4_rename(rqstp, current_fh, save_fh, &op->u.rename);
1483                         break;
1484                 case OP_RENEW:
1485                         op->status = nfsd4_renew(&op->u.renew);
1486                         break;
1487                 case OP_RESTOREFH:
1488 -                       op->status = nfsd4_restorefh(&current_fh, &save_fh);
1489 +                       op->status = nfsd4_restorefh(current_fh, save_fh);
1490                         break;
1491                 case OP_SAVEFH:
1492 -                       op->status = nfsd4_savefh(&current_fh, &save_fh);
1493 +                       op->status = nfsd4_savefh(current_fh, save_fh);
1494                         break;
1495                 case OP_SETATTR:
1496 -                       op->status = nfsd4_setattr(rqstp, &current_fh, &op->u.setattr);
1497 +                       op->status = nfsd4_setattr(rqstp, current_fh, &op->u.setattr);
1498                         break;
1499                 case OP_SETCLIENTID:
1500                         op->status = nfsd4_setclientid(rqstp, &op->u.setclientid);
1501 @@ -950,12 +967,12 @@ nfsd4_proc_compound(struct svc_rqst *rqs
1502                         op->status = nfsd4_setclientid_confirm(rqstp, &op->u.setclientid_confirm);
1503                         break;
1504                 case OP_VERIFY:
1505 -                       op->status = nfsd4_verify(rqstp, &current_fh, &op->u.verify);
1506 +                       op->status = nfsd4_verify(rqstp, current_fh, &op->u.verify);
1507                         if (op->status == nfserr_same)
1508                                 op->status = nfs_ok;
1509                         break;
1510                 case OP_WRITE:
1511 -                       op->status = nfsd4_write(rqstp, &current_fh, &op->u.write);
1512 +                       op->status = nfsd4_write(rqstp, current_fh, &op->u.write);
1513                         break;
1514                 case OP_RELEASE_LOCKOWNER:
1515                         op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner);
1516 @@ -976,22 +993,13 @@ encode_op:
1517         }
1518  
1519  out:
1520 -       if (args->ops != args->iops) {
1521 -               kfree(args->ops);
1522 -               args->ops = args->iops;
1523 -       }
1524 -       if (args->tmpp) {
1525 -               kfree(args->tmpp);
1526 -               args->tmpp = NULL;
1527 -       }
1528 -       while (args->to_free) {
1529 -               struct tmpbuf *tb = args->to_free;
1530 -               args->to_free = tb->next;
1531 -               kfree(tb->buf);
1532 -               kfree(tb);
1533 -       }
1534 -       fh_put(&current_fh);
1535 -       fh_put(&save_fh);
1536 +       nfsd4_release_compoundargs(args);
1537 +       if (current_fh)
1538 +               fh_put(current_fh);
1539 +       kfree(current_fh);
1540 +       if (save_fh)
1541 +               fh_put(save_fh);
1542 +       kfree(save_fh);
1543         return status;
1544  }
1545  
1546 --- linux-2.6.7/fs/nfsd/nfs4state.c.lsec        2004-06-15 23:19:43.000000000 -0600
1547 +++ linux-2.6.7/fs/nfsd/nfs4state.c     2005-03-23 14:28:24.028396824 -0700
1548 @@ -51,6 +51,9 @@
1549  #define NFSDDBG_FACILITY                NFSDDBG_PROC
1550  
1551  /* Globals */
1552 +static time_t lease_time = 90;     /* default lease time */
1553 +static time_t old_lease_time = 90; /* past incarnation lease time */
1554 +static u32 nfs4_reclaim_init = 0;
1555  time_t boot_time;
1556  static time_t grace_end = 0;
1557  static u32 current_clientid = 1;
1558 @@ -82,7 +85,7 @@ struct nfs4_stateid * find_stateid(state
1559   *     protects clientid_hashtbl[], clientstr_hashtbl[],
1560   *     unconfstr_hashtbl[], uncofid_hashtbl[].
1561   */
1562 -static struct semaphore client_sema;
1563 +static DECLARE_MUTEX(client_sema);
1564  
1565  void
1566  nfs4_lock_state(void)
1567 @@ -131,8 +134,11 @@ static void release_file(struct nfs4_fil
1568         ((id) & CLIENT_HASH_MASK)
1569  #define clientstr_hashval(name, namelen) \
1570         (opaque_hashval((name), (namelen)) & CLIENT_HASH_MASK)
1571 -
1572 -/* conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed
1573 +/*
1574 + * reclaim_str_hashtbl[] holds known client info from previous reset/reboot
1575 + * used in reboot/reset lease grace period processing
1576 + *
1577 + * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed
1578   * setclientid_confirmed info. 
1579   *
1580   * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed 
1581 @@ -144,6 +150,8 @@ static void release_file(struct nfs4_fil
1582   * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
1583   * for last close replay.
1584   */
1585 +static struct list_head        reclaim_str_hashtbl[CLIENT_HASH_SIZE];
1586 +static int reclaim_str_hashtbl_size;
1587  static struct list_head        conf_id_hashtbl[CLIENT_HASH_SIZE];
1588  static struct list_head        conf_str_hashtbl[CLIENT_HASH_SIZE];
1589  static struct list_head        unconf_str_hashtbl[CLIENT_HASH_SIZE];
1590 @@ -208,12 +216,20 @@ free_client(struct nfs4_client *clp)
1591         kfree(clp);
1592  }
1593  
1594 -static void
1595 +void
1596 +put_nfs4_client(struct nfs4_client *clp)
1597 +{
1598 +       if (atomic_dec_and_test(&clp->cl_count))
1599 +               free_client(clp);
1600 +}
1601 +
1602 +void
1603  expire_client(struct nfs4_client *clp)
1604  {
1605         struct nfs4_stateowner *sop;
1606  
1607 -       dprintk("NFSD: expire_client\n");
1608 +       dprintk("NFSD: expire_client cl_count %d\n",
1609 +                   atomic_read(&clp->cl_count));
1610         list_del(&clp->cl_idhash);
1611         list_del(&clp->cl_strhash);
1612         list_del(&clp->cl_lru);
1613 @@ -221,7 +237,7 @@ expire_client(struct nfs4_client *clp)
1614                 sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient);
1615                 release_stateowner(sop);
1616         }
1617 -       free_client(clp);
1618 +       put_nfs4_client(clp);
1619  }
1620  
1621  static struct nfs4_client *
1622 @@ -230,6 +246,7 @@ create_client(struct xdr_netobj name) {
1623  
1624         if(!(clp = alloc_client(name)))
1625                 goto out;
1626 +       atomic_set(&clp->cl_count, 1);
1627         INIT_LIST_HEAD(&clp->cl_idhash);
1628         INIT_LIST_HEAD(&clp->cl_strhash);
1629         INIT_LIST_HEAD(&clp->cl_perclient);
1630 @@ -339,6 +356,99 @@ move_to_confirmed(struct nfs4_client *cl
1631         renew_client(clp);
1632  }
1633  
1634 +
1635 +/* a helper function for parse_callback */
1636 +static int
1637 +parse_octet(unsigned int *lenp, char **addrp)
1638 +{
1639 +       unsigned int len = *lenp;
1640 +       char *p = *addrp;
1641 +       int n = -1;
1642 +       char c;
1643 +
1644 +       for (;;) {
1645 +               if (!len)
1646 +                       break;
1647 +               len--;
1648 +               c = *p++;
1649 +               if (c == '.')
1650 +                       break;
1651 +               if ((c < '0') || (c > '9')) {
1652 +                       n = -1;
1653 +                       break;
1654 +               }
1655 +               if (n < 0)
1656 +                       n = 0;
1657 +               n = (n * 10) + (c - '0');
1658 +               if (n > 255) {
1659 +                       n = -1;
1660 +                       break;
1661 +               }
1662 +       }
1663 +       *lenp = len;
1664 +       *addrp = p;
1665 +       return n;
1666 +}
1667 +
1668 +/* parse and set the setclientid ipv4 callback address */
1669 +int
1670 +parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp)
1671 +{
1672 +       int temp = 0;
1673 +       u32 cbaddr = 0;
1674 +       u16 cbport = 0;
1675 +       u32 addrlen = addr_len;
1676 +       char *addr = addr_val;
1677 +       int i, shift;
1678 +
1679 +       /* ipaddress */
1680 +       shift = 24;
1681 +       for(i = 4; i > 0  ; i--) {
1682 +               if ((temp = parse_octet(&addrlen, &addr)) < 0) {
1683 +                       return 0;
1684 +               }
1685 +               cbaddr |= (temp << shift);
1686 +               if(shift > 0)
1687 +               shift -= 8;
1688 +       }
1689 +       *cbaddrp = cbaddr;
1690 +
1691 +       /* port */
1692 +       shift = 8;
1693 +       for(i = 2; i > 0  ; i--) {
1694 +               if ((temp = parse_octet(&addrlen, &addr)) < 0) {
1695 +                       return 0;
1696 +               }
1697 +               cbport |= (temp << shift);
1698 +               if(shift > 0)
1699 +                       shift -= 8;
1700 +       }
1701 +       *cbportp = cbport;
1702 +       return 1;
1703 +}
1704 +
1705 +void
1706 +gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
1707 +{
1708 +       struct nfs4_callback *cb = &clp->cl_callback;
1709 +
1710 +       if( !(parse_ipv4(se->se_callback_addr_len, se->se_callback_addr_val,
1711 +                        &cb->cb_addr, &cb->cb_port))) {
1712 +               printk(KERN_INFO "NFSD: BAD callback address. client will not receive delegations\n");
1713 +               printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
1714 +                       "will not receive delegations\n",
1715 +                       clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
1716 +
1717 +               cb->cb_parsed = 0;
1718 +               return;
1719 +       }
1720 +       cb->cb_netid.len = se->se_callback_netid_len;
1721 +       cb->cb_netid.data = se->se_callback_netid_val;
1722 +        cb->cb_prog = se->se_callback_prog;
1723 +        cb->cb_ident = se->se_callback_ident;
1724 +        cb->cb_parsed = 1;
1725 +}
1726 +
1727  /*
1728   * RFC 3010 has a complex implmentation description of processing a 
1729   * SETCLIENTID request consisting of 5 bullets, labeled as 
1730 @@ -450,6 +560,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp
1731                 copy_cred(&new->cl_cred,&rqstp->rq_cred);
1732                 gen_clid(new);
1733                 gen_confirm(new);
1734 +               gen_callback(new, setclid);
1735                 add_to_unconfirmed(new, strhashval);
1736         } else if (cmp_verf(&conf->cl_verifier, &clverifier)) {
1737                 /*
1738 @@ -477,6 +588,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp
1739                 copy_cred(&new->cl_cred,&rqstp->rq_cred);
1740                 copy_clid(new, conf);
1741                 gen_confirm(new);
1742 +               gen_callback(new, setclid);
1743                 add_to_unconfirmed(new,strhashval);
1744         } else if (!unconf) {
1745                 /*
1746 @@ -494,6 +606,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp
1747                 copy_cred(&new->cl_cred,&rqstp->rq_cred);
1748                 gen_clid(new);
1749                 gen_confirm(new);
1750 +               gen_callback(new, setclid);
1751                 add_to_unconfirmed(new, strhashval);
1752         } else if (!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm)) {
1753                 /*      
1754 @@ -519,6 +632,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp
1755                 copy_cred(&new->cl_cred,&rqstp->rq_cred);
1756                 gen_clid(new);
1757                 gen_confirm(new);
1758 +               gen_callback(new, setclid);
1759                 add_to_unconfirmed(new, strhashval);
1760         } else {
1761                 /* No cases hit !!! */
1762 @@ -529,7 +643,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp
1763         setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
1764         setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
1765         memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
1766 -       printk(KERN_INFO "NFSD: this client will not receive delegations\n");
1767         status = nfs_ok;
1768  out:
1769         nfs4_unlock_state();
1770 @@ -575,7 +688,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
1771                  * not been found.
1772                  */
1773                 if (clp->cl_addr != ip_addr) { 
1774 -                       printk("NFSD: setclientid: string in use by client"
1775 +                       dprintk("NFSD: setclientid: string in use by client"
1776                         "(clientid %08x/%08x)\n",
1777                         clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
1778                         goto out;
1779 @@ -588,7 +701,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
1780                         continue;
1781                 status = nfserr_inval;
1782                 if (clp->cl_addr != ip_addr) { 
1783 -                       printk("NFSD: setclientid: string in use by client"
1784 +                       dprintk("NFSD: setclientid: string in use by client"
1785                         "(clientid %08x/%08x)\n",
1786                         clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
1787                         goto out;
1788 @@ -610,6 +723,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
1789                         status = nfserr_clid_inuse;
1790                 else {
1791                         expire_client(conf);
1792 +                       clp = unconf;
1793                         move_to_confirmed(unconf, idhashval);
1794                         status = nfs_ok;
1795                 }
1796 @@ -627,6 +741,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
1797                 if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) {
1798                         status = nfserr_clid_inuse;
1799                 } else {
1800 +                       clp = conf;
1801                         status = nfs_ok;
1802                 }
1803                 goto out;
1804 @@ -641,6 +756,7 @@ nfsd4_setclientid_confirm(struct svc_rqs
1805                         status = nfserr_clid_inuse;
1806                 } else {
1807                         status = nfs_ok;
1808 +                       clp = unconf;
1809                         move_to_confirmed(unconf, idhashval);
1810                 }
1811                 goto out;
1812 @@ -660,7 +776,9 @@ nfsd4_setclientid_confirm(struct svc_rqs
1813         status = nfserr_inval;
1814         goto out;
1815  out:
1816 -       /* XXX if status == nfs_ok, probe callback path */
1817 +       if (!status)
1818 +               nfsd4_probe_callback(clp);
1819 +
1820         nfs4_unlock_state();
1821         return status;
1822  }
1823 @@ -1510,10 +1628,12 @@ nfs4_preprocess_seqid_op(struct svc_fh *
1824  
1825         status = nfserr_bad_stateid;
1826  
1827 -       /* for new lock stateowners, check that the lock->v.new.open_stateid
1828 -        * refers to an open stateowner, and that the lockclid
1829 -        * (nfs4_lock->v.new.clientid) is the same as the
1830 -        * open_stateid->st_stateowner->so_client->clientid
1831 +       /* for new lock stateowners: 
1832 +        * check that the lock->v.new.open_stateid
1833 +        * refers to an open stateowner
1834 +        * 
1835 +        * check that the lockclid (nfs4_lock->v.new.clientid) is the same 
1836 +        * as the open_stateid->st_stateowner->so_client->clientid
1837          */
1838         if (lockclid) {
1839                 struct nfs4_stateowner *sop = stp->st_stateowner;
1840 @@ -1599,6 +1719,17 @@ check_replay:
1841  }
1842  
1843  /*
1844 + * eventually, this will perform an upcall to the 'state daemon' as well as
1845 + * set the cl_first_state field.
1846 + */
1847 +void
1848 +first_state(struct nfs4_client *clp)
1849 +{
1850 +       if (!clp->cl_first_state)
1851 +               clp->cl_first_state = get_seconds();
1852 +}
1853 +
1854 +/*
1855   * nfs4_unlock_state(); called in encode
1856   */
1857  int
1858 @@ -1635,6 +1766,7 @@ nfsd4_open_confirm(struct svc_rqst *rqst
1859                          stp->st_stateid.si_fileid,
1860                          stp->st_stateid.si_generation);
1861         status = nfs_ok;
1862 +       first_state(sop->so_client);
1863  out:
1864         return status;
1865  }
1866 @@ -1850,6 +1982,21 @@ nfs4_set_lock_denied(struct file_lock *f
1867                 deny->ld_type = NFS4_WRITE_LT;
1868  }
1869  
1870 +static struct nfs4_stateowner *
1871 +find_lockstateowner(struct xdr_netobj *owner, clientid_t *clid)
1872 +{
1873 +       struct nfs4_stateowner *local = NULL;
1874 +       int i;
1875 +
1876 +       for (i = 0; i < LOCK_HASH_SIZE; i++) {
1877 +               list_for_each_entry(local, &lock_ownerid_hashtbl[i], so_idhash) {
1878 +                       if(!cmp_owner_str(local, owner, clid))
1879 +                               continue;
1880 +                       return local;
1881 +               }
1882 +       }
1883 +       return NULL;
1884 +}
1885  
1886  static int
1887  find_lockstateowner_str(unsigned int hashval, struct xdr_netobj *owner, clientid_t *clid, struct nfs4_stateowner **op) {
1888 @@ -1969,7 +2116,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
1889  
1890         if (nfs4_in_grace() && !lock->lk_reclaim)
1891                 return nfserr_grace;
1892 -       if (nfs4_in_no_grace() && lock->lk_reclaim)
1893 +       if (!nfs4_in_grace() && lock->lk_reclaim)
1894                 return nfserr_no_grace;
1895  
1896         if (check_lock_length(lock->lk_offset, lock->lk_length))
1897 @@ -1992,7 +2139,11 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
1898                         printk("NFSD: nfsd4_lock: clientid is stale!\n");
1899                         goto out;
1900                 }
1901 -               /* does the clientid in the lock owner own the open stateid? */
1902 +
1903 +               /* is the new lock seqid presented by the client zero? */
1904 +               status = nfserr_bad_seqid;
1905 +               if (lock->v.new.lock_seqid != 0)
1906 +                       goto out;
1907  
1908                 /* validate and update open stateid and open seqid */
1909                 status = nfs4_preprocess_seqid_op(current_fh, 
1910 @@ -2011,15 +2162,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
1911                 strhashval = lock_ownerstr_hashval(fp->fi_inode, 
1912                                 open_sop->so_client->cl_clientid.cl_id, 
1913                                 lock->v.new.owner);
1914 -
1915                 /* 
1916                  * If we already have this lock owner, the client is in 
1917                  * error (or our bookeeping is wrong!) 
1918                  * for asking for a 'new lock'.
1919                  */
1920                 status = nfserr_bad_stateid;
1921 -               if (find_lockstateowner_str(strhashval, &lock->v.new.owner,
1922 -                                       &lock->v.new.clientid, &lock_sop))
1923 +               lock_sop = find_lockstateowner(&lock->v.new.owner,
1924 +                                               &lock->v.new.clientid);
1925 +               if (lock_sop)
1926                         goto out;
1927                 status = nfserr_resource;
1928                 if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
1929 @@ -2315,7 +2466,7 @@ nfsd4_release_lockowner(struct svc_rqst 
1930         clientid_t *clid = &rlockowner->rl_clientid;
1931         struct nfs4_stateowner *local = NULL;
1932         struct xdr_netobj *owner = &rlockowner->rl_owner;
1933 -       int status, i;
1934 +       int status;
1935  
1936         dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
1937                 clid->cl_boot, clid->cl_id);
1938 @@ -2330,34 +2481,136 @@ nfsd4_release_lockowner(struct svc_rqst 
1939  
1940         nfs4_lock_state();
1941  
1942 -       /* find the lockowner */
1943          status = nfs_ok;
1944 -       for (i=0; i < LOCK_HASH_SIZE; i++)
1945 -               list_for_each_entry(local, &lock_ownerstr_hashtbl[i], so_strhash)
1946 -                       if(cmp_owner_str(local, owner, clid)) {
1947 -                               struct nfs4_stateid *stp;
1948 -
1949 -                               /* check for any locks held by any stateid
1950 -                                * associated with the (lock) stateowner */
1951 -                               status = nfserr_locks_held;
1952 -                               list_for_each_entry(stp, &local->so_perfilestate,
1953 -                                                   st_perfilestate) {
1954 -                                       if(stp->st_vfs_set) {
1955 -                                               if (check_for_locks(&stp->st_vfs_file,
1956 -                                                                   local))
1957 -                                                       goto out;
1958 -                                       }
1959 -                               }
1960 -                               /* no locks held by (lock) stateowner */
1961 -                               status = nfs_ok;
1962 -                               release_stateowner(local);
1963 -                               goto out;
1964 +       local = find_lockstateowner(owner, clid);
1965 +       if (local) {
1966 +               struct nfs4_stateid *stp;
1967 +
1968 +               /* check for any locks held by any stateid
1969 +                * associated with the (lock) stateowner */
1970 +               status = nfserr_locks_held;
1971 +               list_for_each_entry(stp, &local->so_perfilestate,
1972 +                               st_perfilestate) {
1973 +                       if(stp->st_vfs_set) {
1974 +                               if (check_for_locks(&stp->st_vfs_file, local))
1975 +                                       goto out;
1976                         }
1977 +               }
1978 +               /* no locks held by (lock) stateowner */
1979 +               status = nfs_ok;
1980 +               release_stateowner(local);
1981 +       }
1982  out:
1983         nfs4_unlock_state();
1984         return status;
1985  }
1986  
1987 +static inline struct nfs4_client_reclaim *
1988 +alloc_reclaim(int namelen)
1989 +{
1990 +       struct nfs4_client_reclaim *crp = NULL;
1991 +
1992 +       crp = kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
1993 +       if (!crp)
1994 +               return NULL;
1995 +       crp->cr_name.data = kmalloc(namelen, GFP_KERNEL);
1996 +       if (!crp->cr_name.data) {
1997 +               kfree(crp);
1998 +               return NULL;
1999 +       }
2000 +               return crp;
2001 +}
2002 +
2003 +/*
2004 + * failure => all reset bets are off, nfserr_no_grace...
2005 + */
2006 +static int
2007 +nfs4_client_to_reclaim(struct nfs4_client *clp)
2008 +{
2009 +       unsigned int strhashval;
2010 +       struct nfs4_client_reclaim *crp = NULL;
2011 +
2012 +       crp = alloc_reclaim(clp->cl_name.len);
2013 +       if (!crp)
2014 +               return 0;
2015 +       strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len);
2016 +       INIT_LIST_HEAD(&crp->cr_strhash);
2017 +       list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
2018 +       memcpy(crp->cr_name.data, clp->cl_name.data, clp->cl_name.len);
2019 +       crp->cr_name.len = clp->cl_name.len;
2020 +       crp->cr_first_state = clp->cl_first_state;
2021 +       crp->cr_expired = 0;
2022 +       return 1;
2023 +}
2024 +
2025 +static void
2026 +nfs4_release_reclaim(void)
2027 +{
2028 +       struct nfs4_client_reclaim *crp = NULL;
2029 +       int i;
2030 +
2031 +       BUG_ON(!nfs4_reclaim_init);
2032 +       for (i = 0; i < CLIENT_HASH_SIZE; i++) {
2033 +               while (!list_empty(&reclaim_str_hashtbl[i])) {
2034 +                       crp = list_entry(reclaim_str_hashtbl[i].next,
2035 +                                       struct nfs4_client_reclaim, cr_strhash);
2036 +                       list_del(&crp->cr_strhash);
2037 +                       kfree(crp->cr_name.data);
2038 +                       kfree(crp);
2039 +                       reclaim_str_hashtbl_size--;
2040 +               }
2041 +       }
2042 +       BUG_ON(reclaim_str_hashtbl_size);
2043 +}
2044 +
2045 +/*
2046 + * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
2047 +struct nfs4_client_reclaim *
2048 +nfs4_find_reclaim_client(clientid_t *clid)
2049 +{
2050 +       unsigned int idhashval = clientid_hashval(clid->cl_id);
2051 +       unsigned int strhashval;
2052 +       struct nfs4_client *clp, *client = NULL;
2053 +       struct nfs4_client_reclaim *crp = NULL;
2054 +
2055 +
2056 +       /* find clientid in conf_id_hashtbl */
2057 +       list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
2058 +               if (cmp_clid(&clp->cl_clientid, clid)) {
2059 +                       client = clp;
2060 +                       break;
2061 +               }
2062 +       }
2063 +       if (!client)
2064 +               return NULL;
2065 +
2066 +       /* find clp->cl_name in reclaim_str_hashtbl */
2067 +       strhashval = clientstr_hashval(client->cl_name.data,
2068 +                                     client->cl_name.len);
2069 +       list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) {
2070 +               if(cmp_name(&crp->cr_name, &client->cl_name)) {
2071 +                       return crp;
2072 +               }
2073 +       }
2074 +       return NULL;
2075 +}
2076 +
2077 +/*
2078 +* Called from OPEN. Look for clientid in reclaim list.
2079 +*/
2080 +int
2081 +nfs4_check_open_reclaim(clientid_t *clid)
2082 +{
2083 +       struct nfs4_client_reclaim *crp;
2084 +
2085 +       if ((crp = nfs4_find_reclaim_client(clid)) == NULL)
2086 +               return nfserr_reclaim_bad;
2087 +       if (crp->cr_expired)
2088 +               return nfserr_no_grace;
2089 +       return nfs_ok;
2090 +}
2091 +
2092 +
2093  /* 
2094   * Start and stop routines
2095   */
2096 @@ -2366,10 +2619,16 @@ void 
2097  nfs4_state_init(void)
2098  {
2099         int i;
2100 -       time_t start = get_seconds();
2101 +       time_t grace_time;
2102  
2103         if (nfs4_init)
2104                 return;
2105 +       if (!nfs4_reclaim_init) {
2106 +               for (i = 0; i < CLIENT_HASH_SIZE; i++)
2107 +                       INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
2108 +               reclaim_str_hashtbl_size = 0;
2109 +               nfs4_reclaim_init = 1;
2110 +       }
2111         for (i = 0; i < CLIENT_HASH_SIZE; i++) {
2112                 INIT_LIST_HEAD(&conf_id_hashtbl[i]);
2113                 INIT_LIST_HEAD(&conf_str_hashtbl[i]);
2114 @@ -2396,27 +2655,36 @@ nfs4_state_init(void)
2115  
2116         INIT_LIST_HEAD(&close_lru);
2117         INIT_LIST_HEAD(&client_lru);
2118 -       init_MUTEX(&client_sema);
2119 -       boot_time = start;
2120 -       grace_end = start + NFSD_LEASE_TIME;
2121 +       boot_time = get_seconds();
2122 +       grace_time = max(old_lease_time, lease_time);
2123 +       if (reclaim_str_hashtbl_size == 0)
2124 +               grace_time = 0;
2125 +       if (grace_time)
2126 +               printk("NFSD: starting %ld-second grace period\n", grace_time);
2127 +       grace_end = boot_time + grace_time;
2128         INIT_WORK(&laundromat_work,laundromat_main, NULL);
2129         schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ);
2130         nfs4_init = 1;
2131 -
2132  }
2133  
2134  int
2135  nfs4_in_grace(void)
2136  {
2137 -       return time_before(get_seconds(), (unsigned long)grace_end);
2138 +       return get_seconds() < grace_end;
2139  }
2140  
2141 -int
2142 -nfs4_in_no_grace(void)
2143 +void
2144 +set_no_grace(void)
2145  {
2146 -       return (grace_end < get_seconds());
2147 +       printk("NFSD: ERROR in reboot recovery.  State reclaims will fail.\n");
2148 +       grace_end = get_seconds();
2149  }
2150  
2151 +time_t
2152 +nfs4_lease_time(void)
2153 +{
2154 +       return lease_time;
2155 +}
2156  
2157  static void
2158  __nfs4_state_shutdown(void)
2159 @@ -2454,6 +2722,61 @@ void
2160  nfs4_state_shutdown(void)
2161  {
2162         nfs4_lock_state();
2163 +       nfs4_release_reclaim();
2164         __nfs4_state_shutdown();
2165         nfs4_unlock_state();
2166  }
2167 +
2168 +/*
2169 + * Called when leasetime is changed.
2170 + *
2171 + * if nfsd is not started, simply set the global lease.
2172 + *
2173 + * if nfsd(s) are running, lease change requires nfsv4 state to be reset.
2174 + * e.g: boot_time is reset, existing nfs4_client structs are
2175 + * used to fill reclaim_str_hashtbl, then all state (except for the
2176 + * reclaim_str_hashtbl) is re-initialized.
2177 + *
2178 + * if the old lease time is greater than the new lease time, the grace
2179 + * period needs to be set to the old lease time to allow clients to reclaim
2180 + * their state. XXX - we may want to set the grace period == lease time
2181 + * after an initial grace period == old lease time
2182 + *
2183 + * if an error occurs in this process, the new lease is set, but the server
2184 + * will not honor OPEN or LOCK reclaims, and will return nfserr_no_grace
2185 + * which means OPEN/LOCK/READ/WRITE will fail during grace period.
2186 + *
2187 + * clients will attempt to reset all state with SETCLIENTID/CONFIRM, and
2188 + * OPEN and LOCK reclaims.
2189 + */
2190 +void
2191 +nfs4_reset_lease(time_t leasetime)
2192 +{
2193 +       struct nfs4_client *clp;
2194 +       int i;
2195 +
2196 +       printk("NFSD: New leasetime %ld\n",leasetime);
2197 +       if (!nfs4_init)
2198 +               return;
2199 +       nfs4_lock_state();
2200 +       old_lease_time = lease_time;
2201 +       lease_time = leasetime;
2202 +
2203 +       nfs4_release_reclaim();
2204 +
2205 +       /* populate reclaim_str_hashtbl with current confirmed nfs4_clientid */
2206 +       for (i = 0; i < CLIENT_HASH_SIZE; i++) {
2207 +               list_for_each_entry(clp, &conf_id_hashtbl[i], cl_idhash) {
2208 +                       if (!nfs4_client_to_reclaim(clp)) {
2209 +                               nfs4_release_reclaim();
2210 +                               goto init_state;
2211 +                       }
2212 +                       reclaim_str_hashtbl_size++;
2213 +               }
2214 +       }
2215 +init_state:
2216 +       __nfs4_state_shutdown();
2217 +       nfs4_state_init();
2218 +       nfs4_unlock_state();
2219 +}
2220 +
2221 --- linux-2.6.7/fs/nfsd/vfs.c.lsec      2004-06-15 23:19:13.000000000 -0600
2222 +++ linux-2.6.7/fs/nfsd/vfs.c   2005-03-23 14:28:24.520322040 -0700
2223 @@ -44,6 +44,16 @@
2224  #include <linux/nfsd/nfsfh.h>
2225  #include <linux/quotaops.h>
2226  #include <linux/dnotify.h>
2227 +#ifdef CONFIG_NFSD_V4
2228 +#include <linux/posix_acl.h>
2229 +#include <linux/posix_acl_xattr.h>
2230 +#include <linux/xattr_acl.h>
2231 +#include <linux/xattr.h>
2232 +#include <linux/nfs4.h>
2233 +#include <linux/nfs4_acl.h>
2234 +#include <linux/nfsd_idmap.h>
2235 +#include <linux/security.h>
2236 +#endif /* CONFIG_NFSD_V4 */
2237  
2238  #include <asm/uaccess.h>
2239  
2240 @@ -344,6 +354,177 @@ out_nfserr:
2241         goto out;
2242  }
2243  
2244 +#if defined(CONFIG_NFSD_V4)
2245 +
2246 +static int
2247 +set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
2248 +{
2249 +       int len;
2250 +       size_t buflen;
2251 +       char *buf = NULL;
2252 +       int error = 0;
2253 +       struct inode *inode = dentry->d_inode;
2254 +
2255 +       buflen = posix_acl_xattr_size(pacl->a_count);
2256 +       buf = kmalloc(buflen, GFP_KERNEL);
2257 +       error = -ENOMEM;
2258 +       if (buf == NULL)
2259 +               goto out;
2260 +
2261 +       len = posix_acl_to_xattr(pacl, buf, buflen);
2262 +       if (len < 0) {
2263 +               error = len;
2264 +               goto out;
2265 +       }
2266 +
2267 +       error = -EOPNOTSUPP;
2268 +       if (inode->i_op && inode->i_op->setxattr) {
2269 +               down(&inode->i_sem);
2270 +               security_inode_setxattr(dentry, key, buf, len, 0);
2271 +               error = inode->i_op->setxattr(dentry, key, buf, len, 0);
2272 +               if (!error)
2273 +                       security_inode_post_setxattr(dentry, key, buf, len, 0);
2274 +               up(&inode->i_sem);
2275 +       }
2276 +out:
2277 +       kfree(buf);
2278 +       return (error);
2279 +}
2280 +
2281 +int
2282 +nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
2283 +    struct nfs4_acl *acl)
2284 +{
2285 +       int error;
2286 +       struct dentry *dentry;
2287 +       struct inode *inode;
2288 +       struct posix_acl *pacl = NULL, *dpacl = NULL;
2289 +       unsigned int flags = 0;
2290 +
2291 +       /* Get inode */
2292 +       error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
2293 +       if (error)
2294 +               goto out;
2295 +
2296 +       dentry = fhp->fh_dentry;
2297 +       inode = dentry->d_inode;
2298 +       if (S_ISDIR(inode->i_mode))
2299 +               flags = NFS4_ACL_DIR;
2300 +
2301 +       error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
2302 +       if (error < 0)
2303 +               goto out_nfserr;
2304 +
2305 +       if (pacl) {
2306 +               error = set_nfsv4_acl_one(dentry, pacl, XATTR_NAME_ACL_ACCESS);
2307 +               if (error < 0)
2308 +                       goto out_nfserr;
2309 +       }
2310 +
2311 +       if (dpacl) {
2312 +               error = set_nfsv4_acl_one(dentry, dpacl, XATTR_NAME_ACL_DEFAULT);
2313 +               if (error < 0)
2314 +                       goto out_nfserr;
2315 +       }
2316 +
2317 +       error = nfs_ok;
2318 +
2319 +out:
2320 +       posix_acl_release(pacl);
2321 +       posix_acl_release(dpacl);
2322 +       return (error);
2323 +out_nfserr:
2324 +       error = nfserrno(error);
2325 +       goto out;
2326 +}
2327 +
2328 +static struct posix_acl *
2329 +_get_posix_acl(struct dentry *dentry, char *key)
2330 +{
2331 +       struct inode *inode = dentry->d_inode;
2332 +       char *buf = NULL;
2333 +       int buflen, error = 0;
2334 +       struct posix_acl *pacl = NULL;
2335 +
2336 +       down(&inode->i_sem);
2337 +
2338 +       buflen = inode->i_op->getxattr(dentry, key, NULL, 0);
2339 +       if (buflen <= 0) {
2340 +               error = buflen < 0 ? buflen : -ENODATA;
2341 +               goto out_sem;
2342 +       }
2343 +
2344 +       buf = kmalloc(buflen, GFP_KERNEL);
2345 +       if (buf == NULL) {
2346 +               error = -ENOMEM;
2347 +               goto out_sem;
2348 +       }
2349 +
2350 +       error = -EOPNOTSUPP;
2351 +       if (inode->i_op && inode->i_op->getxattr) {
2352 +               error = security_inode_getxattr(dentry, key);
2353 +               if (error)
2354 +                       goto out_sem;
2355 +               error = inode->i_op->getxattr(dentry, key, buf, buflen);
2356 +       }
2357 +       if (error < 0)
2358 +               goto out_sem;
2359 +
2360 +       error = 0;
2361 +       up(&inode->i_sem);
2362 +
2363 +       pacl = posix_acl_from_xattr(buf, buflen);
2364 + out:
2365 +       kfree(buf);
2366 +       return pacl;
2367 + out_sem:
2368 +       up(&inode->i_sem);
2369 +       pacl = ERR_PTR(error);
2370 +       goto out;
2371 +}
2372 +
2373 +int
2374 +nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl)
2375 +{
2376 +       struct inode *inode = dentry->d_inode;
2377 +       int error = 0;
2378 +       struct posix_acl *pacl = NULL, *dpacl = NULL;
2379 +       unsigned int flags = 0;
2380 +
2381 +       pacl = _get_posix_acl(dentry, XATTR_NAME_ACL_ACCESS);
2382 +       if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA)
2383 +               pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
2384 +       if (IS_ERR(pacl)) {
2385 +               error = PTR_ERR(pacl);
2386 +               pacl = NULL;
2387 +               goto out;
2388 +       }
2389 +
2390 +       if (S_ISDIR(inode->i_mode)) {
2391 +               dpacl = _get_posix_acl(dentry, XATTR_NAME_ACL_DEFAULT);
2392 +               if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA)
2393 +                       dpacl = NULL;
2394 +               else if (IS_ERR(dpacl)) {
2395 +                       error = PTR_ERR(dpacl);
2396 +                       dpacl = NULL;
2397 +                       goto out;
2398 +               }
2399 +               flags = NFS4_ACL_DIR;
2400 +       }
2401 +
2402 +       *acl = nfs4_acl_posix_to_nfsv4(pacl, dpacl, flags);
2403 +       if (IS_ERR(*acl)) {
2404 +               error = PTR_ERR(*acl);
2405 +               *acl = NULL;
2406 +       }
2407 + out:
2408 +       posix_acl_release(pacl);
2409 +       posix_acl_release(dpacl);
2410 +       return error;
2411 +}
2412 +
2413 +#endif /* defined(CONFIG_NFS_V4) */
2414 +
2415  #ifdef CONFIG_NFSD_V3
2416  /*
2417   * Check server access rights to a file system object
2418 --- linux-2.6.7/fs/nfsd/nfs4idmap.c.lsec        2004-06-15 23:19:43.000000000 -0600
2419 +++ linux-2.6.7/fs/nfsd/nfs4idmap.c     2005-03-23 14:28:24.687296656 -0700
2420 @@ -78,9 +78,9 @@ struct ent {
2421  
2422  #define DefineSimpleCacheLookupMap(STRUCT, FUNC)                       \
2423          DefineCacheLookup(struct STRUCT, h, FUNC##_lookup,             \
2424 -        (struct STRUCT *item, int set), /*no setup */,                 \
2425 +        (struct STRUCT *item, int set),                        \
2426         & FUNC##_cache, FUNC##_hash(item), FUNC##_match(item, tmp),     \
2427 -       STRUCT##_init(new, item), STRUCT##_update(tmp, item), 0)
2428 +       STRUCT##_init(new, item), STRUCT##_update(tmp, item))
2429  
2430  /* Common entry handling */
2431  
2432 --- linux-2.6.7/fs/nfsd/nfs4acl.c.lsec  2005-03-23 14:28:24.463330704 -0700
2433 +++ linux-2.6.7/fs/nfsd/nfs4acl.c       2005-03-23 14:28:24.463330704 -0700
2434 @@ -0,0 +1,974 @@
2435 +/*
2436 + *  fs/nfs4acl/acl.c
2437 + *
2438 + *  Common NFSv4 ACL handling code.
2439 + *
2440 + *  Copyright (c) 2002, 2003 The Regents of the University of Michigan.
2441 + *  All rights reserved.
2442 + *
2443 + *  Marius Aamodt Eriksen <marius@umich.edu>
2444 + *  Jeff Sedlak <jsedlak@umich.edu>
2445 + *  J. Bruce Fields <bfields@umich.edu>
2446 + *
2447 + *  Redistribution and use in source and binary forms, with or without
2448 + *  modification, are permitted provided that the following conditions
2449 + *  are met:
2450 + *
2451 + *  1. Redistributions of source code must retain the above copyright
2452 + *     notice, this list of conditions and the following disclaimer.
2453 + *  2. Redistributions in binary form must reproduce the above copyright
2454 + *     notice, this list of conditions and the following disclaimer in the
2455 + *     documentation and/or other materials provided with the distribution.
2456 + *  3. Neither the name of the University nor the names of its
2457 + *     contributors may be used to endorse or promote products derived
2458 + *     from this software without specific prior written permission.
2459 + *
2460 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
2461 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2462 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2463 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2464 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2465 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2466 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2467 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2468 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2469 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
2470 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2471 + */
2472 +
2473 +#include <linux/string.h>
2474 +#include <linux/slab.h>
2475 +#include <linux/list.h>
2476 +#include <linux/types.h>
2477 +#include <linux/fs.h>
2478 +#include <linux/module.h>
2479 +#include <linux/nfs_fs.h>
2480 +#include <linux/posix_acl.h>
2481 +#include <linux/nfs4.h>
2482 +#include <linux/nfs4_acl.h>
2483 +
2484 +
2485 +/* mode bit translations: */
2486 +#define NFS4_READ_MODE (NFS4_ACE_READ_DATA | NFS4_ACE_READ_NAMED_ATTRS)
2487 +#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_WRITE_NAMED_ATTRS | NFS4_ACE_APPEND_DATA)
2488 +#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
2489 +#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL | NFS4_ACE_SYNCHRONIZE)
2490 +#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
2491 +
2492 +/* flags used to simulate posix default ACLs */
2493 +#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
2494 +               | NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE)
2495 +
2496 +#define MASK_EQUAL(mask1, mask2) \
2497 +       ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )
2498 +
2499 +static u32
2500 +mask_from_posix(unsigned short perm, unsigned int flags)
2501 +{
2502 +       int mask = NFS4_ANYONE_MODE;
2503 +
2504 +       if (flags & NFS4_ACL_OWNER)
2505 +               mask |= NFS4_OWNER_MODE;
2506 +       if (perm & ACL_READ)
2507 +               mask |= NFS4_READ_MODE;
2508 +       if (perm & ACL_WRITE)
2509 +               mask |= NFS4_WRITE_MODE;
2510 +       if ((perm & ACL_WRITE) && (flags & NFS4_ACL_DIR))
2511 +               mask |= NFS4_ACE_DELETE_CHILD;
2512 +       if (perm & ACL_EXECUTE)
2513 +               mask |= NFS4_EXECUTE_MODE;
2514 +       return mask;
2515 +}
2516 +
2517 +static u32
2518 +deny_mask(u32 allow_mask, unsigned int flags)
2519 +{
2520 +       u32 ret = ~allow_mask & ~NFS4_ACE_DELETE;
2521 +       if (!(flags & NFS4_ACL_DIR))
2522 +               ret &= ~NFS4_ACE_DELETE_CHILD;
2523 +       return ret;
2524 +}
2525 +
2526 +static int
2527 +mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
2528 +{
2529 +       u32 ignore = 0;
2530 +
2531 +       if (!(flags & NFS4_ACL_DIR))
2532 +               ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */
2533 +       perm |= ignore;
2534 +       *mode = 0;
2535 +       if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
2536 +               *mode |= ACL_READ;
2537 +       if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE)
2538 +               *mode |= ACL_WRITE;
2539 +       if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
2540 +               *mode |= ACL_EXECUTE;
2541 +       if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags)))
2542 +               return -EINVAL;
2543 +       return 0;
2544 +}
2545 +
2546 +struct ace_container {
2547 +       struct nfs4_ace  *ace;
2548 +       struct list_head  ace_l;
2549 +};
2550 +
2551 +static short ace2type(struct nfs4_ace *);
2552 +static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int);
2553 +static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl *, unsigned int);
2554 +int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
2555 +int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *);
2556 +
2557 +struct nfs4_acl *
2558 +nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
2559 +                       unsigned int flags)
2560 +{
2561 +       struct nfs4_acl *acl;
2562 +       int error = -EINVAL;
2563 +
2564 +       if ((pacl != NULL &&
2565 +               (posix_acl_valid(pacl) < 0 || pacl->a_count == 0)) ||
2566 +           (dpacl != NULL &&
2567 +               (posix_acl_valid(dpacl) < 0 || dpacl->a_count == 0)))
2568 +               goto out_err;
2569 +
2570 +       acl = nfs4_acl_new();
2571 +       if (acl == NULL) {
2572 +               error = -ENOMEM;
2573 +               goto out_err;
2574 +       }
2575 +
2576 +       if (pacl != NULL) {
2577 +               error = _posix_to_nfsv4_one(pacl, acl,
2578 +                                               flags & ~NFS4_ACL_TYPE_DEFAULT);
2579 +               if (error < 0)
2580 +                       goto out_acl;
2581 +       }
2582 +
2583 +       if (dpacl != NULL) {
2584 +               error = _posix_to_nfsv4_one(dpacl, acl,
2585 +                                               flags | NFS4_ACL_TYPE_DEFAULT);
2586 +               if (error < 0)
2587 +                       goto out_acl;
2588 +       }
2589 +
2590 +       return acl;
2591 +
2592 +out_acl:
2593 +       nfs4_acl_free(acl);
2594 +out_err:
2595 +       acl = ERR_PTR(error);
2596 +
2597 +       return acl;
2598 +}
2599 +
2600 +static int
2601 +nfs4_acl_add_pair(struct nfs4_acl *acl, int eflag, u32 mask, int whotype,
2602 +               uid_t owner, unsigned int flags)
2603 +{
2604 +       int error;
2605 +
2606 +       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
2607 +                                eflag, mask, whotype, owner);
2608 +       if (error < 0)
2609 +               return error;
2610 +       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
2611 +                               eflag, deny_mask(mask, flags), whotype, owner);
2612 +       return error;
2613 +}
2614 +
2615 +/* We assume the acl has been verified with posix_acl_valid. */
2616 +static int
2617 +_posix_to_nfsv4_one(struct posix_acl *pacl, struct nfs4_acl *acl,
2618 +                                               unsigned int flags)
2619 +{
2620 +       struct posix_acl_entry *pa, *pe, *group_owner_entry;
2621 +       int error = -EINVAL;
2622 +       u32 mask, mask_mask;
2623 +       int eflag = ((flags & NFS4_ACL_TYPE_DEFAULT) ?
2624 +                                       NFS4_INHERITANCE_FLAGS : 0);
2625 +
2626 +       BUG_ON(pacl->a_count < 3);
2627 +       pe = pacl->a_entries + pacl->a_count;
2628 +       pa = pe - 2; /* if mask entry exists, it's second from the last. */
2629 +       if (pa->e_tag == ACL_MASK)
2630 +               mask_mask = deny_mask(mask_from_posix(pa->e_perm, flags), flags);
2631 +       else
2632 +               mask_mask = 0;
2633 +
2634 +       pa = pacl->a_entries;
2635 +       BUG_ON(pa->e_tag != ACL_USER_OBJ);
2636 +       mask = mask_from_posix(pa->e_perm, flags | NFS4_ACL_OWNER);
2637 +       error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_OWNER, 0, flags);
2638 +       if (error < 0)
2639 +               goto out;
2640 +       pa++;
2641 +
2642 +       while (pa->e_tag == ACL_USER) {
2643 +               mask = mask_from_posix(pa->e_perm, flags);
2644 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
2645 +                               eflag,  mask_mask, NFS4_ACL_WHO_NAMED, pa->e_id);
2646 +               if (error < 0)
2647 +                       goto out;
2648 +
2649 +
2650 +               error = nfs4_acl_add_pair(acl, eflag, mask,
2651 +                               NFS4_ACL_WHO_NAMED, pa->e_id, flags);
2652 +               if (error < 0)
2653 +                       goto out;
2654 +               pa++;
2655 +       }
2656 +
2657 +       /* In the case of groups, we apply allow ACEs first, then deny ACEs,
2658 +        * since a user can be in more than one group.  */
2659 +
2660 +       /* allow ACEs */
2661 +
2662 +       if (pacl->a_count > 3) {
2663 +               BUG_ON(pa->e_tag != ACL_GROUP_OBJ);
2664 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
2665 +                               NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask,
2666 +                               NFS4_ACL_WHO_GROUP, 0);
2667 +               if (error < 0)
2668 +                       goto out;
2669 +       }
2670 +       group_owner_entry = pa;
2671 +       mask = mask_from_posix(pa->e_perm, flags);
2672 +       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
2673 +                       NFS4_ACE_IDENTIFIER_GROUP | eflag, mask,
2674 +                       NFS4_ACL_WHO_GROUP, 0);
2675 +       if (error < 0)
2676 +               goto out;
2677 +       pa++;
2678 +
2679 +       while (pa->e_tag == ACL_GROUP) {
2680 +               mask = mask_from_posix(pa->e_perm, flags);
2681 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
2682 +                               NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask,
2683 +                               NFS4_ACL_WHO_NAMED, pa->e_id);
2684 +               if (error < 0)
2685 +                       goto out;
2686 +
2687 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
2688 +                               NFS4_ACE_IDENTIFIER_GROUP | eflag, mask,
2689 +                               NFS4_ACL_WHO_NAMED, pa->e_id);
2690 +               if (error < 0)
2691 +                       goto out;
2692 +               pa++;
2693 +       }
2694 +
2695 +       /* deny ACEs */
2696 +
2697 +       pa = group_owner_entry;
2698 +       mask = mask_from_posix(pa->e_perm, flags);
2699 +       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
2700 +                       NFS4_ACE_IDENTIFIER_GROUP | eflag,
2701 +                       deny_mask(mask, flags), NFS4_ACL_WHO_GROUP, 0);
2702 +       if (error < 0)
2703 +               goto out;
2704 +       pa++;
2705 +       while (pa->e_tag == ACL_GROUP) {
2706 +               mask = mask_from_posix(pa->e_perm, flags);
2707 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
2708 +                               NFS4_ACE_IDENTIFIER_GROUP | eflag,
2709 +                               deny_mask(mask, flags), NFS4_ACL_WHO_NAMED, pa->e_id);
2710 +               if (error < 0)
2711 +                       goto out;
2712 +               pa++;
2713 +       }
2714 +
2715 +       if (pa->e_tag == ACL_MASK)
2716 +               pa++;
2717 +       BUG_ON(pa->e_tag != ACL_OTHER);
2718 +       mask = mask_from_posix(pa->e_perm, flags);
2719 +       error = nfs4_acl_add_pair(acl, eflag, mask, NFS4_ACL_WHO_EVERYONE, 0, flags);
2720 +
2721 +out:
2722 +       return error;
2723 +}
2724 +
2725 +static void
2726 +sort_pacl_range(struct posix_acl *pacl, int start, int end) {
2727 +       int sorted = 0, i;
2728 +       struct posix_acl_entry tmp;
2729 +
2730 +       /* We just do a bubble sort; easy to do in place, and we're not
2731 +        * expecting acl's to be long enough to justify anything more. */
2732 +       while (!sorted) {
2733 +               sorted = 1;
2734 +               for (i = start; i < end; i++) {
2735 +                       if (pacl->a_entries[i].e_id
2736 +                                       > pacl->a_entries[i+1].e_id) {
2737 +                               sorted = 0;
2738 +                               tmp = pacl->a_entries[i];
2739 +                               pacl->a_entries[i] = pacl->a_entries[i+1];
2740 +                               pacl->a_entries[i+1] = tmp;
2741 +                       }
2742 +               }
2743 +       }
2744 +}
2745 +
2746 +static void
2747 +sort_pacl(struct posix_acl *pacl)
2748 +{
2749 +       /* posix_acl_valid requires that users and groups be in order
2750 +        * by uid/gid. */
2751 +       int i, j;
2752 +
2753 +       if (pacl->a_count <= 4)
2754 +               return; /* no users or groups */
2755 +       i = 1;
2756 +       while (pacl->a_entries[i].e_tag == ACL_USER)
2757 +               i++;
2758 +       sort_pacl_range(pacl, 1, i-1);
2759 +
2760 +       BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);
2761 +       j = i++;
2762 +       while (pacl->a_entries[j].e_tag == ACL_GROUP)
2763 +               j++;
2764 +       sort_pacl_range(pacl, i, j-1);
2765 +       return;
2766 +}
2767 +
2768 +static int
2769 +write_pace(struct nfs4_ace *ace, struct posix_acl *pacl,
2770 +               struct posix_acl_entry **pace, short tag, unsigned int flags)
2771 +{
2772 +       struct posix_acl_entry *this = *pace;
2773 +
2774 +       if (*pace == pacl->a_entries + pacl->a_count)
2775 +               return -EINVAL; /* fell off the end */
2776 +       (*pace)++;
2777 +       this->e_tag = tag;
2778 +       if (tag == ACL_USER_OBJ)
2779 +               flags |= NFS4_ACL_OWNER;
2780 +       if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags))
2781 +               return -EINVAL;
2782 +       this->e_id = (tag == ACL_USER || tag == ACL_GROUP ?
2783 +                       ace->who : ACL_UNDEFINED_ID);
2784 +       return 0;
2785 +}
2786 +
2787 +static struct nfs4_ace *
2788 +get_next_v4_ace(struct list_head **p, struct list_head *head)
2789 +{
2790 +       struct nfs4_ace *ace;
2791 +
2792 +       *p = (*p)->next;
2793 +       if (*p == head)
2794 +               return NULL;
2795 +       ace = list_entry(*p, struct nfs4_ace, l_ace);
2796 +
2797 +       return ace;
2798 +}
2799 +
2800 +int
2801 +nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
2802 +               struct posix_acl **dpacl, unsigned int flags)
2803 +{
2804 +       struct nfs4_acl *dacl;
2805 +       int error = -ENOMEM;
2806 +
2807 +       *pacl = NULL;
2808 +       *dpacl = NULL;
2809 +
2810 +       dacl = nfs4_acl_new();
2811 +       if (dacl == NULL)
2812 +               goto out;
2813 +
2814 +       error = nfs4_acl_split(acl, dacl);
2815 +       if (error < 0)
2816 +               goto out_acl;
2817 +
2818 +       if (pacl != NULL) {
2819 +               if (acl->naces == 0) {
2820 +                       error = -ENODATA;
2821 +                       goto try_dpacl;
2822 +               }
2823 +
2824 +               *pacl = _nfsv4_to_posix_one(acl, flags);
2825 +               if (IS_ERR(*pacl)) {
2826 +                       error = PTR_ERR(*pacl);
2827 +                       *pacl = NULL;
2828 +                       goto out_acl;
2829 +               }
2830 +       }
2831 +
2832 +try_dpacl:
2833 +       if (dpacl != NULL) {
2834 +               if (dacl->naces == 0) {
2835 +                       if (pacl == NULL || *pacl == NULL)
2836 +                               error = -ENODATA;
2837 +                       goto out_acl;
2838 +               }
2839 +
2840 +               error = 0;
2841 +               *dpacl = _nfsv4_to_posix_one(dacl, flags);
2842 +               if (IS_ERR(*dpacl)) {
2843 +                       error = PTR_ERR(*dpacl);
2844 +                       *dpacl = NULL;
2845 +                       goto out_acl;
2846 +               }
2847 +       }
2848 +
2849 +out_acl:
2850 +       if (error && pacl) {
2851 +               posix_acl_release(*pacl);
2852 +               *pacl = NULL;
2853 +       }
2854 +       nfs4_acl_free(dacl);
2855 +out:
2856 +       return error;
2857 +}
2858 +
2859 +static int
2860 +same_who(struct nfs4_ace *a, struct nfs4_ace *b)
2861 +{
2862 +       return a->whotype == b->whotype &&
2863 +               (a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who);
2864 +}
2865 +
2866 +static int
2867 +complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny,
2868 +               unsigned int flags)
2869 +{
2870 +       int ignore = 0;
2871 +       if (!(flags & NFS4_ACL_DIR))
2872 +               ignore |= NFS4_ACE_DELETE_CHILD;
2873 +       return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags),
2874 +                         ignore|deny->access_mask) &&
2875 +               allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
2876 +               deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE &&
2877 +               allow->flag == deny->flag &&
2878 +               same_who(allow, deny);
2879 +}
2880 +
2881 +static inline int
2882 +user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
2883 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
2884 +               unsigned int flags)
2885 +{
2886 +       int error = -EINVAL;
2887 +       struct nfs4_ace *ace, *ace2;
2888 +
2889 +       ace = get_next_v4_ace(p, &n4acl->ace_head);
2890 +       if (ace == NULL)
2891 +               goto out;
2892 +       if (ace2type(ace) != ACL_USER_OBJ)
2893 +               goto out;
2894 +       error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags);
2895 +       if (error < 0)
2896 +               goto out;
2897 +       error = -EINVAL;
2898 +       ace2 = get_next_v4_ace(p, &n4acl->ace_head);
2899 +       if (ace2 == NULL)
2900 +               goto out;
2901 +       if (!complementary_ace_pair(ace, ace2, flags))
2902 +               goto out;
2903 +       error = 0;
2904 +out:
2905 +       return error;
2906 +}
2907 +
2908 +static inline int
2909 +users_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
2910 +               struct nfs4_ace **mask_ace,
2911 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
2912 +               unsigned int flags)
2913 +{
2914 +       int error = -EINVAL;
2915 +       struct nfs4_ace *ace, *ace2;
2916 +
2917 +       ace = get_next_v4_ace(p, &n4acl->ace_head);
2918 +       if (ace == NULL)
2919 +               goto out;
2920 +       while (ace2type(ace) == ACL_USER) {
2921 +               if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
2922 +                       goto out;
2923 +               if (*mask_ace &&
2924 +                       !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
2925 +                       goto out;
2926 +               *mask_ace = ace;
2927 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
2928 +               if (ace == NULL)
2929 +                       goto out;
2930 +               if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
2931 +                       goto out;
2932 +               error = write_pace(ace, pacl, pace, ACL_USER, flags);
2933 +               if (error < 0)
2934 +                       goto out;
2935 +               error = -EINVAL;
2936 +               ace2 = get_next_v4_ace(p, &n4acl->ace_head);
2937 +               if (ace2 == NULL)
2938 +                       goto out;
2939 +               if (!complementary_ace_pair(ace, ace2, flags))
2940 +                       goto out;
2941 +               if ((*mask_ace)->flag != ace2->flag ||
2942 +                               !same_who(*mask_ace, ace2))
2943 +                       goto out;
2944 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
2945 +               if (ace == NULL)
2946 +                       goto out;
2947 +       }
2948 +       error = 0;
2949 +out:
2950 +       return error;
2951 +}
2952 +
2953 +static inline int
2954 +group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
2955 +               struct nfs4_ace **mask_ace,
2956 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
2957 +               unsigned int flags)
2958 +{
2959 +       int error = -EINVAL;
2960 +       struct nfs4_ace *ace, *ace2;
2961 +       struct ace_container *ac;
2962 +       struct list_head group_l;
2963 +
2964 +       INIT_LIST_HEAD(&group_l);
2965 +       ace = list_entry(*p, struct nfs4_ace, l_ace);
2966 +
2967 +       /* group owner (mask and allow aces) */
2968 +
2969 +       if (pacl->a_count != 3) {
2970 +               /* then the group owner should be preceded by mask */
2971 +               if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
2972 +                       goto out;
2973 +               if (*mask_ace &&
2974 +                       !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
2975 +                       goto out;
2976 +               *mask_ace = ace;
2977 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
2978 +               if (ace == NULL)
2979 +                       goto out;
2980 +
2981 +               if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace))
2982 +                       goto out;
2983 +       }
2984 +
2985 +       if (ace2type(ace) != ACL_GROUP_OBJ)
2986 +               goto out;
2987 +
2988 +       ac = kmalloc(sizeof(*ac), GFP_KERNEL);
2989 +       error = -ENOMEM;
2990 +       if (ac == NULL)
2991 +               goto out;
2992 +       ac->ace = ace;
2993 +       list_add_tail(&ac->ace_l, &group_l);
2994 +
2995 +       error = -EINVAL;
2996 +       if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
2997 +               goto out;
2998 +
2999 +       error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags);
3000 +       if (error < 0)
3001 +               goto out;
3002 +
3003 +       error = -EINVAL;
3004 +       ace = get_next_v4_ace(p, &n4acl->ace_head);
3005 +       if (ace == NULL)
3006 +               goto out;
3007 +
3008 +       /* groups (mask and allow aces) */
3009 +
3010 +       while (ace2type(ace) == ACL_GROUP) {
3011 +               if (*mask_ace == NULL)
3012 +                       goto out;
3013 +
3014 +               if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
3015 +                       !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
3016 +                       goto out;
3017 +               *mask_ace = ace;
3018 +
3019 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
3020 +               if (ace == NULL)
3021 +                       goto out;
3022 +               ac = kmalloc(sizeof(*ac), GFP_KERNEL);
3023 +               error = -ENOMEM;
3024 +               if (ac == NULL)
3025 +                       goto out;
3026 +               error = -EINVAL;
3027 +               if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE ||
3028 +                               !same_who(ace, *mask_ace))
3029 +                       goto out;
3030 +
3031 +               ac->ace = ace;
3032 +               list_add_tail(&ac->ace_l, &group_l);
3033 +
3034 +               error = write_pace(ace, pacl, pace, ACL_GROUP, flags);
3035 +               if (error < 0)
3036 +                       goto out;
3037 +               error = -EINVAL;
3038 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
3039 +               if (ace == NULL)
3040 +                       goto out;
3041 +       }
3042 +
3043 +       /* group owner (deny ace) */
3044 +
3045 +       if (ace2type(ace) != ACL_GROUP_OBJ)
3046 +               goto out;
3047 +       ac = list_entry(group_l.next, struct ace_container, ace_l);
3048 +       ace2 = ac->ace;
3049 +       if (!complementary_ace_pair(ace2, ace, flags))
3050 +               goto out;
3051 +       list_del(group_l.next);
3052 +       kfree(ac);
3053 +
3054 +       /* groups (deny aces) */
3055 +
3056 +       while (!list_empty(&group_l)) {
3057 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
3058 +               if (ace == NULL)
3059 +                       goto out;
3060 +               if (ace2type(ace) != ACL_GROUP)
3061 +                       goto out;
3062 +               ac = list_entry(group_l.next, struct ace_container, ace_l);
3063 +               ace2 = ac->ace;
3064 +               if (!complementary_ace_pair(ace2, ace, flags))
3065 +                       goto out;
3066 +               list_del(group_l.next);
3067 +               kfree(ac);
3068 +       }
3069 +
3070 +       ace = get_next_v4_ace(p, &n4acl->ace_head);
3071 +       if (ace == NULL)
3072 +               goto out;
3073 +       if (ace2type(ace) != ACL_OTHER)
3074 +               goto out;
3075 +       error = 0;
3076 +out:
3077 +       while (!list_empty(&group_l)) {
3078 +               ac = list_entry(group_l.next, struct ace_container, ace_l);
3079 +               list_del(group_l.next);
3080 +               kfree(ac);
3081 +       }
3082 +       return error;
3083 +}
3084 +
3085 +static inline int
3086 +mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
3087 +               struct nfs4_ace **mask_ace,
3088 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
3089 +               unsigned int flags)
3090 +{
3091 +       int error = -EINVAL;
3092 +       struct nfs4_ace *ace;
3093 +
3094 +       ace = list_entry(*p, struct nfs4_ace, l_ace);
3095 +       if (pacl->a_count != 3) {
3096 +               if (*mask_ace == NULL)
3097 +                       goto out;
3098 +               (*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags);
3099 +               write_pace(*mask_ace, pacl, pace, ACL_MASK, flags);
3100 +       }
3101 +       error = 0;
3102 +out:
3103 +       return error;
3104 +}
3105 +
3106 +static inline int
3107 +other_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
3108 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
3109 +               unsigned int flags)
3110 +{
3111 +       int error = -EINVAL;
3112 +       struct nfs4_ace *ace, *ace2;
3113 +
3114 +       ace = list_entry(*p, struct nfs4_ace, l_ace);
3115 +       if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
3116 +               goto out;
3117 +       error = write_pace(ace, pacl, pace, ACL_OTHER, flags);
3118 +       if (error < 0)
3119 +               goto out;
3120 +       error = -EINVAL;
3121 +       ace2 = get_next_v4_ace(p, &n4acl->ace_head);
3122 +       if (ace2 == NULL)
3123 +               goto out;
3124 +       if (!complementary_ace_pair(ace, ace2, flags))
3125 +               goto out;
3126 +       error = 0;
3127 +out:
3128 +       return error;
3129 +}
3130 +
3131 +static int
3132 +calculate_posix_ace_count(struct nfs4_acl *n4acl)
3133 +{
3134 +       if (n4acl->naces == 6) /* owner, owner group, and other only */
3135 +               return 3;
3136 +       else { /* Otherwise there must be a mask entry. */
3137 +               /* Also, the remaining entries are for named users and
3138 +                * groups, and come in threes (mask, allow, deny): */
3139 +               if (n4acl->naces < 7)
3140 +                       return -1;
3141 +               if ((n4acl->naces - 7) % 3)
3142 +                       return -1;
3143 +               return 4 + (n4acl->naces - 7)/3;
3144 +       }
3145 +}
3146 +
3147 +
3148 +static struct posix_acl *
3149 +_nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags)
3150 +{
3151 +       struct posix_acl *pacl;
3152 +       int error = -EINVAL, nace = 0;
3153 +       struct list_head *p;
3154 +       struct nfs4_ace *mask_ace = NULL;
3155 +       struct posix_acl_entry *pace;
3156 +
3157 +       nace = calculate_posix_ace_count(n4acl);
3158 +       if (nace < 0)
3159 +               goto out_err;
3160 +
3161 +       pacl = posix_acl_alloc(nace, GFP_KERNEL);
3162 +       error = -ENOMEM;
3163 +       if (pacl == NULL)
3164 +               goto out_err;
3165 +
3166 +       pace = &pacl->a_entries[0];
3167 +       p = &n4acl->ace_head;
3168 +
3169 +       error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags);
3170 +       if (error)
3171 +               goto out_acl;
3172 +
3173 +       error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
3174 +       if (error)
3175 +               goto out_acl;
3176 +
3177 +       error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace,
3178 +                                               flags);
3179 +       if (error)
3180 +               goto out_acl;
3181 +
3182 +       error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
3183 +       if (error)
3184 +               goto out_acl;
3185 +       error = other_from_v4(n4acl, &p, pacl, &pace, flags);
3186 +       if (error)
3187 +               goto out_acl;
3188 +
3189 +       error = -EINVAL;
3190 +       if (p->next != &n4acl->ace_head)
3191 +               goto out_acl;
3192 +       if (pace != pacl->a_entries + pacl->a_count)
3193 +               goto out_acl;
3194 +
3195 +       sort_pacl(pacl);
3196 +
3197 +       return pacl;
3198 +out_acl:
3199 +       posix_acl_release(pacl);
3200 +out_err:
3201 +       pacl = ERR_PTR(error);
3202 +       return pacl;
3203 +}
3204 +
3205 +int
3206 +nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
3207 +{
3208 +       struct list_head *h, *n;
3209 +       struct nfs4_ace *ace;
3210 +       int error = 0;
3211 +
3212 +       list_for_each_safe(h, n, &acl->ace_head) {
3213 +               ace = list_entry(h, struct nfs4_ace, l_ace);
3214 +
3215 +               if ((ace->flag & NFS4_INHERITANCE_FLAGS)
3216 +                               != NFS4_INHERITANCE_FLAGS)
3217 +                       continue;
3218 +
3219 +               error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
3220 +                               ace->access_mask, ace->whotype, ace->who) == -1;
3221 +               if (error < 0)
3222 +                       goto out;
3223 +
3224 +               list_del(h);
3225 +               kfree(ace);
3226 +               acl->naces--;
3227 +       }
3228 +
3229 +out:
3230 +       return error;
3231 +}
3232 +
3233 +static short
3234 +ace2type(struct nfs4_ace *ace)
3235 +{
3236 +       switch (ace->whotype) {
3237 +               case NFS4_ACL_WHO_NAMED:
3238 +                       return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ?
3239 +                                       ACL_GROUP : ACL_USER);
3240 +               case NFS4_ACL_WHO_OWNER:
3241 +                       return ACL_USER_OBJ;
3242 +               case NFS4_ACL_WHO_GROUP:
3243 +                       return ACL_GROUP_OBJ;
3244 +               case NFS4_ACL_WHO_EVERYONE:
3245 +                       return ACL_OTHER;
3246 +       }
3247 +       BUG();
3248 +       return -1;
3249 +}
3250 +
3251 +EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4);
3252 +EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix);
3253 +
3254 +struct nfs4_acl *
3255 +nfs4_acl_new(void)
3256 +{
3257 +       struct nfs4_acl *acl;
3258 +
3259 +       if ((acl = kmalloc(sizeof(*acl), GFP_KERNEL)) == NULL)
3260 +               return NULL;
3261 +
3262 +       acl->naces = 0;
3263 +       INIT_LIST_HEAD(&acl->ace_head);
3264 +
3265 +       return acl;
3266 +}
3267 +
3268 +void
3269 +nfs4_acl_free(struct nfs4_acl *acl)
3270 +{
3271 +       struct list_head *h;
3272 +       struct nfs4_ace *ace;
3273 +
3274 +       if (!acl)
3275 +               return;
3276 +
3277 +       while (!list_empty(&acl->ace_head)) {
3278 +               h = acl->ace_head.next;
3279 +               list_del(h);
3280 +               ace = list_entry(h, struct nfs4_ace, l_ace);
3281 +               kfree(ace);
3282 +       }
3283 +
3284 +       kfree(acl);
3285 +
3286 +       return;
3287 +}
3288 +
3289 +int
3290 +nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
3291 +               int whotype, uid_t who)
3292 +{
3293 +       struct nfs4_ace *ace;
3294 +
3295 +       if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL)
3296 +               return -1;
3297 +
3298 +       ace->type = type;
3299 +       ace->flag = flag;
3300 +       ace->access_mask = access_mask;
3301 +       ace->whotype = whotype;
3302 +       ace->who = who;
3303 +
3304 +       list_add_tail(&ace->l_ace, &acl->ace_head);
3305 +       acl->naces++;
3306 +
3307 +       return 0;
3308 +}
3309 +
3310 +static struct {
3311 +       char *string;
3312 +       int   stringlen;
3313 +       int type;
3314 +} s2t_map[] = {
3315 +       {
3316 +               .string    = "OWNER@",
3317 +               .stringlen = sizeof("OWNER@") - 1,
3318 +               .type      = NFS4_ACL_WHO_OWNER,
3319 +       },
3320 +       {
3321 +               .string    = "GROUP@",
3322 +               .stringlen = sizeof("GROUP@") - 1,
3323 +               .type      = NFS4_ACL_WHO_GROUP,
3324 +       },
3325 +       {
3326 +               .string    = "EVERYONE@",
3327 +               .stringlen = sizeof("EVERYONE@") - 1,
3328 +               .type      = NFS4_ACL_WHO_EVERYONE,
3329 +       },
3330 +};
3331 +
3332 +int
3333 +nfs4_acl_get_whotype(char *p, u32 len)
3334 +{
3335 +       int i;
3336 +
3337 +       for (i=0; i < sizeof(s2t_map) / sizeof(*s2t_map); i++) {
3338 +               if (s2t_map[i].stringlen == len &&
3339 +                               0 == memcmp(s2t_map[i].string, p, len))
3340 +                       return s2t_map[i].type;
3341 +       }
3342 +       return NFS4_ACL_WHO_NAMED;
3343 +}
3344 +
3345 +int
3346 +nfs4_acl_write_who(int who, char *p)
3347 +{
3348 +       int i;
3349 +
3350 +       for (i=0; i < sizeof(s2t_map) / sizeof(*s2t_map); i++) {
3351 +               if (s2t_map[i].type == who) {
3352 +                       memcpy(p, s2t_map[i].string, s2t_map[i].stringlen);
3353 +                       return s2t_map[i].stringlen;
3354 +               }
3355 +       }
3356 +       BUG();
3357 +       return -1;
3358 +}
3359 +
3360 +static inline int
3361 +match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who)
3362 +{
3363 +       switch (ace->whotype) {
3364 +               case NFS4_ACL_WHO_NAMED:
3365 +                       return who == ace->who;
3366 +               case NFS4_ACL_WHO_OWNER:
3367 +                       return who == owner;
3368 +               case NFS4_ACL_WHO_GROUP:
3369 +                       return who == group;
3370 +               case NFS4_ACL_WHO_EVERYONE:
3371 +                       return 1;
3372 +               default:
3373 +                       return 0;
3374 +       }
3375 +}
3376 +
3377 +/* 0 = granted, -EACCES = denied; mask is an nfsv4 mask, not mode bits */
3378 +int
3379 +nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
3380 +                       uid_t who, u32 mask)
3381 +{
3382 +       struct nfs4_ace *ace;
3383 +       u32 allowed = 0;
3384 +
3385 +       list_for_each_entry(ace, &acl->ace_head, l_ace) {
3386 +               if (!match_who(ace, group, owner, who))
3387 +                       continue;
3388 +               switch (ace->type) {
3389 +                       case NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE:
3390 +                               allowed |= ace->access_mask;
3391 +                               if ((allowed & mask) == mask)
3392 +                                       return 0;
3393 +                               break;
3394 +                       case NFS4_ACE_ACCESS_DENIED_ACE_TYPE:
3395 +                               if (ace->access_mask & mask)
3396 +                                       return -EACCES;
3397 +                               break;
3398 +               }
3399 +       }
3400 +       return -EACCES;
3401 +}
3402 +
3403 +EXPORT_SYMBOL(nfs4_acl_new);
3404 +EXPORT_SYMBOL(nfs4_acl_free);
3405 +EXPORT_SYMBOL(nfs4_acl_add_ace);
3406 +EXPORT_SYMBOL(nfs4_acl_get_whotype);
3407 +EXPORT_SYMBOL(nfs4_acl_write_who);
3408 +EXPORT_SYMBOL(nfs4_acl_permission);
3409 --- linux-2.6.7/fs/nfsd/Makefile.lsec   2004-06-15 23:19:13.000000000 -0600
3410 +++ linux-2.6.7/fs/nfsd/Makefile        2005-03-23 14:28:24.461331008 -0700
3411 @@ -7,5 +7,6 @@ obj-$(CONFIG_NFSD)      += nfsd.o
3412  nfsd-y                         := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
3413                            export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
3414  nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
3415 -nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o
3416 +nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
3417 +                          nfs4acl.o nfs4callback.o
3418  nfsd-objs              := $(nfsd-y)
3419 --- linux-2.6.7/fs/nfsd/nfsctl.c.lsec   2004-06-15 23:19:01.000000000 -0600
3420 +++ linux-2.6.7/fs/nfsd/nfsctl.c        2005-03-23 14:28:24.132381016 -0700
3421 @@ -36,7 +36,7 @@
3422  #include <asm/uaccess.h>
3423  
3424  /*
3425 - *     We have a single directory with 8 nodes in it.
3426 + *     We have a single directory with 9 nodes in it.
3427   */
3428  enum {
3429         NFSD_Root = 1,
3430 @@ -50,6 +50,7 @@ enum {
3431         NFSD_List,
3432         NFSD_Fh,
3433         NFSD_Threads,
3434 +       NFSD_Leasetime,
3435  };
3436  
3437  /*
3438 @@ -64,6 +65,7 @@ static ssize_t write_getfd(struct file *
3439  static ssize_t write_getfs(struct file *file, char *buf, size_t size);
3440  static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
3441  static ssize_t write_threads(struct file *file, char *buf, size_t size);
3442 +static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
3443  
3444  static ssize_t (*write_op[])(struct file *, char *, size_t) = {
3445         [NFSD_Svc] = write_svc,
3446 @@ -75,6 +77,7 @@ static ssize_t (*write_op[])(struct file
3447         [NFSD_Getfs] = write_getfs,
3448         [NFSD_Fh] = write_filehandle,
3449         [NFSD_Threads] = write_threads,
3450 +       [NFSD_Leasetime] = write_leasetime,
3451  };
3452  
3453  /* an argresp is stored in an allocated page and holds the 
3454 @@ -393,6 +396,29 @@ static ssize_t write_threads(struct file
3455         return strlen(buf);
3456  }
3457  
3458 +extern time_t nfs4_leasetime(void);
3459 +
3460 +static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
3461 +{
3462 +       /* if size > 10 seconds, call
3463 +        * nfs4_reset_lease() then write out the new lease (seconds) as reply
3464 +        */
3465 +       char *mesg = buf;
3466 +       int rv;
3467 +
3468 +       if (size > 0) {
3469 +               int lease;
3470 +               rv = get_int(&mesg, &lease);
3471 +               if (rv)
3472 +                       return rv;
3473 +               if (lease < 10 || lease > 3600)
3474 +                       return -EINVAL;
3475 +               nfs4_reset_lease(lease);
3476 +       }
3477 +       sprintf(buf, "%ld\n", nfs4_lease_time());
3478 +       return strlen(buf);
3479 +}
3480 +
3481  /*----------------------------------------------------------------------------*/
3482  /*
3483   *     populating the filesystem.
3484 @@ -411,6 +437,7 @@ static int nfsd_fill_super(struct super_
3485                 [NFSD_List] = {"exports", &exports_operations, S_IRUGO},
3486                 [NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
3487                 [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
3488 +               [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
3489                 /* last one */ {""}
3490         };
3491         return simple_fill_super(sb, 0x6e667364, nfsd_files);
3492 --- linux-2.6.7/fs/nfs/callback_proc.c.lsec     2005-03-23 14:28:22.485631360 -0700
3493 +++ linux-2.6.7/fs/nfs/callback_proc.c  2005-03-23 14:28:22.485631360 -0700
3494 @@ -0,0 +1,85 @@
3495 +/*
3496 + * linux/fs/nfs/callback_proc.c
3497 + *
3498 + * Copyright (C) 2004 Trond Myklebust
3499 + *
3500 + * NFSv4 callback procedures
3501 + */
3502 +#include <linux/config.h>
3503 +#include <linux/nfs4.h>
3504 +#include <linux/nfs_fs.h>
3505 +#include "callback.h"
3506 +#include "delegation.h"
3507 +
3508 +#define NFSDBG_FACILITY NFSDBG_CALLBACK
3509
3510 +unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
3511 +{
3512 +       struct nfs4_client *clp;
3513 +       struct nfs_delegation *delegation;
3514 +       struct nfs_inode *nfsi;
3515 +       struct inode *inode;
3516 +       
3517 +       res->bitmap[0] = res->bitmap[1] = 0;
3518 +       res->status = htonl(NFS4ERR_BADHANDLE);
3519 +       clp = nfs4_find_client(&args->addr->sin_addr);
3520 +       if (clp == NULL)
3521 +               goto out;
3522 +       inode = nfs_delegation_find_inode(clp, &args->fh);
3523 +       if (inode == NULL)
3524 +               goto out_putclient;
3525 +       nfsi = NFS_I(inode);
3526 +       down_read(&nfsi->rwsem);
3527 +       delegation = nfsi->delegation;
3528 +       if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
3529 +               goto out_iput;
3530 +       res->size = i_size_read(inode);
3531 +       res->change_attr = NFS_CHANGE_ATTR(inode);
3532 +       res->ctime = inode->i_ctime;
3533 +       res->mtime = inode->i_mtime;
3534 +       res->bitmap[0] = (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE) &
3535 +               args->bitmap[0];
3536 +       res->bitmap[1] = (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY) &
3537 +               args->bitmap[1];
3538 +       res->status = 0;
3539 +out_iput:
3540 +       up_read(&nfsi->rwsem);
3541 +       iput(inode);
3542 +out_putclient:
3543 +       nfs4_put_client(clp);
3544 +out:
3545 +       dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res->status));
3546 +       return res->status;
3547 +}
3548 +
3549 +unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
3550 +{
3551 +       struct nfs4_client *clp;
3552 +       struct inode *inode;
3553 +       unsigned res;
3554 +       
3555 +       res = htonl(NFS4ERR_BADHANDLE);
3556 +       clp = nfs4_find_client(&args->addr->sin_addr);
3557 +       if (clp == NULL)
3558 +               goto out;
3559 +       inode = nfs_delegation_find_inode(clp, &args->fh);
3560 +       if (inode == NULL)
3561 +               goto out_putclient;
3562 +       /* Set up a helper thread to actually return the delegation */
3563 +       switch(nfs_async_inode_return_delegation(inode, &args->stateid)) {
3564 +               case 0:
3565 +                       res = 0;
3566 +                       break;
3567 +               case -ENOENT:
3568 +                       res = htonl(NFS4ERR_BAD_STATEID);
3569 +                       break;
3570 +               default:
3571 +                       res = htonl(NFS4ERR_RESOURCE);
3572 +       }
3573 +       iput(inode);
3574 +out_putclient:
3575 +       nfs4_put_client(clp);
3576 +out:
3577 +       dprintk("%s: exit with status = %d\n", __FUNCTION__, ntohl(res));
3578 +       return res;
3579 +}
3580 --- linux-2.6.7/fs/nfs/delegation.c.lsec        2005-03-23 14:28:22.546622088 -0700
3581 +++ linux-2.6.7/fs/nfs/delegation.c     2005-03-23 14:28:22.545622240 -0700
3582 @@ -0,0 +1,320 @@
3583 +/*
3584 + * linux/fs/nfs/delegation.c
3585 + *
3586 + * Copyright (C) 2004 Trond Myklebust
3587 + *
3588 + * NFS file delegation management
3589 + *
3590 + */
3591 +#include <linux/config.h>
3592 +#include <linux/completion.h>
3593 +#include <linux/module.h>
3594 +#include <linux/sched.h>
3595 +#include <linux/spinlock.h>
3596 +
3597 +#include <linux/nfs4.h>
3598 +#include <linux/nfs_fs.h>
3599 +#include <linux/nfs_xdr.h>
3600 +
3601 +#include "delegation.h"
3602 +
3603 +static struct nfs_delegation *nfs_alloc_delegation(void)
3604 +{
3605 +       return (struct nfs_delegation *)kmalloc(sizeof(struct nfs_delegation), GFP_KERNEL);
3606 +}
3607 +
3608 +static void nfs_free_delegation(struct nfs_delegation *delegation)
3609 +{
3610 +       if (delegation->cred)
3611 +               put_rpccred(delegation->cred);
3612 +       kfree(delegation);
3613 +}
3614 +
3615 +static void nfs_delegation_claim_opens(struct inode *inode)
3616 +{
3617 +       struct nfs_inode *nfsi = NFS_I(inode);
3618 +       struct nfs_open_context *ctx;
3619 +       struct nfs4_state *state;
3620 +
3621 +again:
3622 +       spin_lock(&inode->i_lock);
3623 +       list_for_each_entry(ctx, &nfsi->open_files, list) {
3624 +               state = ctx->state;
3625 +               if (state == NULL)
3626 +                       continue;
3627 +               if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
3628 +                       continue;
3629 +               get_nfs_open_context(ctx);
3630 +               spin_unlock(&inode->i_lock);
3631 +               if (nfs4_open_delegation_recall(ctx->dentry, state) < 0)
3632 +                       return;
3633 +               put_nfs_open_context(ctx);
3634 +               goto again;
3635 +       }
3636 +       spin_unlock(&inode->i_lock);
3637 +}
3638 +
3639 +/*
3640 + * Set up a delegation on an inode
3641 + */
3642 +void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
3643 +{
3644 +       struct nfs_delegation *delegation = NFS_I(inode)->delegation;
3645 +
3646 +       if (delegation == NULL)
3647 +               return;
3648 +       memcpy(delegation->stateid.data, res->delegation.data,
3649 +                       sizeof(delegation->stateid.data));
3650 +       delegation->type = res->delegation_type;
3651 +       delegation->maxsize = res->maxsize;
3652 +       put_rpccred(cred);
3653 +       delegation->cred = get_rpccred(cred);
3654 +       delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM;
3655 +       NFS_I(inode)->delegation_state = delegation->type;
3656 +       wmb();
3657 +}
3658 +
3659 +/*
3660 + * Set up a delegation on an inode
3661 + */
3662 +int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
3663 +{
3664 +       struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
3665 +       struct nfs_inode *nfsi = NFS_I(inode);
3666 +       struct nfs_delegation *delegation;
3667 +       int status = 0;
3668 +
3669 +       delegation = nfs_alloc_delegation();
3670 +       if (delegation == NULL)
3671 +               return -ENOMEM;
3672 +       memcpy(delegation->stateid.data, res->delegation.data,
3673 +                       sizeof(delegation->stateid.data));
3674 +       delegation->type = res->delegation_type;
3675 +       delegation->maxsize = res->maxsize;
3676 +       delegation->cred = get_rpccred(cred);
3677 +       delegation->inode = inode;
3678 +
3679 +       spin_lock(&clp->cl_lock);
3680 +       if (nfsi->delegation == NULL) {
3681 +               list_add(&delegation->super_list, &clp->cl_delegations);
3682 +               nfsi->delegation = delegation;
3683 +               nfsi->delegation_state = delegation->type;
3684 +               delegation = NULL;
3685 +       } else {
3686 +               if (memcmp(&delegation->stateid, &nfsi->delegation->stateid,
3687 +                                       sizeof(delegation->stateid)) != 0 ||
3688 +                               delegation->type != nfsi->delegation->type) {
3689 +                       printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n",
3690 +                                       __FUNCTION__, NIPQUAD(clp->cl_addr));
3691 +                       status = -EIO;
3692 +               }
3693 +       }
3694 +       spin_unlock(&clp->cl_lock);
3695 +       if (delegation != NULL)
3696 +               kfree(delegation);
3697 +       return status;
3698 +}
3699 +
3700 +static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation)
3701 +{
3702 +       int res = 0;
3703 +
3704 +       __nfs_revalidate_inode(NFS_SERVER(inode), inode);
3705 +
3706 +       res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid);
3707 +       nfs_free_delegation(delegation);
3708 +       return res;
3709 +}
3710 +
3711 +/* Sync all data to disk upon delegation return */
3712 +static void nfs_msync_inode(struct inode *inode)
3713 +{
3714 +       down(&inode->i_sem);
3715 +       filemap_fdatawrite(inode->i_mapping);
3716 +       nfs_wb_all(inode);
3717 +       filemap_fdatawait(inode->i_mapping);
3718 +       up(&inode->i_sem);
3719 +}
3720 +
3721 +/*
3722 + * Basic procedure for returning a delegation to the server
3723 + */
3724 +int nfs_inode_return_delegation(struct inode *inode)
3725 +{
3726 +       struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
3727 +       struct nfs_inode *nfsi = NFS_I(inode);
3728 +       struct nfs_delegation *delegation;
3729 +       int res = 0;
3730 +
3731 +       nfs_msync_inode(inode);
3732 +       down_read(&clp->cl_sem);
3733 +       /* Guard against new delegated open calls */
3734 +       down_write(&nfsi->rwsem);
3735 +       spin_lock(&clp->cl_lock);
3736 +       delegation = nfsi->delegation;
3737 +       if (delegation != NULL) {
3738 +               list_del_init(&delegation->super_list);
3739 +               nfsi->delegation = NULL;
3740 +               nfsi->delegation_state = 0;
3741 +       }
3742 +       spin_unlock(&clp->cl_lock);
3743 +       nfs_delegation_claim_opens(inode);
3744 +       up_write(&nfsi->rwsem);
3745 +       up_read(&clp->cl_sem);
3746 +       nfs_msync_inode(inode);
3747 +
3748 +       if (delegation != NULL)
3749 +               res = nfs_do_return_delegation(inode, delegation);
3750 +       return res;
3751 +}
3752 +
3753 +/*
3754 + * Return all delegations associated to a super block
3755 + */
3756 +void nfs_return_all_delegations(struct super_block *sb)
3757 +{
3758 +       struct nfs4_client *clp = NFS_SB(sb)->nfs4_state;
3759 +       struct nfs_delegation *delegation;
3760 +       struct inode *inode;
3761 +
3762 +       if (clp == NULL)
3763 +               return;
3764 +restart:
3765 +       spin_lock(&clp->cl_lock);
3766 +       list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
3767 +               if (delegation->inode->i_sb != sb)
3768 +                       continue;
3769 +               inode = igrab(delegation->inode);
3770 +               if (inode == NULL)
3771 +                       continue;
3772 +               spin_unlock(&clp->cl_lock);
3773 +               nfs_inode_return_delegation(inode);
3774 +               iput(inode);
3775 +               goto restart;
3776 +       }
3777 +       spin_unlock(&clp->cl_lock);
3778 +}
3779 +
3780 +struct recall_threadargs {
3781 +       struct inode *inode;
3782 +       struct nfs4_client *clp;
3783 +       const nfs4_stateid *stateid;
3784 +
3785 +       struct completion started;
3786 +       int result;
3787 +};
3788 +
3789 +static int recall_thread(void *data)
3790 +{
3791 +       struct recall_threadargs *args = (struct recall_threadargs *)data;
3792 +       struct inode *inode = igrab(args->inode);
3793 +       struct nfs4_client *clp = NFS_SERVER(inode)->nfs4_state;
3794 +       struct nfs_inode *nfsi = NFS_I(inode);
3795 +       struct nfs_delegation *delegation;
3796 +
3797 +       daemonize("nfsv4-delegreturn");
3798 +
3799 +       nfs_msync_inode(inode);
3800 +       down_read(&clp->cl_sem);
3801 +       down_write(&nfsi->rwsem);
3802 +       spin_lock(&clp->cl_lock);
3803 +       delegation = nfsi->delegation;
3804 +       if (delegation != NULL && memcmp(delegation->stateid.data,
3805 +                               args->stateid->data,
3806 +                               sizeof(delegation->stateid.data)) == 0) {
3807 +               list_del_init(&delegation->super_list);
3808 +               nfsi->delegation = NULL;
3809 +               nfsi->delegation_state = 0;
3810 +               args->result = 0;
3811 +       } else {
3812 +               delegation = NULL;
3813 +               args->result = -ENOENT;
3814 +       }
3815 +       spin_unlock(&clp->cl_lock);
3816 +       complete(&args->started);
3817 +       nfs_delegation_claim_opens(inode);
3818 +       up_write(&nfsi->rwsem);
3819 +       up_read(&clp->cl_sem);
3820 +       nfs_msync_inode(inode);
3821 +
3822 +       if (delegation != NULL)
3823 +               nfs_do_return_delegation(inode, delegation);
3824 +       iput(inode);
3825 +       module_put_and_exit(0);
3826 +}
3827 +
3828 +/*
3829 + * Asynchronous delegation recall!
3830 + */
3831 +int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid)
3832 +{
3833 +       struct recall_threadargs data = {
3834 +               .inode = inode,
3835 +               .stateid = stateid,
3836 +       };
3837 +       int status;
3838 +
3839 +       init_completion(&data.started);
3840 +       __module_get(THIS_MODULE);
3841 +       status = kernel_thread(recall_thread, &data, CLONE_KERNEL);
3842 +       if (status < 0)
3843 +               goto out_module_put;
3844 +       wait_for_completion(&data.started);
3845 +       return data.result;
3846 +out_module_put:
3847 +       module_put(THIS_MODULE);
3848 +       return status;
3849 +}
3850 +
3851 +/*
3852 + * Retrieve the inode associated with a delegation
3853 + */
3854 +struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle)
3855 +{
3856 +       struct nfs_delegation *delegation;
3857 +       struct inode *res = NULL;
3858 +       spin_lock(&clp->cl_lock);
3859 +       list_for_each_entry(delegation, &clp->cl_delegations, super_list) {
3860 +               if (nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
3861 +                       res = igrab(delegation->inode);
3862 +                       break;
3863 +               }
3864 +       }
3865 +       spin_unlock(&clp->cl_lock);
3866 +       return res;
3867 +}
3868 +
3869 +/*
3870 + * Mark all delegations as needing to be reclaimed
3871 + */
3872 +void nfs_delegation_mark_reclaim(struct nfs4_client *clp)
3873 +{
3874 +       struct nfs_delegation *delegation;
3875 +       spin_lock(&clp->cl_lock);
3876 +       list_for_each_entry(delegation, &clp->cl_delegations, super_list)
3877 +               delegation->flags |= NFS_DELEGATION_NEED_RECLAIM;
3878 +       spin_unlock(&clp->cl_lock);
3879 +}
3880 +
3881 +/*
3882 + * Reap all unclaimed delegations after reboot recovery is done
3883 + */
3884 +void nfs_delegation_reap_unclaimed(struct nfs4_client *clp)
3885 +{
3886 +       struct nfs_delegation *delegation, *n;
3887 +       LIST_HEAD(head);
3888 +       spin_lock(&clp->cl_lock);
3889 +       list_for_each_entry_safe(delegation, n, &clp->cl_delegations, super_list) {
3890 +               if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0)
3891 +                       continue;
3892 +               list_move(&delegation->super_list, &head);
3893 +               NFS_I(delegation->inode)->delegation = NULL;
3894 +               NFS_I(delegation->inode)->delegation_state = 0;
3895 +       }
3896 +       spin_unlock(&clp->cl_lock);
3897 +       while(!list_empty(&head)) {
3898 +               delegation = list_entry(head.next, struct nfs_delegation, super_list);
3899 +               list_del(&delegation->super_list);
3900 +               nfs_free_delegation(delegation);
3901 +       }
3902 +}
3903 --- linux-2.6.7/fs/nfs/delegation.h.lsec        2005-03-23 14:28:22.546622088 -0700
3904 +++ linux-2.6.7/fs/nfs/delegation.h     2005-03-23 14:28:22.546622088 -0700
3905 @@ -0,0 +1,56 @@
3906 +/*
3907 + * linux/fs/nfs/delegation.h
3908 + *
3909 + * Copyright (c) Trond Myklebust
3910 + *
3911 + * Definitions pertaining to NFS delegated files
3912 + */
3913 +#ifndef FS_NFS_DELEGATION_H
3914 +#define FS_NFS_DELEGATION_H
3915 +
3916 +#if defined(CONFIG_NFS_V4)
3917 +/*
3918 + * NFSv4 delegation
3919 + */
3920 +struct nfs_delegation {
3921 +       struct list_head super_list;
3922 +       struct rpc_cred *cred;
3923 +       struct inode *inode;
3924 +       nfs4_stateid stateid;
3925 +       int type;
3926 +#define NFS_DELEGATION_NEED_RECLAIM 1
3927 +       long flags;
3928 +       loff_t maxsize;
3929 +};
3930 +
3931 +int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
3932 +void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
3933 +int nfs_inode_return_delegation(struct inode *inode);
3934 +int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
3935 +
3936 +struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
3937 +void nfs_return_all_delegations(struct super_block *sb);
3938 +
3939 +void nfs_delegation_mark_reclaim(struct nfs4_client *clp);
3940 +void nfs_delegation_reap_unclaimed(struct nfs4_client *clp);
3941 +
3942 +/* NFSv4 delegation-related procedures */
3943 +int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
3944 +int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state);
3945 +
3946 +static inline int nfs_have_delegation(struct inode *inode, int flags)
3947 +{
3948 +       flags &= FMODE_READ|FMODE_WRITE;
3949 +       rmb();
3950 +       if ((NFS_I(inode)->delegation_state & flags) == flags)
3951 +               return 1;
3952 +       return 0;
3953 +}
3954 +#else
3955 +static inline int nfs_have_delegation(struct inode *inode, int flags)
3956 +{
3957 +       return 0;
3958 +}
3959 +#endif
3960 +
3961 +#endif
3962 --- linux-2.6.7/fs/nfs/nfs3proc.c.lsec  2004-06-15 23:19:23.000000000 -0600
3963 +++ linux-2.6.7/fs/nfs/nfs3proc.c       2005-03-23 14:28:22.820580440 -0700
3964 @@ -68,18 +68,6 @@ nfs3_async_handle_jukebox(struct rpc_tas
3965         return 1;
3966  }
3967  
3968 -static struct rpc_cred *
3969 -nfs_cred(struct inode *inode, struct file *filp)
3970 -{
3971 -       struct rpc_cred *cred = NULL;
3972 -
3973 -       if (filp)
3974 -               cred = (struct rpc_cred *)filp->private_data;
3975 -       if (!cred)
3976 -               cred = NFS_I(inode)->mm_cred;
3977 -       return cred;
3978 -}
3979 -
3980  /*
3981   * Bare-bones access to getattr: this is for nfs_read_super.
3982   */
3983 @@ -164,8 +152,7 @@ nfs3_proc_lookup(struct inode *dir, stru
3984         return status;
3985  }
3986  
3987 -static int
3988 -nfs3_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
3989 +static int nfs3_proc_access(struct inode *inode, struct nfs_access_entry *entry)
3990  {
3991         struct nfs_fattr        fattr;
3992         struct nfs3_accessargs  arg = {
3993 @@ -178,9 +165,10 @@ nfs3_proc_access(struct inode *inode, st
3994                 .rpc_proc       = &nfs3_procedures[NFS3PROC_ACCESS],
3995                 .rpc_argp       = &arg,
3996                 .rpc_resp       = &res,
3997 -               .rpc_cred       = cred
3998 +               .rpc_cred       = entry->cred
3999         };
4000 -       int     status;
4001 +       int mode = entry->mask;
4002 +       int status;
4003  
4004         dprintk("NFS call  access\n");
4005         fattr.valid = 0;
4006 @@ -200,10 +188,16 @@ nfs3_proc_access(struct inode *inode, st
4007         }
4008         status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
4009         nfs_refresh_inode(inode, &fattr);
4010 -       dprintk("NFS reply access\n");
4011 -
4012 -       if (status == 0 && (arg.access & res.access) != arg.access)
4013 -               status = -EACCES;
4014 +       if (status == 0) {
4015 +               entry->mask = 0;
4016 +               if (res.access & NFS3_ACCESS_READ)
4017 +                       entry->mask |= MAY_READ;
4018 +               if (res.access & (NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE))
4019 +                       entry->mask |= MAY_WRITE;
4020 +               if (res.access & (NFS3_ACCESS_LOOKUP|NFS3_ACCESS_EXECUTE))
4021 +                       entry->mask |= MAY_EXEC;
4022 +       }
4023 +       dprintk("NFS reply access, status = %d\n", status);
4024         return status;
4025  }
4026  
4027 @@ -227,8 +221,7 @@ nfs3_proc_readlink(struct inode *inode, 
4028         return status;
4029  }
4030  
4031 -static int
4032 -nfs3_proc_read(struct nfs_read_data *rdata, struct file *filp)
4033 +static int nfs3_proc_read(struct nfs_read_data *rdata)
4034  {
4035         int                     flags = rdata->flags;
4036         struct inode *          inode = rdata->inode;
4037 @@ -237,13 +230,13 @@ nfs3_proc_read(struct nfs_read_data *rda
4038                 .rpc_proc       = &nfs3_procedures[NFS3PROC_READ],
4039                 .rpc_argp       = &rdata->args,
4040                 .rpc_resp       = &rdata->res,
4041 +               .rpc_cred       = rdata->cred,
4042         };
4043         int                     status;
4044  
4045         dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
4046                         (long long) rdata->args.offset);
4047         fattr->valid = 0;
4048 -       msg.rpc_cred = nfs_cred(inode, filp);
4049         status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
4050         if (status >= 0)
4051                 nfs_refresh_inode(inode, fattr);
4052 @@ -251,8 +244,7 @@ nfs3_proc_read(struct nfs_read_data *rda
4053         return status;
4054  }
4055  
4056 -static int
4057 -nfs3_proc_write(struct nfs_write_data *wdata, struct file *filp)
4058 +static int nfs3_proc_write(struct nfs_write_data *wdata)
4059  {
4060         int                     rpcflags = wdata->flags;
4061         struct inode *          inode = wdata->inode;
4062 @@ -261,13 +253,13 @@ nfs3_proc_write(struct nfs_write_data *w
4063                 .rpc_proc       = &nfs3_procedures[NFS3PROC_WRITE],
4064                 .rpc_argp       = &wdata->args,
4065                 .rpc_resp       = &wdata->res,
4066 +               .rpc_cred       = wdata->cred,
4067         };
4068         int                     status;
4069  
4070         dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
4071                         (long long) wdata->args.offset);
4072         fattr->valid = 0;
4073 -       msg.rpc_cred = nfs_cred(inode, filp);
4074         status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
4075         if (status >= 0)
4076                 nfs_refresh_inode(inode, fattr);
4077 @@ -275,8 +267,7 @@ nfs3_proc_write(struct nfs_write_data *w
4078         return status < 0? status : wdata->res.count;
4079  }
4080  
4081 -static int
4082 -nfs3_proc_commit(struct nfs_write_data *cdata, struct file *filp)
4083 +static int nfs3_proc_commit(struct nfs_write_data *cdata)
4084  {
4085         struct inode *          inode = cdata->inode;
4086         struct nfs_fattr *      fattr = cdata->res.fattr;
4087 @@ -284,13 +275,13 @@ nfs3_proc_commit(struct nfs_write_data *
4088                 .rpc_proc       = &nfs3_procedures[NFS3PROC_COMMIT],
4089                 .rpc_argp       = &cdata->args,
4090                 .rpc_resp       = &cdata->res,
4091 +               .rpc_cred       = cdata->cred,
4092         };
4093         int                     status;
4094  
4095         dprintk("NFS call  commit %d @ %Ld\n", cdata->args.count,
4096                         (long long) cdata->args.offset);
4097         fattr->valid = 0;
4098 -       msg.rpc_cred = nfs_cred(inode, filp);
4099         status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
4100         if (status >= 0)
4101                 nfs_refresh_inode(inode, fattr);
4102 @@ -534,6 +525,8 @@ nfs3_proc_symlink(struct inode *dir, str
4103         };
4104         int                     status;
4105  
4106 +       if (path->len > NFS3_MAXPATHLEN)
4107 +               return -ENAMETOOLONG;
4108         dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
4109         dir_attr.valid = 0;
4110         fattr->valid = 0;
4111 @@ -832,27 +825,6 @@ nfs3_proc_commit_setup(struct nfs_write_
4112         rpc_call_setup(task, &msg, 0);
4113  }
4114  
4115 -/*
4116 - * Set up the nfspage struct with the right credentials
4117 - */
4118 -void
4119 -nfs3_request_init(struct nfs_page *req, struct file *filp)
4120 -{
4121 -       req->wb_cred = get_rpccred(nfs_cred(req->wb_inode, filp));
4122 -}
4123 -
4124 -static int
4125 -nfs3_request_compatible(struct nfs_page *req, struct file *filp, struct page *page)
4126 -{
4127 -       if (req->wb_file != filp)
4128 -               return 0;
4129 -       if (req->wb_page != page)
4130 -               return 0;
4131 -       if (req->wb_cred != nfs_file_cred(filp))
4132 -               return 0;
4133 -       return 1;
4134 -}
4135 -
4136  static int
4137  nfs3_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
4138  {
4139 @@ -863,6 +835,7 @@ struct nfs_rpc_ops  nfs_v3_clientops = {
4140         .version        = 3,                    /* protocol version */
4141         .dentry_ops     = &nfs_dentry_operations,
4142         .dir_inode_ops  = &nfs_dir_inode_operations,
4143 +       .file_inode_ops = &nfs_file_inode_operations,
4144         .getroot        = nfs3_proc_get_root,
4145         .getattr        = nfs3_proc_getattr,
4146         .setattr        = nfs3_proc_setattr,
4147 @@ -892,7 +865,5 @@ struct nfs_rpc_ops  nfs_v3_clientops = {
4148         .commit_setup   = nfs3_proc_commit_setup,
4149         .file_open      = nfs_open,
4150         .file_release   = nfs_release,
4151 -       .request_init   = nfs3_request_init,
4152 -       .request_compatible = nfs3_request_compatible,
4153         .lock           = nfs3_proc_lock,
4154  };
4155 --- linux-2.6.7/fs/nfs/proc.c.lsec      2004-06-15 23:20:03.000000000 -0600
4156 +++ linux-2.6.7/fs/nfs/proc.c   2005-03-23 14:28:23.058544264 -0700
4157 @@ -49,18 +49,6 @@
4158  
4159  extern struct rpc_procinfo nfs_procedures[];
4160  
4161 -static struct rpc_cred *
4162 -nfs_cred(struct inode *inode, struct file *filp)
4163 -{
4164 -       struct rpc_cred *cred = NULL;
4165 -
4166 -       if (filp)
4167 -               cred = (struct rpc_cred *)filp->private_data;
4168 -       if (!cred)
4169 -               cred = NFS_I(inode)->mm_cred;
4170 -       return cred;
4171 -}
4172 -
4173  /*
4174   * Bare-bones access to getattr: this is for nfs_read_super.
4175   */
4176 @@ -167,8 +155,7 @@ nfs_proc_readlink(struct inode *inode, s
4177         return status;
4178  }
4179  
4180 -static int
4181 -nfs_proc_read(struct nfs_read_data *rdata, struct file *filp)
4182 +static int nfs_proc_read(struct nfs_read_data *rdata)
4183  {
4184         int                     flags = rdata->flags;
4185         struct inode *          inode = rdata->inode;
4186 @@ -177,15 +164,14 @@ nfs_proc_read(struct nfs_read_data *rdat
4187                 .rpc_proc       = &nfs_procedures[NFSPROC_READ],
4188                 .rpc_argp       = &rdata->args,
4189                 .rpc_resp       = &rdata->res,
4190 +               .rpc_resp       = rdata->cred,
4191         };
4192         int                     status;
4193  
4194         dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
4195                         (long long) rdata->args.offset);
4196         fattr->valid = 0;
4197 -       msg.rpc_cred = nfs_cred(inode, filp);
4198         status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
4199 -
4200         if (status >= 0) {
4201                 nfs_refresh_inode(inode, fattr);
4202                 /* Emulate the eof flag, which isn't normally needed in NFSv2
4203 @@ -198,8 +184,7 @@ nfs_proc_read(struct nfs_read_data *rdat
4204         return status;
4205  }
4206  
4207 -static int
4208 -nfs_proc_write(struct nfs_write_data *wdata, struct file *filp)
4209 +static int nfs_proc_write(struct nfs_write_data *wdata)
4210  {
4211         int                     flags = wdata->flags;
4212         struct inode *          inode = wdata->inode;
4213 @@ -208,13 +193,13 @@ nfs_proc_write(struct nfs_write_data *wd
4214                 .rpc_proc       = &nfs_procedures[NFSPROC_WRITE],
4215                 .rpc_argp       = &wdata->args,
4216                 .rpc_resp       = &wdata->res,
4217 +               .rpc_resp       = wdata->cred,
4218         };
4219         int                     status;
4220  
4221         dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
4222                         (long long) wdata->args.offset);
4223         fattr->valid = 0;
4224 -       msg.rpc_cred = nfs_cred(inode, filp);
4225         status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
4226         if (status >= 0) {
4227                 nfs_refresh_inode(inode, fattr);
4228 @@ -400,6 +385,8 @@ nfs_proc_symlink(struct inode *dir, stru
4229         };
4230         int                     status;
4231  
4232 +       if (path->len > NFS2_MAXPATHLEN)
4233 +               return -ENAMETOOLONG;
4234         dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
4235         fattr->valid = 0;
4236         status = rpc_call(NFS_CLIENT(dir), NFSPROC_SYMLINK, &arg, NULL, 0);
4237 @@ -619,27 +606,6 @@ nfs_proc_commit_setup(struct nfs_write_d
4238         BUG();
4239  }
4240  
4241 -/*
4242 - * Set up the nfspage struct with the right credentials
4243 - */
4244 -static void
4245 -nfs_request_init(struct nfs_page *req, struct file *filp)
4246 -{
4247 -       req->wb_cred = get_rpccred(nfs_cred(req->wb_inode, filp));
4248 -}
4249 -
4250 -static int
4251 -nfs_request_compatible(struct nfs_page *req, struct file *filp, struct page *page)
4252 -{
4253 -       if (req->wb_file != filp)
4254 -               return 0;
4255 -       if (req->wb_page != page)
4256 -               return 0;
4257 -       if (req->wb_cred != nfs_file_cred(filp))
4258 -               return 0;
4259 -       return 1;
4260 -}
4261 -
4262  static int
4263  nfs_proc_lock(struct file *filp, int cmd, struct file_lock *fl)
4264  {
4265 @@ -651,6 +617,7 @@ struct nfs_rpc_ops  nfs_v2_clientops = {
4266         .version        = 2,                   /* protocol version */
4267         .dentry_ops     = &nfs_dentry_operations,
4268         .dir_inode_ops  = &nfs_dir_inode_operations,
4269 +       .file_inode_ops = &nfs_file_inode_operations,
4270         .getroot        = nfs_proc_get_root,
4271         .getattr        = nfs_proc_getattr,
4272         .setattr        = nfs_proc_setattr,
4273 @@ -680,7 +647,5 @@ struct nfs_rpc_ops  nfs_v2_clientops = {
4274         .commit_setup   = nfs_proc_commit_setup,
4275         .file_open      = nfs_open,
4276         .file_release   = nfs_release,
4277 -       .request_init   = nfs_request_init,
4278 -       .request_compatible = nfs_request_compatible,
4279         .lock           = nfs_proc_lock,
4280  };
4281 --- linux-2.6.7/fs/nfs/file.c.lsec      2004-06-15 23:19:37.000000000 -0600
4282 +++ linux-2.6.7/fs/nfs/file.c   2005-03-23 14:28:22.760589560 -0700
4283 @@ -31,6 +31,8 @@
4284  #include <asm/uaccess.h>
4285  #include <asm/system.h>
4286  
4287 +#include "delegation.h"
4288 +
4289  #define NFSDBG_FACILITY                NFSDBG_FILE
4290  
4291  static long nfs_file_fcntl(int fd, unsigned int cmd,
4292 @@ -66,6 +68,19 @@ struct inode_operations nfs_file_inode_o
4293         .setattr        = nfs_setattr,
4294  };
4295  
4296 +#ifdef CONFIG_NFS_V4
4297 +
4298 +struct inode_operations nfs4_file_inode_operations = {
4299 +       .permission     = nfs_permission,
4300 +       .getattr        = nfs_getattr,
4301 +       .setattr        = nfs_setattr,
4302 +       .getxattr       = nfs_getxattr,
4303 +       .setxattr       = nfs_setxattr,
4304 +       .listxattr      = nfs_listxattr,
4305 +};
4306 +
4307 +#endif /* CONFIG_NFS_V4 */
4308 +
4309  /* Hack for future NFS swap support */
4310  #ifndef IS_SWAPFILE
4311  # define IS_SWAPFILE(inode)    (0)
4312 @@ -127,6 +142,7 @@ nfs_file_release(struct inode *inode, st
4313  static int
4314  nfs_file_flush(struct file *file)
4315  {
4316 +       struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
4317         struct inode    *inode = file->f_dentry->d_inode;
4318         int             status;
4319  
4320 @@ -138,9 +154,9 @@ nfs_file_flush(struct file *file)
4321         /* Ensure that data+attribute caches are up to date after close() */
4322         status = nfs_wb_all(inode);
4323         if (!status) {
4324 -               status = file->f_error;
4325 -               file->f_error = 0;
4326 -               if (!status)
4327 +               status = ctx->error;
4328 +               ctx->error = 0;
4329 +               if (!status && !nfs_have_delegation(inode, FMODE_READ))
4330                         __nfs_revalidate_inode(NFS_SERVER(inode), inode);
4331         }
4332         unlock_kernel();
4333 @@ -211,6 +227,7 @@ nfs_file_mmap(struct file * file, struct
4334  static int
4335  nfs_fsync(struct file *file, struct dentry *dentry, int datasync)
4336  {
4337 +       struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
4338         struct inode *inode = dentry->d_inode;
4339         int status;
4340  
4341 @@ -219,8 +236,8 @@ nfs_fsync(struct file *file, struct dent
4342         lock_kernel();
4343         status = nfs_wb_all(inode);
4344         if (!status) {
4345 -               status = file->f_error;
4346 -               file->f_error = 0;
4347 +               status = ctx->error;
4348 +               ctx->error = 0;
4349         }
4350         unlock_kernel();
4351         return status;
4352 @@ -302,6 +319,90 @@ out_swapfile:
4353         goto out;
4354  }
4355  
4356 +static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
4357 +{
4358 +       struct inode *inode = filp->f_mapping->host;
4359 +       int status;
4360 +
4361 +       lock_kernel();
4362 +       status = NFS_PROTO(inode)->lock(filp, cmd, fl);
4363 +       unlock_kernel();
4364 +       return status;
4365 +}
4366 +
4367 +static int do_unlk(struct file *filp, int cmd, struct file_lock *fl)
4368 +{
4369 +       struct inode *inode = filp->f_mapping->host;
4370 +       sigset_t oldset;
4371 +       int status;
4372 +
4373 +       rpc_clnt_sigmask(NFS_CLIENT(inode), &oldset);
4374 +       /*
4375 +        * Flush all pending writes before doing anything
4376 +        * with locks..
4377 +        */
4378 +       filemap_fdatawrite(filp->f_mapping);
4379 +       down(&inode->i_sem);
4380 +       nfs_wb_all(inode);
4381 +       up(&inode->i_sem);
4382 +       filemap_fdatawait(filp->f_mapping);
4383 +
4384 +       /* NOTE: special case
4385 +        *      If we're signalled while cleaning up locks on process exit, we
4386 +        *      still need to complete the unlock.
4387 +        */
4388 +       lock_kernel();
4389 +       status = NFS_PROTO(inode)->lock(filp, cmd, fl);
4390 +       rpc_clnt_sigunmask(NFS_CLIENT(inode), &oldset);
4391 +       return status;
4392 +}
4393 +
4394 +static int do_setlk(struct file *filp, int cmd, struct file_lock *fl)
4395 +{
4396 +       struct inode *inode = filp->f_mapping->host;
4397 +       int status;
4398 +
4399 +       /*
4400 +        * Flush all pending writes before doing anything
4401 +        * with locks..
4402 +        */
4403 +       status = filemap_fdatawrite(filp->f_mapping);
4404 +       if (status == 0) {
4405 +               down(&inode->i_sem);
4406 +               status = nfs_wb_all(inode);
4407 +               up(&inode->i_sem);
4408 +               if (status == 0)
4409 +                       status = filemap_fdatawait(filp->f_mapping);
4410 +       }
4411 +       if (status < 0)
4412 +               return status;
4413 +
4414 +       lock_kernel();
4415 +       status = NFS_PROTO(inode)->lock(filp, cmd, fl);
4416 +       /* If we were signalled we still need to ensure that
4417 +        * we clean up any state on the server. We therefore
4418 +        * record the lock call as having succeeded in order to
4419 +        * ensure that locks_remove_posix() cleans it out when
4420 +        * the process exits.
4421 +        */
4422 +       if (status == -EINTR || status == -ERESTARTSYS)
4423 +               posix_lock_file(filp, fl);
4424 +       unlock_kernel();
4425 +       if (status < 0)
4426 +               return status;
4427 +       /*
4428 +        * Make sure we clear the cache whenever we try to get the lock.
4429 +        * This makes locking act as a cache coherency point.
4430 +        */
4431 +       filemap_fdatawrite(filp->f_mapping);
4432 +       down(&inode->i_sem);
4433 +       nfs_wb_all(inode);      /* we may have slept */
4434 +       up(&inode->i_sem);
4435 +       filemap_fdatawait(filp->f_mapping);
4436 +       nfs_zap_caches(inode);
4437 +       return 0;
4438 +}
4439 +
4440  /*
4441   * Lock a (portion of) a file
4442   */
4443 @@ -309,8 +410,6 @@ int
4444  nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
4445  {
4446         struct inode * inode = filp->f_mapping->host;
4447 -       int     status = 0;
4448 -       int     status2;
4449  
4450         dprintk("NFS: nfs_lock(f=%s/%ld, t=%x, fl=%x, r=%Ld:%Ld)\n",
4451                         inode->i_sb->s_id, inode->i_ino,
4452 @@ -328,8 +427,8 @@ nfs_lock(struct file *filp, int cmd, str
4453                 /* Fake OK code if mounted without NLM support */
4454                 if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM) {
4455                         if (IS_GETLK(cmd))
4456 -                               status = LOCK_USE_CLNT;
4457 -                       goto out_ok;
4458 +                               return LOCK_USE_CLNT;
4459 +                       return 0;
4460                 }
4461         }
4462  
4463 @@ -340,45 +439,12 @@ nfs_lock(struct file *filp, int cmd, str
4464          * Not sure whether that would be unique, though, or whether
4465          * that would break in other places.
4466          */
4467 -       if (!fl->fl_owner || !(fl->fl_flags & FL_POSIX))
4468 +       if (!(fl->fl_flags & FL_POSIX))
4469                 return -ENOLCK;
4470  
4471 -       /*
4472 -        * Flush all pending writes before doing anything
4473 -        * with locks..
4474 -        */
4475 -       status = filemap_fdatawrite(filp->f_mapping);
4476 -       down(&inode->i_sem);
4477 -       status2 = nfs_wb_all(inode);
4478 -       if (!status)
4479 -               status = status2;
4480 -       up(&inode->i_sem);
4481 -       status2 = filemap_fdatawait(filp->f_mapping);
4482 -       if (!status)
4483 -               status = status2;
4484 -       if (status < 0)
4485 -               return status;
4486 -
4487 -       lock_kernel();
4488 -       status = NFS_PROTO(inode)->lock(filp, cmd, fl);
4489 -       unlock_kernel();
4490 -       if (status < 0)
4491 -               return status;
4492 -       
4493 -       status = 0;
4494 -
4495 -       /*
4496 -        * Make sure we clear the cache whenever we try to get the lock.
4497 -        * This makes locking act as a cache coherency point.
4498 -        */
4499 - out_ok:
4500 -       if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
4501 -               filemap_fdatawrite(filp->f_mapping);
4502 -               down(&inode->i_sem);
4503 -               nfs_wb_all(inode);      /* we may have slept */
4504 -               up(&inode->i_sem);
4505 -               filemap_fdatawait(filp->f_mapping);
4506 -               nfs_zap_caches(inode);
4507 -       }
4508 -       return status;
4509 +       if (IS_GETLK(cmd))
4510 +               return do_getlk(filp, cmd, fl);
4511 +       if (fl->fl_type == F_UNLCK)
4512 +               return do_unlk(filp, cmd, fl);
4513 +       return do_setlk(filp, cmd, fl);
4514  }
4515 --- linux-2.6.7/fs/nfs/write.c.lsec     2004-06-15 23:19:43.000000000 -0600
4516 +++ linux-2.6.7/fs/nfs/write.c  2005-03-23 14:28:23.225518880 -0700
4517 @@ -63,6 +63,8 @@
4518  #include <linux/smp_lock.h>
4519  #include <linux/mempool.h>
4520  
4521 +#include "delegation.h"
4522 +
4523  #define NFSDBG_FACILITY                NFSDBG_PAGECACHE
4524  
4525  #define MIN_POOL_WRITE         (32)
4526 @@ -71,7 +73,8 @@
4527  /*
4528   * Local function declarations
4529   */
4530 -static struct nfs_page * nfs_update_request(struct file*, struct inode *,
4531 +static struct nfs_page * nfs_update_request(struct nfs_open_context*,
4532 +                                           struct inode *,
4533                                             struct page *,
4534                                             unsigned int, unsigned int);
4535  static void nfs_writeback_done_partial(struct nfs_write_data *, int);
4536 @@ -173,7 +176,7 @@ static void nfs_mark_uptodate(struct pag
4537   * Write a page synchronously.
4538   * Offset is the data offset within the page.
4539   */
4540 -static int nfs_writepage_sync(struct file *file, struct inode *inode,
4541 +static int nfs_writepage_sync(struct nfs_open_context *ctx, struct inode *inode,
4542                 struct page *page, unsigned int offset, unsigned int count,
4543                 int how)
4544  {
4545 @@ -187,9 +190,10 @@ static int nfs_writepage_sync(struct fil
4546  
4547         memset(wdata, 0, sizeof(*wdata));
4548         wdata->flags = how;
4549 +       wdata->cred = ctx->cred;
4550         wdata->inode = inode;
4551         wdata->args.fh = NFS_FH(inode);
4552 -       wdata->args.lockowner = current->files;
4553 +       wdata->args.context = ctx;
4554         wdata->args.pages = &page;
4555         wdata->args.stable = NFS_FILE_SYNC;
4556         wdata->args.pgbase = offset;
4557 @@ -208,7 +212,7 @@ static int nfs_writepage_sync(struct fil
4558                         wdata->args.count = count;
4559                 wdata->args.offset = page_offset(page) + wdata->args.pgbase;
4560  
4561 -               result = NFS_PROTO(inode)->write(wdata, file);
4562 +               result = NFS_PROTO(inode)->write(wdata);
4563  
4564                 if (result < 0) {
4565                         /* Must mark the page invalid after I/O error */
4566 @@ -241,13 +245,14 @@ io_error:
4567         return written ? written : result;
4568  }
4569  
4570 -static int nfs_writepage_async(struct file *file, struct inode *inode,
4571 -               struct page *page, unsigned int offset, unsigned int count)
4572 +static int nfs_writepage_async(struct nfs_open_context *ctx,
4573 +               struct inode *inode, struct page *page,
4574 +               unsigned int offset, unsigned int count)
4575  {
4576         struct nfs_page *req;
4577         int             status;
4578  
4579 -       req = nfs_update_request(file, inode, page, offset, count);
4580 +       req = nfs_update_request(ctx, inode, page, offset, count);
4581         status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
4582         if (status < 0)
4583                 goto out;
4584 @@ -274,6 +279,7 @@ static int wb_priority(struct writeback_
4585   */
4586  int nfs_writepage(struct page *page, struct writeback_control *wbc)
4587  {
4588 +       struct nfs_open_context *ctx;
4589         struct inode *inode = page->mapping->host;
4590         unsigned long end_index;
4591         unsigned offset = PAGE_CACHE_SIZE;
4592 @@ -308,16 +314,21 @@ int nfs_writepage(struct page *page, str
4593         if (page->index >= end_index+1 || !offset)
4594                 goto out;
4595  do_it:
4596 +       ctx = nfs_find_open_context(inode, FMODE_WRITE);
4597 +       if (ctx == NULL) {
4598 +               err = -EBADF;
4599 +               goto out;
4600 +       }
4601         lock_kernel();
4602         if (!IS_SYNC(inode) && inode_referenced) {
4603 -               err = nfs_writepage_async(NULL, inode, page, 0, offset);
4604 +               err = nfs_writepage_async(ctx, inode, page, 0, offset);
4605                 if (err >= 0) {
4606                         err = 0;
4607                         if (wbc->for_reclaim)
4608                                 nfs_flush_inode(inode, 0, 0, FLUSH_STABLE);
4609                 }
4610         } else {
4611 -               err = nfs_writepage_sync(NULL, inode, page, 0,
4612 +               err = nfs_writepage_sync(ctx, inode, page, 0,
4613                                                 offset, priority);
4614                 if (err >= 0) {
4615                         if (err != offset)
4616 @@ -326,6 +337,7 @@ do_it:
4617                 }
4618         }
4619         unlock_kernel();
4620 +       put_nfs_open_context(ctx);
4621  out:
4622         unlock_page(page);
4623         if (inode_referenced)
4624 @@ -374,8 +386,7 @@ out:
4625  /*
4626   * Insert a write request into an inode
4627   */
4628 -static inline int
4629 -nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
4630 +static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
4631  {
4632         struct nfs_inode *nfsi = NFS_I(inode);
4633         int error;
4634 @@ -387,6 +398,8 @@ nfs_inode_add_request(struct inode *inod
4635         if (!nfsi->npages) {
4636                 igrab(inode);
4637                 nfs_begin_data_update(inode);
4638 +               if (nfs_have_delegation(inode, FMODE_WRITE))
4639 +                       nfsi->change_attr++;
4640         }
4641         nfsi->npages++;
4642         req->wb_count++;
4643 @@ -404,7 +417,7 @@ nfs_inode_remove_request(struct nfs_page
4644  
4645         BUG_ON (!NFS_WBACK_BUSY(req));
4646         spin_lock(&nfs_wreq_lock);
4647 -       inode = req->wb_inode;
4648 +       inode = req->wb_context->dentry->d_inode;
4649         nfsi = NFS_I(inode);
4650         radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
4651         nfsi->npages--;
4652 @@ -450,7 +463,7 @@ nfs_find_request(struct inode *inode, un
4653  static void
4654  nfs_mark_request_dirty(struct nfs_page *req)
4655  {
4656 -       struct inode *inode = req->wb_inode;
4657 +       struct inode *inode = req->wb_context->dentry->d_inode;
4658         struct nfs_inode *nfsi = NFS_I(inode);
4659  
4660         spin_lock(&nfs_wreq_lock);
4661 @@ -467,7 +480,7 @@ nfs_mark_request_dirty(struct nfs_page *
4662  static inline int
4663  nfs_dirty_request(struct nfs_page *req)
4664  {
4665 -       struct nfs_inode *nfsi = NFS_I(req->wb_inode);
4666 +       struct nfs_inode *nfsi = NFS_I(req->wb_context->dentry->d_inode);
4667         return !list_empty(&req->wb_list) && req->wb_list_head == &nfsi->dirty;
4668  }
4669  
4670 @@ -478,7 +491,7 @@ nfs_dirty_request(struct nfs_page *req)
4671  static void
4672  nfs_mark_request_commit(struct nfs_page *req)
4673  {
4674 -       struct inode *inode = req->wb_inode;
4675 +       struct inode *inode = req->wb_context->dentry->d_inode;
4676         struct nfs_inode *nfsi = NFS_I(inode);
4677  
4678         spin_lock(&nfs_wreq_lock);
4679 @@ -619,9 +632,9 @@ static int nfs_wait_on_write_congestion(
4680   *
4681   * Note: Should always be called with the Page Lock held!
4682   */
4683 -static struct nfs_page *
4684 -nfs_update_request(struct file* file, struct inode *inode, struct page *page,
4685 -                  unsigned int offset, unsigned int bytes)
4686 +static struct nfs_page * nfs_update_request(struct nfs_open_context* ctx,
4687 +               struct inode *inode, struct page *page,
4688 +               unsigned int offset, unsigned int bytes)
4689  {
4690         struct nfs_server *server = NFS_SERVER(inode);
4691         struct nfs_page         *req, *new = NULL;
4692 @@ -668,13 +681,9 @@ nfs_update_request(struct file* file, st
4693                 }
4694                 spin_unlock(&nfs_wreq_lock);
4695  
4696 -               new = nfs_create_request(file, inode, page, offset, bytes);
4697 +               new = nfs_create_request(ctx, inode, page, offset, bytes);
4698                 if (IS_ERR(new))
4699                         return new;
4700 -               if (file) {
4701 -                       new->wb_file = file;
4702 -                       get_file(file);
4703 -               }
4704         }
4705  
4706         /* We have a request for our page.
4707 @@ -684,7 +693,7 @@ nfs_update_request(struct file* file, st
4708          * request.
4709          */
4710         rqend = req->wb_offset + req->wb_bytes;
4711 -       if (req->wb_file != file
4712 +       if (req->wb_context != ctx
4713             || req->wb_page != page
4714             || !nfs_dirty_request(req)
4715             || offset > rqend || end < req->wb_offset) {
4716 @@ -705,9 +714,9 @@ nfs_update_request(struct file* file, st
4717         return req;
4718  }
4719  
4720 -int
4721 -nfs_flush_incompatible(struct file *file, struct page *page)
4722 +int nfs_flush_incompatible(struct file *file, struct page *page)
4723  {
4724 +       struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
4725         struct inode    *inode = page->mapping->host;
4726         struct nfs_page *req;
4727         int             status = 0;
4728 @@ -721,7 +730,7 @@ nfs_flush_incompatible(struct file *file
4729          */
4730         req = nfs_find_request(inode, page->index);
4731         if (req) {
4732 -               if (!NFS_PROTO(inode)->request_compatible(req, file, page))
4733 +               if (req->wb_page != page || ctx != req->wb_context)
4734                         status = nfs_wb_page(inode, page);
4735                 nfs_release_request(req);
4736         }
4737 @@ -737,6 +746,7 @@ nfs_flush_incompatible(struct file *file
4738  int nfs_updatepage(struct file *file, struct page *page,
4739                 unsigned int offset, unsigned int count)
4740  {
4741 +       struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data;
4742         struct dentry   *dentry = file->f_dentry;
4743         struct inode    *inode = page->mapping->host;
4744         struct nfs_page *req;
4745 @@ -747,7 +757,7 @@ int nfs_updatepage(struct file *file, st
4746                 count, (long long)(page_offset(page) +offset));
4747  
4748         if (IS_SYNC(inode)) {
4749 -               status = nfs_writepage_sync(file, inode, page, offset, count, 0);
4750 +               status = nfs_writepage_sync(ctx, inode, page, offset, count, 0);
4751                 if (status > 0) {
4752                         if (offset == 0 && status == PAGE_CACHE_SIZE)
4753                                 SetPageUptodate(page);
4754 @@ -784,7 +794,7 @@ int nfs_updatepage(struct file *file, st
4755          * it out now.
4756          */
4757         do {
4758 -               req = nfs_update_request(file, inode, page, offset, count);
4759 +               req = nfs_update_request(ctx, inode, page, offset, count);
4760                 status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
4761                 if (status != -EBUSY)
4762                         break;
4763 @@ -860,16 +870,15 @@ static void nfs_write_rpcsetup(struct nf
4764          * NB: take care not to mess about with data->commit et al. */
4765  
4766         data->req = req;
4767 -       data->inode = inode = req->wb_inode;
4768 -       data->cred = req->wb_cred;
4769 +       data->inode = inode = req->wb_context->dentry->d_inode;
4770 +       data->cred = req->wb_context->cred;
4771  
4772         data->args.fh     = NFS_FH(inode);
4773         data->args.offset = req_offset(req) + offset;
4774         data->args.pgbase = req->wb_pgbase + offset;
4775         data->args.pages  = data->pagevec;
4776         data->args.count  = count;
4777 -       data->args.lockowner = req->wb_lockowner;
4778 -       data->args.state  = req->wb_state;
4779 +       data->args.context = req->wb_context;
4780  
4781         data->res.fattr   = &data->fattr;
4782         data->res.count   = count;
4783 @@ -1029,7 +1038,7 @@ nfs_flush_list(struct list_head *head, i
4784         while (!list_empty(head)) {
4785                 pages += nfs_coalesce_requests(head, &one_request, wpages);
4786                 req = nfs_list_entry(one_request.next);
4787 -               error = nfs_flush_one(&one_request, req->wb_inode, how);
4788 +               error = nfs_flush_one(&one_request, req->wb_context->dentry->d_inode, how);
4789                 if (error < 0)
4790                         break;
4791         }
4792 @@ -1054,16 +1063,15 @@ static void nfs_writeback_done_partial(s
4793         struct page             *page = req->wb_page;
4794  
4795         dprintk("NFS: write (%s/%Ld %d@%Ld)",
4796 -               req->wb_inode->i_sb->s_id,
4797 -               (long long)NFS_FILEID(req->wb_inode),
4798 +               req->wb_context->dentry->d_inode->i_sb->s_id,
4799 +               (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
4800                 req->wb_bytes,
4801                 (long long)req_offset(req));
4802  
4803         if (status < 0) {
4804                 ClearPageUptodate(page);
4805                 SetPageError(page);
4806 -               if (req->wb_file)
4807 -                       req->wb_file->f_error = status;
4808 +               req->wb_context->error = status;
4809                 dprintk(", error = %d\n", status);
4810         } else {
4811  #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
4812 @@ -1104,16 +1112,15 @@ static void nfs_writeback_done_full(stru
4813                 page = req->wb_page;
4814  
4815                 dprintk("NFS: write (%s/%Ld %d@%Ld)",
4816 -                       req->wb_inode->i_sb->s_id,
4817 -                       (long long)NFS_FILEID(req->wb_inode),
4818 +                       req->wb_context->dentry->d_inode->i_sb->s_id,
4819 +                       (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
4820                         req->wb_bytes,
4821                         (long long)req_offset(req));
4822  
4823                 if (status < 0) {
4824                         ClearPageUptodate(page);
4825                         SetPageError(page);
4826 -                       if (req->wb_file)
4827 -                               req->wb_file->f_error = status;
4828 +                       req->wb_context->error = status;
4829                         end_page_writeback(page);
4830                         nfs_inode_remove_request(req);
4831                         dprintk(", error = %d\n", status);
4832 @@ -1232,7 +1239,7 @@ static void nfs_commit_rpcsetup(struct l
4833         list_splice_init(head, &data->pages);
4834         first = nfs_list_entry(data->pages.next);
4835         last = nfs_list_entry(data->pages.prev);
4836 -       inode = first->wb_inode;
4837 +       inode = first->wb_context->dentry->d_inode;
4838  
4839         /*
4840          * Determine the offset range of requests in the COMMIT call.
4841 @@ -1246,7 +1253,7 @@ static void nfs_commit_rpcsetup(struct l
4842                 len = 0;
4843  
4844         data->inode       = inode;
4845 -       data->cred        = first->wb_cred;
4846 +       data->cred        = first->wb_context->cred;
4847  
4848         data->args.fh     = NFS_FH(data->inode);
4849         data->args.offset = start;
4850 @@ -1313,13 +1320,12 @@ nfs_commit_done(struct rpc_task *task)
4851                 nfs_list_remove_request(req);
4852  
4853                 dprintk("NFS: commit (%s/%Ld %d@%Ld)",
4854 -                       req->wb_inode->i_sb->s_id,
4855 -                       (long long)NFS_FILEID(req->wb_inode),
4856 +                       req->wb_context->dentry->d_inode->i_sb->s_id,
4857 +                       (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
4858                         req->wb_bytes,
4859                         (long long)req_offset(req));
4860                 if (task->tk_status < 0) {
4861 -                       if (req->wb_file)
4862 -                               req->wb_file->f_error = task->tk_status;
4863 +                       req->wb_context->error = task->tk_status;
4864                         nfs_inode_remove_request(req);
4865                         dprintk(", error = %d\n", task->tk_status);
4866                         goto next;
4867 --- linux-2.6.7/fs/nfs/nfs4xdr.c.lsec   2004-06-15 23:20:26.000000000 -0600
4868 +++ linux-2.6.7/fs/nfs/nfs4xdr.c        2005-03-23 14:28:23.056544568 -0700
4869 @@ -84,9 +84,13 @@ static int nfs_stat_to_errno(int);
4870                                 ((3+NFS4_FHSIZE) >> 2))
4871  #define encode_getattr_maxsz    (op_encode_hdr_maxsz + 3)
4872  #define nfs4_name_maxsz                (1 + ((3 + NFS4_MAXNAMLEN) >> 2))
4873 +#define nfs4_path_maxsz                (1 + ((3 + NFS4_MAXPATHLEN) >> 2))
4874  #define nfs4_fattr_bitmap_maxsz (36 + 2 * nfs4_name_maxsz)
4875  #define decode_getattr_maxsz    (op_decode_hdr_maxsz + 3 + \
4876                                  nfs4_fattr_bitmap_maxsz)
4877 +#define encode_setattr_maxsz   (op_decode_hdr_maxsz + 4 + \
4878 +                               nfs4_fattr_bitmap_maxsz)
4879 +#define decode_setattr_maxsz   (op_decode_hdr_maxsz + 3)
4880  #define encode_savefh_maxsz     (op_encode_hdr_maxsz)
4881  #define decode_savefh_maxsz     (op_decode_hdr_maxsz)
4882  #define encode_fsinfo_maxsz    (op_encode_hdr_maxsz + 2)
4883 @@ -118,10 +122,17 @@ static int nfs_stat_to_errno(int);
4884  #define encode_link_maxsz      (op_encode_hdr_maxsz + \
4885                                 nfs4_name_maxsz)
4886  #define decode_link_maxsz      (op_decode_hdr_maxsz + 5)
4887 +#define encode_symlink_maxsz   (op_encode_hdr_maxsz + \
4888 +                               1 + nfs4_name_maxsz + \
4889 +                               nfs4_path_maxsz + \
4890 +                               nfs4_fattr_bitmap_maxsz)
4891 +#define decode_symlink_maxsz   (op_decode_hdr_maxsz + 8)
4892  #define encode_create_maxsz    (op_encode_hdr_maxsz + \
4893 -                               2 + 2 * nfs4_name_maxsz + \
4894 +                               2 + nfs4_name_maxsz + \
4895                                 nfs4_fattr_bitmap_maxsz)
4896  #define decode_create_maxsz    (op_decode_hdr_maxsz + 8)
4897 +#define encode_delegreturn_maxsz (op_encode_hdr_maxsz + 4)
4898 +#define decode_delegreturn_maxsz (op_decode_hdr_maxsz)
4899  #define NFS4_enc_compound_sz   (1024)  /* XXX: large enough? */
4900  #define NFS4_dec_compound_sz   (1024)  /* XXX: large enough? */
4901  #define NFS4_enc_read_sz       (compound_encode_hdr_maxsz + \
4902 @@ -172,16 +183,14 @@ static int nfs_stat_to_errno(int);
4903  #define NFS4_dec_open_confirm_sz        (compound_decode_hdr_maxsz + \
4904                                          decode_putfh_maxsz + \
4905                                          op_decode_hdr_maxsz + 4)
4906 -#define NFS4_enc_open_reclaim_sz       (compound_encode_hdr_maxsz + \
4907 +#define NFS4_enc_open_noattr_sz        (compound_encode_hdr_maxsz + \
4908                                         encode_putfh_maxsz + \
4909                                         op_encode_hdr_maxsz + \
4910 -                                       11 + \
4911 -                                       encode_getattr_maxsz)
4912 -#define NFS4_dec_open_reclaim_sz       (compound_decode_hdr_maxsz + \
4913 +                                       11)
4914 +#define NFS4_dec_open_noattr_sz        (compound_decode_hdr_maxsz + \
4915                                         decode_putfh_maxsz + \
4916                                         op_decode_hdr_maxsz + \
4917 -                                       4 + 5 + 2 + 3 + \
4918 -                                       decode_getattr_maxsz)
4919 +                                       4 + 5 + 2 + 3)
4920  #define NFS4_enc_open_downgrade_sz \
4921                                 (compound_encode_hdr_maxsz + \
4922                                  encode_putfh_maxsz + \
4923 @@ -313,6 +322,16 @@ static int nfs_stat_to_errno(int);
4924                                 decode_savefh_maxsz + \
4925                                 decode_putfh_maxsz + \
4926                                 decode_link_maxsz)
4927 +#define NFS4_enc_symlink_sz    (compound_encode_hdr_maxsz + \
4928 +                               encode_putfh_maxsz + \
4929 +                               encode_symlink_maxsz + \
4930 +                               encode_getattr_maxsz + \
4931 +                               encode_getfh_maxsz)
4932 +#define NFS4_dec_symlink_sz    (compound_decode_hdr_maxsz + \
4933 +                               decode_putfh_maxsz + \
4934 +                               decode_symlink_maxsz + \
4935 +                               decode_getattr_maxsz + \
4936 +                               decode_getfh_maxsz)
4937  #define NFS4_enc_create_sz     (compound_encode_hdr_maxsz + \
4938                                 encode_putfh_maxsz + \
4939                                 encode_create_maxsz + \
4940 @@ -339,6 +358,33 @@ static int nfs_stat_to_errno(int);
4941                                 encode_getattr_maxsz)
4942  #define NFS4_dec_server_caps_sz (compound_decode_hdr_maxsz + \
4943                                 decode_getattr_maxsz)
4944 +#define NFS4_enc_delegreturn_sz        (compound_encode_hdr_maxsz + \
4945 +                               encode_putfh_maxsz + \
4946 +                               encode_delegreturn_maxsz)
4947 +#define NFS4_dec_delegreturn_sz (compound_decode_hdr_maxsz + \
4948 +                               decode_delegreturn_maxsz)
4949 +#define username_maxsz         (1 + ((IDMAP_NAMESZ + 3) >> 2))
4950 +/* XXX: fix ACL bounds */
4951 +#define ace_maxsz              (3 + username_maxsz)
4952 +#define NFS_ACL_MAX_ENTRIES    32
4953 +#define acl_maxentries         ((NFS_ACL_MAX_ENTRIES - 3) * 3 + 6)
4954 +#define acl_maxsz              (1 + acl_maxentries * ace_maxsz)
4955 +#define NFS4_enc_getacl_sz     compound_encode_hdr_maxsz + \
4956 +                               encode_putfh_maxsz + \
4957 +                               encode_getattr_maxsz
4958 +#define username_maxsz         (1 + ((IDMAP_NAMESZ + 3) >> 2))
4959 +#define ace_maxsz              (3 + username_maxsz)
4960 +#define acl_maxentries         ((NFS_ACL_MAX_ENTRIES - 3) * 3 + 6)
4961 +#define acl_maxsz              (1 + acl_maxentries * ace_maxsz)
4962 +#define NFS4_dec_getacl_sz     (compound_decode_hdr_maxsz + \
4963 +                               decode_putfh_maxsz + \
4964 +                               op_decode_hdr_maxsz + 3 + 1 + acl_maxsz)
4965 +#define NFS4_enc_setacl_sz     (compound_encode_hdr_maxsz + \
4966 +                               encode_putfh_maxsz + \
4967 +                               op_encode_hdr_maxsz + 4 + 1 + acl_maxsz)
4968 +#define NFS4_dec_setacl_sz     (compound_decode_hdr_maxsz + \
4969 +                               decode_putfh_maxsz + \
4970 +                               decode_setattr_maxsz)
4971  
4972  static struct {
4973         unsigned int    mode;
4974 @@ -388,6 +434,15 @@ struct compound_hdr {
4975         BUG_ON(!p);                                             \
4976  } while (0)
4977  
4978 +static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
4979 +{
4980 +       uint32_t *p;
4981 +
4982 +       p = xdr_reserve_space(xdr, 4 + len);
4983 +       BUG_ON(p == NULL);
4984 +       xdr_encode_opaque(p, str, len);
4985 +}
4986 +
4987  static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
4988  {
4989         uint32_t *p;
4990 @@ -402,6 +457,15 @@ static int encode_compound_hdr(struct xd
4991         return 0;
4992  }
4993  
4994 +static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
4995 +{
4996 +       uint32_t *p;
4997 +
4998 +       p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
4999 +       BUG_ON(p == NULL);
5000 +       xdr_encode_opaque_fixed(p, verf->data, NFS4_VERIFIER_SIZE);
5001 +}
5002 +
5003  static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs_server *server)
5004  {
5005         char owner_name[IDMAP_NAMESZ];
5006 @@ -420,7 +484,7 @@ static int encode_attrs(struct xdr_strea
5007          * In the worst-case, this would be
5008          *   12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
5009          *          = 36 bytes, plus any contribution from variable-length fields
5010 -        *            such as owner/group/acl's.
5011 +        *            such as owner/group.
5012          */
5013         len = 16;
5014  
5015 @@ -742,19 +806,12 @@ static int encode_lookup(struct xdr_stre
5016         return 0;
5017  }
5018  
5019 -static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
5020 +static void encode_share_access(struct xdr_stream *xdr, int open_flags)
5021  {
5022 -       int status;
5023         uint32_t *p;
5024  
5025 - /*
5026 - * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
5027 - * owner 4, opentype 4 = 36
5028 - */
5029 -       RESERVE_SPACE(36);
5030 -       WRITE32(OP_OPEN);
5031 -       WRITE32(arg->seqid);
5032 -       switch (arg->share_access) {
5033 +       RESERVE_SPACE(8);
5034 +       switch (open_flags & (FMODE_READ|FMODE_WRITE)) {
5035                 case FMODE_READ:
5036                         WRITE32(NFS4_SHARE_ACCESS_READ);
5037                         break;
5038 @@ -767,84 +824,135 @@ static int encode_open(struct xdr_stream
5039                 default:
5040                         BUG();
5041         }
5042 -       WRITE32(0);                  /* for linux, share_deny = 0 always */
5043 +       WRITE32(0);             /* for linux, share_deny = 0 always */
5044 +}
5045 +
5046 +static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
5047 +{
5048 +       uint32_t *p;
5049 + /*
5050 + * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
5051 + * owner 4 = 32
5052 + */
5053 +       RESERVE_SPACE(8);
5054 +       WRITE32(OP_OPEN);
5055 +       WRITE32(arg->seqid);
5056 +       encode_share_access(xdr, arg->open_flags);
5057 +       RESERVE_SPACE(16);
5058         WRITE64(arg->clientid);
5059         WRITE32(4);
5060         WRITE32(arg->id);
5061 -       WRITE32(arg->opentype);
5062 +}
5063  
5064 -       if (arg->opentype == NFS4_OPEN_CREATE) {
5065 -               if (arg->createmode == NFS4_CREATE_EXCLUSIVE) {
5066 -                       RESERVE_SPACE(12);
5067 -                       WRITE32(arg->createmode);
5068 -                       WRITEMEM(arg->u.verifier.data, sizeof(arg->u.verifier.data));
5069 -               }
5070 -               else if (arg->u.attrs) {
5071 -                       RESERVE_SPACE(4);
5072 -                       WRITE32(arg->createmode);
5073 -                       if ((status = encode_attrs(xdr, arg->u.attrs, arg->server)))
5074 -                               return status;
5075 -               }
5076 -               else {
5077 -                       RESERVE_SPACE(12);
5078 -                       WRITE32(arg->createmode);
5079 -                       WRITE32(0);
5080 -                       WRITE32(0);
5081 -               }
5082 +static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
5083 +{
5084 +       uint32_t *p;
5085 +
5086 +       RESERVE_SPACE(4);
5087 +       switch(arg->open_flags & O_EXCL) {
5088 +               case 0:
5089 +                       WRITE32(NFS4_CREATE_UNCHECKED);
5090 +                       encode_attrs(xdr, arg->u.attrs, arg->server);
5091 +                       break;
5092 +               default:
5093 +                       WRITE32(NFS4_CREATE_EXCLUSIVE);
5094 +                       encode_nfs4_verifier(xdr, &arg->u.verifier);
5095         }
5096 +}
5097  
5098 -       RESERVE_SPACE(8 + arg->name->len);
5099 -       WRITE32(NFS4_OPEN_CLAIM_NULL);
5100 -       WRITE32(arg->name->len);
5101 -       WRITEMEM(arg->name->name, arg->name->len);
5102 +static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
5103 +{
5104 +       uint32_t *p;
5105  
5106 -       return 0;
5107 +       RESERVE_SPACE(4);
5108 +       switch (arg->open_flags & O_CREAT) {
5109 +               case 0:
5110 +                       WRITE32(NFS4_OPEN_NOCREATE);
5111 +                       break;
5112 +               default:
5113 +                       BUG_ON(arg->claim != NFS4_OPEN_CLAIM_NULL);
5114 +                       WRITE32(NFS4_OPEN_CREATE);
5115 +                       encode_createmode(xdr, arg);
5116 +       }
5117  }
5118  
5119 -static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
5120 +static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type)
5121  {
5122         uint32_t *p;
5123  
5124 -       RESERVE_SPACE(8+sizeof(arg->stateid.data));
5125 -       WRITE32(OP_OPEN_CONFIRM);
5126 -       WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data));
5127 -       WRITE32(arg->seqid);
5128 +       RESERVE_SPACE(4);
5129 +       switch (delegation_type) {
5130 +               case 0:
5131 +                       WRITE32(NFS4_OPEN_DELEGATE_NONE);
5132 +                       break;
5133 +               case FMODE_READ:
5134 +                       WRITE32(NFS4_OPEN_DELEGATE_READ);
5135 +                       break;
5136 +               case FMODE_WRITE|FMODE_READ:
5137 +                       WRITE32(NFS4_OPEN_DELEGATE_WRITE);
5138 +                       break;
5139 +               default:
5140 +                       BUG();
5141 +       }
5142 +}
5143  
5144 -       return 0;
5145 +static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
5146 +{
5147 +       uint32_t *p;
5148 +
5149 +       RESERVE_SPACE(4);
5150 +       WRITE32(NFS4_OPEN_CLAIM_NULL);
5151 +       encode_string(xdr, name->len, name->name);
5152  }
5153  
5154 +static inline void encode_claim_previous(struct xdr_stream *xdr, int type)
5155 +{
5156 +       uint32_t *p;
5157 +
5158 +       RESERVE_SPACE(4);
5159 +       WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
5160 +       encode_delegation_type(xdr, type);
5161 +}
5162  
5163 -static int encode_open_reclaim(struct xdr_stream *xdr, const struct nfs_open_reclaimargs *arg)
5164 +static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
5165  {
5166         uint32_t *p;
5167  
5168 - /*
5169 - * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
5170 - * owner 4, opentype 4, claim 4, delegation_type 4 = 44
5171 - */
5172 -       RESERVE_SPACE(44);
5173 -       WRITE32(OP_OPEN);
5174 -       WRITE32(arg->seqid);
5175 -       switch (arg->share_access) {
5176 -               case FMODE_READ:
5177 -                       WRITE32(NFS4_SHARE_ACCESS_READ);
5178 +       RESERVE_SPACE(4+sizeof(stateid->data));
5179 +       WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
5180 +       WRITEMEM(stateid->data, sizeof(stateid->data));
5181 +       encode_string(xdr, name->len, name->name);
5182 +}
5183 +
5184 +static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
5185 +{
5186 +       encode_openhdr(xdr, arg);
5187 +       encode_opentype(xdr, arg);
5188 +       switch (arg->claim) {
5189 +               case NFS4_OPEN_CLAIM_NULL:
5190 +                       encode_claim_null(xdr, arg->name);
5191                         break;
5192 -               case FMODE_WRITE:
5193 -                       WRITE32(NFS4_SHARE_ACCESS_WRITE);
5194 +               case NFS4_OPEN_CLAIM_PREVIOUS:
5195 +                       encode_claim_previous(xdr, arg->u.delegation_type);
5196                         break;
5197 -               case FMODE_READ|FMODE_WRITE:
5198 -                       WRITE32(NFS4_SHARE_ACCESS_BOTH);
5199 +               case NFS4_OPEN_CLAIM_DELEGATE_CUR:
5200 +                       encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);
5201                         break;
5202                 default:
5203                         BUG();
5204         }
5205 -       WRITE32(0);                  /* for linux, share_deny = 0 always */
5206 -       WRITE64(arg->clientid);
5207 -       WRITE32(4);
5208 -       WRITE32(arg->id);
5209 -       WRITE32(NFS4_OPEN_NOCREATE);
5210 -       WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
5211 -       WRITE32(NFS4_OPEN_DELEGATE_NONE);
5212 +       return 0;
5213 +}
5214 +
5215 +static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
5216 +{
5217 +       uint32_t *p;
5218 +
5219 +       RESERVE_SPACE(8+sizeof(arg->stateid.data));
5220 +       WRITE32(OP_OPEN_CONFIRM);
5221 +       WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data));
5222 +       WRITE32(arg->seqid);
5223 +
5224         return 0;
5225  }
5226  
5227 @@ -852,14 +960,11 @@ static int encode_open_downgrade(struct 
5228  {
5229         uint32_t *p;
5230  
5231 -       RESERVE_SPACE(16+sizeof(arg->stateid.data));
5232 +       RESERVE_SPACE(8+sizeof(arg->stateid.data));
5233         WRITE32(OP_OPEN_DOWNGRADE);
5234         WRITEMEM(arg->stateid.data, sizeof(arg->stateid.data));
5235         WRITE32(arg->seqid);
5236 -       WRITE32(arg->share_access);
5237 -       /* No deny modes */
5238 -       WRITE32(0);
5239 -
5240 +       encode_share_access(xdr, arg->open_flags);
5241         return 0;
5242  }
5243  
5244 @@ -887,15 +992,15 @@ static int encode_putrootfh(struct xdr_s
5245          return 0;
5246  }
5247  
5248 -static void encode_stateid(struct xdr_stream *xdr, struct nfs4_state *state, fl_owner_t lockowner)
5249 +static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
5250  {
5251         extern nfs4_stateid zero_stateid;
5252         nfs4_stateid stateid;
5253         uint32_t *p;
5254  
5255         RESERVE_SPACE(16);
5256 -       if (state != NULL) {
5257 -               nfs4_copy_stateid(&stateid, state, lockowner);
5258 +       if (ctx->state != NULL) {
5259 +               nfs4_copy_stateid(&stateid, ctx->state, ctx->pid);
5260                 WRITEMEM(stateid.data, sizeof(stateid.data));
5261         } else
5262                 WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
5263 @@ -908,7 +1013,7 @@ static int encode_read(struct xdr_stream
5264         RESERVE_SPACE(4);
5265         WRITE32(OP_READ);
5266  
5267 -       encode_stateid(xdr, args->state, args->lockowner);
5268 +       encode_stateid(xdr, args->context);
5269  
5270         RESERVE_SPACE(12);
5271         WRITE64(args->offset);
5272 @@ -1003,6 +1108,45 @@ static int encode_renew(struct xdr_strea
5273         return 0;
5274  }
5275  
5276 +extern nfs4_stateid zero_stateid;
5277 +
5278 +static int
5279 +encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
5280 +{
5281 +       uint32_t *p;
5282 +       uint32_t *q = (uint32_t *)arg->acl;
5283 +       uint32_t *end = (uint32_t *)(arg->acl + arg->acl_len);
5284 +       uint32_t tmp;
5285 +       int naces, i;
5286 +
5287 +       RESERVE_SPACE(4+sizeof(zero_stateid.data));
5288 +       WRITE32(OP_SETATTR);
5289 +       WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
5290 +       RESERVE_SPACE(4*4);
5291 +       WRITE32(1);
5292 +       WRITE32(FATTR4_WORD0_ACL);
5293 +       WRITE32(arg->acl_len);
5294 +       if (q + 1 > end)
5295 +               return -EINVAL;
5296 +       naces = ntohl(*q++);
5297 +       WRITE32(naces);
5298 +       for (i = 0; i < naces; i++) {
5299 +               if (q + 4 > end)
5300 +                       return -EINVAL;
5301 +               RESERVE_SPACE(3*4);
5302 +               memcpy(p, q, 3*4); /* type, flag, access_mask, length */
5303 +               q += 3;
5304 +               tmp = ntohl(*q++); /* length */
5305 +               if (tmp > XDR_MAX_NETOBJ)
5306 +                       return -EINVAL;
5307 +               if (q + XDR_QUADLEN(tmp) > end)
5308 +                       return -EINVAL;
5309 +               RESERVE_SPACE((XDR_QUADLEN(tmp) << 2) + 4);
5310 +               p = xdr_encode_opaque(p, q, tmp);
5311 +       }
5312 +       return 0;
5313 +}
5314 +
5315  static int
5316  encode_savefh(struct xdr_stream *xdr)
5317  {
5318 @@ -1031,26 +1175,18 @@ static int encode_setattr(struct xdr_str
5319  
5320  static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
5321  {
5322 -       uint32_t total_len;
5323 -       uint32_t len1, len2, len3;
5324         uint32_t *p;
5325  
5326 -       len1 = strlen(setclientid->sc_name);
5327 -       len2 = strlen(setclientid->sc_netid);
5328 -       len3 = strlen(setclientid->sc_uaddr);
5329 -       total_len = XDR_QUADLEN(len1) + XDR_QUADLEN(len2) + XDR_QUADLEN(len3);
5330 -       total_len = (total_len << 2) + 24 + sizeof(setclientid->sc_verifier.data);
5331 -
5332 -       RESERVE_SPACE(total_len);
5333 +       RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data));
5334         WRITE32(OP_SETCLIENTID);
5335 -       WRITEMEM(setclientid->sc_verifier.data, sizeof(setclientid->sc_verifier.data));
5336 -       WRITE32(len1);
5337 -       WRITEMEM(setclientid->sc_name, len1);
5338 +       WRITEMEM(setclientid->sc_verifier->data, sizeof(setclientid->sc_verifier->data));
5339 +
5340 +       encode_string(xdr, setclientid->sc_name_len, setclientid->sc_name);
5341 +       RESERVE_SPACE(4);
5342         WRITE32(setclientid->sc_prog);
5343 -       WRITE32(len2);
5344 -       WRITEMEM(setclientid->sc_netid, len2);
5345 -       WRITE32(len3);
5346 -       WRITEMEM(setclientid->sc_uaddr, len3);
5347 +       encode_string(xdr, setclientid->sc_netid_len, setclientid->sc_netid);
5348 +       encode_string(xdr, setclientid->sc_uaddr_len, setclientid->sc_uaddr);
5349 +       RESERVE_SPACE(4);
5350         WRITE32(setclientid->sc_cb_ident);
5351  
5352         return 0;
5353 @@ -1075,7 +1211,7 @@ static int encode_write(struct xdr_strea
5354         RESERVE_SPACE(4);
5355         WRITE32(OP_WRITE);
5356  
5357 -       encode_stateid(xdr, args->state, args->lockowner);
5358 +       encode_stateid(xdr, args->context);
5359  
5360         RESERVE_SPACE(16);
5361         WRITE64(args->offset);
5362 @@ -1086,6 +1222,18 @@ static int encode_write(struct xdr_strea
5363  
5364         return 0;
5365  }
5366 +
5367 +static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
5368 +{
5369 +       uint32_t *p;
5370 +
5371 +       RESERVE_SPACE(20);
5372 +
5373 +       WRITE32(OP_DELEGRETURN);
5374 +       WRITEMEM(stateid->data, sizeof(stateid->data));
5375 +       return 0;
5376 +
5377 +}
5378  /*
5379   * END OF "GENERIC" ENCODE ROUTINES.
5380   */
5381 @@ -1244,6 +1392,14 @@ out:
5382  }
5383  
5384  /*
5385 + * Encode SYMLINK request
5386 + */
5387 +static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
5388 +{
5389 +       return nfs4_xdr_enc_create(req, p, args);
5390 +}
5391 +
5392 +/*
5393   * Encode GETATTR request
5394   */
5395  static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args)
5396 @@ -1331,13 +1487,13 @@ out:
5397  }
5398  
5399  /*
5400 - * Encode an OPEN request
5401 + * Encode an OPEN request with no attributes.
5402   */
5403 -static int nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p, struct nfs_open_reclaimargs *args)
5404 +static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
5405  {
5406         struct xdr_stream xdr;
5407         struct compound_hdr hdr = {
5408 -               .nops   = 3,
5409 +               .nops   = 2,
5410         };
5411         int status;
5412  
5413 @@ -1346,10 +1502,7 @@ static int nfs4_xdr_enc_open_reclaim(str
5414         status = encode_putfh(&xdr, args->fh);
5415         if (status)
5416                 goto out;
5417 -       status = encode_open_reclaim(&xdr, args);
5418 -       if (status)
5419 -               goto out;
5420 -       status = encode_getfattr(&xdr, args->bitmask);
5421 +       status = encode_open(&xdr, args);
5422  out:
5423         return status;
5424  }
5425 @@ -1538,6 +1691,52 @@ out:
5426  }
5427  
5428  /*
5429 + * Encode an SETACL request
5430 + */
5431 +static int
5432 +nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args)
5433 +
5434 +{
5435 +        struct xdr_stream xdr;
5436 +        struct compound_hdr hdr = {
5437 +                .nops   = 2,
5438 +        };
5439 +        int status;
5440 +
5441 +        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
5442 +        encode_compound_hdr(&xdr, &hdr);
5443 +        status = encode_putfh(&xdr, args->fh);
5444 +        if(status)
5445 +                goto out;
5446 +        status = encode_setacl(&xdr, args);
5447 +out:
5448 +        return status;
5449 +}
5450 +
5451 +/*
5452 + * Encode a GETACL request
5453 + */
5454 +static int
5455 +nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p,struct nfs_fh *fhandle)
5456 +{
5457 +       struct xdr_stream xdr;
5458 +       struct compound_hdr hdr = {
5459 +               .nops   = 2,
5460 +       };
5461 +       int status;
5462 +
5463 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
5464 +       encode_compound_hdr(&xdr, &hdr);
5465 +       status = encode_putfh(&xdr, fhandle);
5466 +       if (status)
5467 +               goto out;
5468 +       status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
5469 +out:
5470 +       return status;
5471 +
5472 +}
5473 +
5474 +/*
5475   * Encode a WRITE request
5476   */
5477  static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
5478 @@ -1716,6 +1915,24 @@ static int nfs4_xdr_enc_setclientid_conf
5479  }
5480  
5481  /*
5482 + * DELEGRETURN request
5483 + */
5484 +static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const struct nfs4_delegreturnargs *args)
5485 +{
5486 +       struct xdr_stream xdr;
5487 +       struct compound_hdr hdr = {
5488 +               .nops = 2,
5489 +       };
5490 +       int status;
5491 +
5492 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
5493 +       encode_compound_hdr(&xdr, &hdr);
5494 +       if ((status = encode_putfh(&xdr, args->fhandle)) == 0)
5495 +               status = encode_delegreturn(&xdr, args->stateid);
5496 +       return status;
5497 +}
5498 +
5499 +/*
5500   * START OF "GENERIC" DECODE ROUTINES.
5501   *   These may look a little ugly since they are imported from a "generic"
5502   * set of XDR encode/decode routines which are intended to be shared by
5503 @@ -1749,6 +1966,17 @@ static int nfs4_xdr_enc_setclientid_conf
5504         } \
5505  } while (0)
5506  
5507 +static int decode_opaque_inline(struct xdr_stream *xdr, uint32_t *len, char **string)
5508 +{
5509 +       uint32_t *p;
5510 +
5511 +       READ_BUF(4);
5512 +       READ32(*len);
5513 +       READ_BUF(*len);
5514 +       *string = (char *)p;
5515 +       return 0;
5516 +}
5517 +
5518  static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
5519  {
5520         uint32_t *p;
5521 @@ -1785,6 +2013,17 @@ static int decode_op_hdr(struct xdr_stre
5522         return 0;
5523  }
5524  
5525 +/* Dummy routine */
5526 +static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs4_client *clp)
5527 +{
5528 +       uint32_t *p;
5529 +       uint32_t strlen;
5530 +       char *str;
5531 +
5532 +       READ_BUF(12);
5533 +       return decode_opaque_inline(xdr, &strlen, &str);
5534 +}
5535 +
5536  static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
5537  {
5538         uint32_t bmlen, *p;
5539 @@ -2717,10 +2956,56 @@ static int decode_lookup(struct xdr_stre
5540         return decode_op_hdr(xdr, OP_LOOKUP);
5541  }
5542  
5543 +/* This is too sick! */
5544 +static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
5545 +{
5546 +        uint32_t *p;
5547 +       uint32_t limit_type, nblocks, blocksize;
5548 +
5549 +       READ_BUF(12);
5550 +       READ32(limit_type);
5551 +       switch (limit_type) {
5552 +               case 1:
5553 +                       READ64(*maxsize);
5554 +                       break;
5555 +               case 2:
5556 +                       READ32(nblocks);
5557 +                       READ32(blocksize);
5558 +                       *maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
5559 +       }
5560 +       return 0;
5561 +}
5562 +
5563 +static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
5564 +{
5565 +        uint32_t *p;
5566 +        uint32_t delegation_type;
5567 +
5568 +       READ_BUF(4);
5569 +       READ32(delegation_type);
5570 +       if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
5571 +               res->delegation_type = 0;
5572 +               return 0;
5573 +       }
5574 +       READ_BUF(20);
5575 +       COPYMEM(res->delegation.data, sizeof(res->delegation.data));
5576 +       READ32(res->do_recall);
5577 +       switch (delegation_type) {
5578 +               case NFS4_OPEN_DELEGATE_READ:
5579 +                       res->delegation_type = FMODE_READ;
5580 +                       break;
5581 +               case NFS4_OPEN_DELEGATE_WRITE:
5582 +                       res->delegation_type = FMODE_WRITE|FMODE_READ;
5583 +                       if (decode_space_limit(xdr, &res->maxsize) < 0)
5584 +                               return -EIO;
5585 +       }
5586 +       return decode_ace(xdr, NULL, res->server->nfs4_state);
5587 +}
5588 +
5589  static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
5590  {
5591          uint32_t *p;
5592 -        uint32_t bmlen, delegation_type;
5593 +        uint32_t bmlen;
5594          int status;
5595  
5596          status = decode_op_hdr(xdr, OP_OPEN);
5597 @@ -2737,11 +3022,9 @@ static int decode_open(struct xdr_stream
5598          if (bmlen > 10)
5599                  goto xdr_error;
5600  
5601 -        READ_BUF((bmlen << 2) + 4);
5602 +        READ_BUF(bmlen << 2);
5603          p += bmlen;
5604 -        READ32(delegation_type);
5605 -        if (delegation_type == NFS4_OPEN_DELEGATE_NONE)
5606 -               return 0;
5607 +       return decode_delegation(xdr, res);
5608  xdr_error:
5609         printk(KERN_NOTICE "%s: xdr error!\n", __FUNCTION__);
5610         return -EIO;
5611 @@ -2967,6 +3250,72 @@ static int decode_renew(struct xdr_strea
5612         return decode_op_hdr(xdr, OP_RENEW);
5613  }
5614  
5615 +static int decode_attr_acl(struct xdr_stream *xdr, uint32_t *bitmap,
5616 +                               struct nfs_getaclres *res)
5617 +{
5618 +       uint32_t *p;
5619 +
5620 +       if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
5621 +               return -EIO;
5622 +       if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
5623 +               ssize_t size = res->acl_len;
5624 +               uint32_t nace, tmp;
5625 +               u32 *start;
5626 +               int i;
5627 +
5628 +               res->acl_len = 0;
5629 +               READ_BUF(4);
5630 +               start = p;
5631 +               READ32(nace);
5632 +               res->acl_len += 4;
5633 +
5634 +               for (i = 0; i < nace; i++) {
5635 +                       READ_BUF(4*4);
5636 +                       res->acl_len += 4*4;
5637 +                       p += 3;
5638 +                       READ32(tmp); /* namelen */
5639 +                       READ_BUF(tmp);
5640 +                       if (tmp > XDR_MAX_NETOBJ) {
5641 +                               printk(KERN_WARNING "%s: name too long (%u)!\n",
5642 +                                       __FUNCTION__, tmp);
5643 +                               return -EIO;
5644 +                       }
5645 +                       res->acl_len += XDR_QUADLEN(tmp) << 2;
5646 +               }
5647 +               if (size && res->acl_len > size)
5648 +                       return -ERANGE;
5649 +               if (size == 0 && res->acl_len <= XATTR_SIZE_MAX)
5650 +                       res->acl = kmalloc(res->acl_len, GFP_KERNEL);
5651 +               if (res->acl)
5652 +                       memcpy(res->acl, start, res->acl_len);
5653 +       }
5654 +       return 0;
5655 +}
5656 +
5657 +static int decode_getacl(struct xdr_stream *xdr, struct nfs_getaclres *res)
5658 +{
5659 +       uint32_t *savep;
5660 +       uint32_t attrlen,
5661 +                bitmap[2] = {0};
5662 +       int status;
5663 +
5664 +       if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
5665 +               goto xdr_error;
5666 +       if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
5667 +               goto xdr_error;
5668 +       if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
5669 +               goto xdr_error;
5670 +
5671 +       if ((status = decode_attr_acl(xdr, bitmap, res)) != 0)
5672 +               goto xdr_error;
5673 +
5674 +       status = verify_attr_len(xdr, savep, attrlen);
5675 +xdr_error:
5676 +       if (status != 0)
5677 +               printk(KERN_NOTICE "%s: xdr error %d!\n", __FUNCTION__, -status);
5678 +       return status;
5679 +}
5680 +
5681  static int
5682  decode_savefh(struct xdr_stream *xdr)
5683  {
5684 @@ -3048,6 +3397,11 @@ static int decode_write(struct xdr_strea
5685         return 0;
5686  }
5687  
5688 +static int decode_delegreturn(struct xdr_stream *xdr)
5689 +{
5690 +       return decode_op_hdr(xdr, OP_DELEGRETURN);
5691 +}
5692 +
5693  /*
5694   * Decode OPEN_DOWNGRADE response
5695   */
5696 @@ -3222,6 +3576,14 @@ out:
5697  }
5698  
5699  /*
5700 + * Decode SYMLINK response
5701 + */
5702 +static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
5703 +{
5704 +       return nfs4_xdr_dec_create(rqstp, p, res);
5705 +}
5706 +
5707 +/*
5708   * Decode GETATTR response
5709   */
5710  static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res)
5711 @@ -3243,6 +3605,50 @@ out:
5712  
5713  }
5714  
5715 +/*
5716 + * Decode SETACL response
5717 + */
5718 +static int
5719 +nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res)
5720 +{
5721 +       struct xdr_stream xdr;
5722 +       struct compound_hdr hdr;
5723 +       int status;
5724 +
5725 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
5726 +       status = decode_compound_hdr(&xdr, &hdr);
5727 +       if (status)
5728 +               goto out;
5729 +       status = decode_putfh(&xdr);
5730 +       if (status)
5731 +               goto out;
5732 +       status = decode_setattr(&xdr, res);
5733 +out:
5734 +       return status;
5735 +}
5736 +
5737 +/*
5738 + * Decode GETACL response
5739 + */
5740 +static int
5741 +nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_getaclres *res)
5742 +{
5743 +       struct xdr_stream xdr;
5744 +       struct compound_hdr hdr;
5745 +       int status;
5746 +
5747 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
5748 +       status = decode_compound_hdr(&xdr, &hdr);
5749 +       if (status)
5750 +               goto out;
5751 +       status = decode_putfh(&xdr);
5752 +       if (status)
5753 +               goto out;
5754 +       status = decode_getacl(&xdr, res);
5755 +
5756 +out:
5757 +       return status;
5758 +}
5759  
5760  /*
5761   * Decode CLOSE response
5762 @@ -3314,9 +3720,9 @@ out:
5763  }
5764  
5765  /*
5766 - * Decode OPEN_RECLAIM response
5767 + * Decode OPEN response
5768   */
5769 -static int nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
5770 +static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
5771  {
5772          struct xdr_stream xdr;
5773          struct compound_hdr hdr;
5774 @@ -3330,9 +3736,6 @@ static int nfs4_xdr_dec_open_reclaim(str
5775          if (status)
5776                  goto out;
5777          status = decode_open(&xdr, res);
5778 -        if (status)
5779 -                goto out;
5780 -       status = decode_getfattr(&xdr, res->f_attr, res->server);
5781  out:
5782          return status;
5783  }
5784 @@ -3665,6 +4068,25 @@ static int nfs4_xdr_dec_setclientid_conf
5785         return status;
5786  }
5787  
5788 +/*
5789 + * DELEGRETURN request
5790 + */
5791 +static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
5792 +{
5793 +       struct xdr_stream xdr;
5794 +       struct compound_hdr hdr;
5795 +       int status;
5796 +
5797 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
5798 +       status = decode_compound_hdr(&xdr, &hdr);
5799 +       if (status == 0) {
5800 +               status = decode_putfh(&xdr);
5801 +               if (status == 0)
5802 +                       status = decode_delegreturn(&xdr);
5803 +       }
5804 +       return status;
5805 +}
5806 +
5807  uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
5808  {
5809         uint32_t len;
5810 @@ -3756,7 +4178,7 @@ nfs_stat_to_errno(int stat)
5811                 if (nfs_errtbl[i].stat == stat)
5812                         return nfs_errtbl[i].errno;
5813         }
5814 -       if (stat < 0) {
5815 +       if (stat <= 10000 || stat > 10100) {
5816                 /* The server is looney tunes. */
5817                 return ESERVERFAULT;
5818         }
5819 @@ -3786,7 +4208,7 @@ struct rpc_procinfo       nfs4_procedures[] = 
5820    PROC(COMMIT,         enc_commit,     dec_commit),
5821    PROC(OPEN,           enc_open,       dec_open),
5822    PROC(OPEN_CONFIRM,   enc_open_confirm,       dec_open_confirm),
5823 -  PROC(OPEN_RECLAIM,   enc_open_reclaim,       dec_open_reclaim),
5824 +  PROC(OPEN_NOATTR,    enc_open_noattr,        dec_open_noattr),
5825    PROC(OPEN_DOWNGRADE, enc_open_downgrade,     dec_open_downgrade),
5826    PROC(CLOSE,          enc_close,      dec_close),
5827    PROC(SETATTR,                enc_setattr,    dec_setattr),
5828 @@ -3804,12 +4226,16 @@ struct rpc_procinfo     nfs4_procedures[] = 
5829    PROC(REMOVE,         enc_remove,     dec_remove),
5830    PROC(RENAME,         enc_rename,     dec_rename),
5831    PROC(LINK,           enc_link,       dec_link),
5832 +  PROC(SYMLINK,                enc_symlink,    dec_symlink),
5833    PROC(CREATE,         enc_create,     dec_create),
5834    PROC(PATHCONF,       enc_pathconf,   dec_pathconf),
5835    PROC(STATFS,         enc_statfs,     dec_statfs),
5836    PROC(READLINK,       enc_readlink,   dec_readlink),
5837    PROC(READDIR,                enc_readdir,    dec_readdir),
5838    PROC(SERVER_CAPS,    enc_server_caps, dec_server_caps),
5839 +  PROC(DELEGRETURN,    enc_delegreturn, dec_delegreturn),
5840 +  PROC(GETACL,         enc_getacl,     dec_getacl),
5841 +  PROC(SETACL,         enc_setacl,     dec_setacl),
5842  };
5843  
5844  struct rpc_version             nfs_version4 = {
5845 --- linux-2.6.7/fs/nfs/pagelist.c.lsec  2004-06-15 23:20:03.000000000 -0600
5846 +++ linux-2.6.7/fs/nfs/pagelist.c       2005-03-23 14:28:23.057544416 -0700
5847 @@ -36,7 +36,6 @@ nfs_page_alloc(void)
5848         if (p) {
5849                 memset(p, 0, sizeof(*p));
5850                 INIT_LIST_HEAD(&p->wb_list);
5851 -               init_waitqueue_head(&p->wb_wait);
5852         }
5853         return p;
5854  }
5855 @@ -62,7 +61,7 @@ nfs_page_free(struct nfs_page *p)
5856   * User should ensure it is safe to sleep in this function.
5857   */
5858  struct nfs_page *
5859 -nfs_create_request(struct file *file, struct inode *inode,
5860 +nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
5861                    struct page *page,
5862                    unsigned int offset, unsigned int count)
5863  {
5864 @@ -94,33 +93,38 @@ nfs_create_request(struct file *file, st
5865         req->wb_offset  = offset;
5866         req->wb_pgbase  = offset;
5867         req->wb_bytes   = count;
5868 -       req->wb_inode   = inode;
5869         req->wb_count   = 1;
5870 -       server->rpc_ops->request_init(req, file);
5871 +       req->wb_context = get_nfs_open_context(ctx);
5872  
5873         return req;
5874  }
5875  
5876  /**
5877 + * nfs_unlock_request - Unlock request and wake up sleepers.
5878 + * @req:
5879 + */
5880 +void nfs_unlock_request(struct nfs_page *req)
5881 +{
5882 +       if (!NFS_WBACK_BUSY(req)) {
5883 +               printk(KERN_ERR "NFS: Invalid unlock attempted\n");
5884 +               BUG();
5885 +       }
5886 +       smp_mb__before_clear_bit();
5887 +       clear_bit(PG_BUSY, &req->wb_flags);
5888 +       smp_mb__after_clear_bit();
5889 +       wake_up_all(&req->wb_context->waitq);
5890 +       nfs_release_request(req);
5891 +}
5892 +
5893 +/**
5894   * nfs_clear_request - Free up all resources allocated to the request
5895   * @req:
5896   *
5897 - * Release all resources associated with a write request after it
5898 + * Release page resources associated with a write request after it
5899   * has completed.
5900   */
5901  void nfs_clear_request(struct nfs_page *req)
5902  {
5903 -       if (req->wb_state)
5904 -               req->wb_state = NULL;
5905 -       /* Release struct file or cached credential */
5906 -       if (req->wb_file) {
5907 -               fput(req->wb_file);
5908 -               req->wb_file = NULL;
5909 -       }
5910 -       if (req->wb_cred) {
5911 -               put_rpccred(req->wb_cred);
5912 -               req->wb_cred = NULL;
5913 -       }
5914         if (req->wb_page) {
5915                 page_cache_release(req->wb_page);
5916                 req->wb_page = NULL;
5917 @@ -151,6 +155,7 @@ nfs_release_request(struct nfs_page *req
5918  
5919         /* Release struct file or cached credential */
5920         nfs_clear_request(req);
5921 +       put_nfs_open_context(req->wb_context);
5922         nfs_page_free(req);
5923  }
5924  
5925 @@ -194,12 +199,12 @@ nfs_list_add_request(struct nfs_page *re
5926  int
5927  nfs_wait_on_request(struct nfs_page *req)
5928  {
5929 -       struct inode    *inode = req->wb_inode;
5930 +       struct inode    *inode = req->wb_context->dentry->d_inode;
5931          struct rpc_clnt        *clnt = NFS_CLIENT(inode);
5932  
5933         if (!NFS_WBACK_BUSY(req))
5934                 return 0;
5935 -       return nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req));
5936 +       return nfs_wait_event(clnt, req->wb_context->waitq, !NFS_WBACK_BUSY(req));
5937  }
5938  
5939  /**
5940 @@ -224,7 +229,11 @@ nfs_coalesce_requests(struct list_head *
5941  
5942                 req = nfs_list_entry(head->next);
5943                 if (prev) {
5944 -                       if (req->wb_cred != prev->wb_cred)
5945 +                       if (req->wb_context->cred != prev->wb_context->cred)
5946 +                               break;
5947 +                       if (req->wb_context->pid != prev->wb_context->pid)
5948 +                               break;
5949 +                       if (req->wb_context->state != prev->wb_context->state)
5950                                 break;
5951                         if (req->wb_index != (prev->wb_index + 1))
5952                                 break;
5953 --- linux-2.6.7/fs/nfs/nfs4proc.c.lsec  2004-06-15 23:19:44.000000000 -0600
5954 +++ linux-2.6.7/fs/nfs/nfs4proc.c       2005-03-23 14:32:35.532162440 -0700
5955 @@ -47,12 +47,16 @@
5956  #include <linux/smp_lock.h>
5957  #include <linux/namei.h>
5958  
5959 +#include "delegation.h"
5960 +
5961  #define NFSDBG_FACILITY                NFSDBG_PROC
5962  
5963 -#define NFS4_POLL_RETRY_TIME   (15*HZ)
5964 +#define NFS4_POLL_RETRY_MIN    (1*HZ)
5965 +#define NFS4_POLL_RETRY_MAX    (15*HZ)
5966  
5967  static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
5968  static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *);
5969 +static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry);
5970  extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
5971  extern struct rpc_procinfo nfs4_procedures[];
5972  
5973 @@ -189,53 +193,296 @@ static void update_changeattr(struct ino
5974   *     reclaim state on the server after a reboot.
5975   *     Assumes caller is holding the sp->so_sem
5976   */
5977 -int
5978 -nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
5979 +static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
5980  {
5981         struct inode *inode = state->inode;
5982         struct nfs_server *server = NFS_SERVER(inode);
5983 -       struct nfs_fattr fattr = {
5984 -               .valid = 0,
5985 -       };
5986 -       struct nfs_open_reclaimargs o_arg = {
5987 +       struct nfs_delegation *delegation = NFS_I(inode)->delegation;
5988 +       struct nfs_openargs o_arg = {
5989                 .fh = NFS_FH(inode),
5990                 .seqid = sp->so_seqid,
5991                 .id = sp->so_id,
5992 -               .share_access = state->state,
5993 +               .open_flags = state->state,
5994                 .clientid = server->nfs4_state->cl_clientid,
5995                 .claim = NFS4_OPEN_CLAIM_PREVIOUS,
5996                 .bitmask = server->attr_bitmask,
5997         };
5998         struct nfs_openres o_res = {
5999 -               .f_attr = &fattr,
6000                 .server = server,       /* Grrr */
6001         };
6002         struct rpc_message msg = {
6003 -               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_OPEN_RECLAIM],
6004 +               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR],
6005                 .rpc_argp       = &o_arg,
6006                 .rpc_resp       = &o_res,
6007                 .rpc_cred       = sp->so_cred,
6008         };
6009         int status;
6010  
6011 +       if (delegation != NULL) {
6012 +               if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) {
6013 +                       memcpy(&state->stateid, &delegation->stateid,
6014 +                                       sizeof(state->stateid));
6015 +                       set_bit(NFS_DELEGATED_STATE, &state->flags);
6016 +                       return 0;
6017 +               }
6018 +               o_arg.u.delegation_type = delegation->type;
6019 +       }
6020         status = rpc_call_sync(server->client, &msg, 0);
6021         nfs4_increment_seqid(status, sp);
6022 -       if (status == 0)
6023 +       if (status == 0) {
6024                 memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
6025 -       /* Update the inode attributes */
6026 -       nfs_refresh_inode(inode, &fattr);
6027 +               if (o_res.delegation_type != 0) {
6028 +                       nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res);
6029 +                       /* Did the server issue an immediate delegation recall? */
6030 +                       if (o_res.do_recall)
6031 +                               nfs_async_inode_return_delegation(inode, &o_res.stateid);
6032 +               }
6033 +       }
6034 +       clear_bit(NFS_DELEGATED_STATE, &state->flags);
6035 +       /* Ensure we update the inode attributes */
6036 +       NFS_CACHEINV(inode);
6037         return status;
6038  }
6039  
6040 +int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
6041 +{
6042 +       struct nfs_server *server = NFS_SERVER(state->inode);
6043 +       struct nfs4_exception exception = { };
6044 +       int err;
6045 +       do {
6046 +               err = _nfs4_open_reclaim(sp, state);
6047 +               switch (err) {
6048 +                       case 0:
6049 +                       case -NFS4ERR_STALE_CLIENTID:
6050 +                       case -NFS4ERR_STALE_STATEID:
6051 +                       case -NFS4ERR_EXPIRED:
6052 +                               return err;
6053 +               }
6054 +               err = nfs4_handle_exception(server, err, &exception);
6055 +       } while (exception.retry);
6056 +       return err;
6057 +}
6058 +
6059 +static int _nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
6060 +{
6061 +       struct nfs4_state_owner  *sp  = state->owner;
6062 +       struct inode *inode = dentry->d_inode;
6063 +       struct nfs_server *server = NFS_SERVER(inode);
6064 +       struct dentry *parent = dget_parent(dentry);
6065 +       struct nfs_openargs arg = {
6066 +               .fh = NFS_FH(parent->d_inode),
6067 +               .clientid = server->nfs4_state->cl_clientid,
6068 +               .name = &dentry->d_name,
6069 +               .id = sp->so_id,
6070 +               .server = server,
6071 +               .bitmask = server->attr_bitmask,
6072 +               .claim = NFS4_OPEN_CLAIM_DELEGATE_CUR,
6073 +       };
6074 +       struct nfs_openres res = {
6075 +               .server = server,
6076 +       };
6077 +       struct  rpc_message msg = {
6078 +               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR],
6079 +               .rpc_argp       = &arg,
6080 +               .rpc_resp       = &res,
6081 +               .rpc_cred       = sp->so_cred,
6082 +       };
6083 +       int status = 0;
6084 +
6085 +       down(&sp->so_sema);
6086 +       if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
6087 +               goto out;
6088 +       if (state->state == 0)
6089 +               goto out;
6090 +       arg.seqid = sp->so_seqid;
6091 +       arg.open_flags = state->state;
6092 +       memcpy(arg.u.delegation.data, state->stateid.data, sizeof(arg.u.delegation.data));
6093 +       status = rpc_call_sync(server->client, &msg, 0);
6094 +       nfs4_increment_seqid(status, sp);
6095 +       if (status >= 0) {
6096 +               memcpy(state->stateid.data, res.stateid.data,
6097 +                               sizeof(state->stateid.data));
6098 +               clear_bit(NFS_DELEGATED_STATE, &state->flags);
6099 +       }
6100 +out:
6101 +       up(&sp->so_sema);
6102 +       dput(parent);
6103 +       return status;
6104 +}
6105 +
6106 +int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state)
6107 +{
6108 +       struct nfs4_exception exception = { };
6109 +       struct nfs_server *server = NFS_SERVER(dentry->d_inode);
6110 +       int err;
6111 +       do {
6112 +               err = _nfs4_open_delegation_recall(dentry, state);
6113 +               switch (err) {
6114 +                       case 0:
6115 +                               return err;
6116 +                       case -NFS4ERR_STALE_CLIENTID:
6117 +                       case -NFS4ERR_STALE_STATEID:
6118 +                       case -NFS4ERR_EXPIRED:
6119 +                               /* Don't recall a delegation if it was lost */
6120 +                               nfs4_schedule_state_recovery(server->nfs4_state);
6121 +                               return err;
6122 +               }
6123 +               err = nfs4_handle_exception(server, err, &exception);
6124 +       } while (exception.retry);
6125 +       return err;
6126 +}
6127 +
6128 +static int _nfs4_proc_open_confirm(struct rpc_clnt *clnt, const struct nfs_fh *fh, struct nfs4_state_owner *sp, nfs4_stateid *stateid)
6129 +{
6130 +       struct nfs_open_confirmargs arg = {
6131 +               .fh             = fh,
6132 +               .seqid          = sp->so_seqid,
6133 +               .stateid        = *stateid,
6134 +       };
6135 +       struct nfs_open_confirmres res;
6136 +       struct  rpc_message msg = {
6137 +               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM],
6138 +               .rpc_argp       = &arg,
6139 +               .rpc_resp       = &res,
6140 +               .rpc_cred       = sp->so_cred,
6141 +       };
6142 +       int status;
6143 +
6144 +       status = rpc_call_sync(clnt, &msg, 0);
6145 +       nfs4_increment_seqid(status, sp);
6146 +       if (status >= 0)
6147 +               memcpy(stateid, &res.stateid, sizeof(*stateid));
6148 +       return status;
6149 +}
6150 +
6151 +static int _nfs4_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
6152 +{
6153 +       struct nfs_access_entry cache;
6154 +       int status;
6155 +
6156 +       status = nfs_access_get_cached(inode, cred, &cache);
6157 +       if (status == 0)
6158 +               goto out;
6159 +
6160 +       /* Be clever: ask server to check for all possible rights */
6161 +       cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;
6162 +       cache.cred = cred;
6163 +       cache.jiffies = jiffies;
6164 +       status = _nfs4_proc_access(inode, &cache);
6165 +       if (status != 0)
6166 +               return status;
6167 +       nfs_access_add_cache(inode, &cache);
6168 +out:
6169 +       if ((cache.mask & mask) == mask)
6170 +               return 0;
6171 +       return -EACCES;
6172 +}
6173 +
6174 +/*
6175 + * Returns an nfs4_state + an extra reference to the inode
6176 + */
6177 +int _nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred, struct nfs4_state **res)
6178 +{
6179 +       struct nfs_delegation *delegation;
6180 +       struct nfs_server *server = NFS_SERVER(inode);
6181 +       struct nfs4_client *clp = server->nfs4_state;
6182 +       struct nfs_inode *nfsi = NFS_I(inode);
6183 +       struct nfs4_state_owner *sp = NULL;
6184 +       struct nfs4_state *state = NULL;
6185 +       int open_flags = flags & (FMODE_READ|FMODE_WRITE);
6186 +       int mask = 0;
6187 +       int err;
6188 +
6189 +       /* Protect against reboot recovery - NOTE ORDER! */
6190 +       down_read(&clp->cl_sem);
6191 +       /* Protect against delegation recall */
6192 +       down_read(&nfsi->rwsem);
6193 +       delegation = NFS_I(inode)->delegation;
6194 +       err = -ENOENT;
6195 +       if (delegation == NULL || (delegation->type & open_flags) != open_flags)
6196 +               goto out_err;
6197 +       err = -ENOMEM;
6198 +       if (!(sp = nfs4_get_state_owner(server, cred))) {
6199 +               dprintk("%s: nfs4_get_state_owner failed!\n", __FUNCTION__);
6200 +               goto out_err;
6201 +       }
6202 +       down(&sp->so_sema);
6203 +       state = nfs4_get_open_state(inode, sp);
6204 +       if (state == NULL)
6205 +               goto out_err;
6206 +
6207 +       err = -ENOENT;
6208 +       if ((state->state & open_flags) == open_flags) {
6209 +               spin_lock(&inode->i_lock);
6210 +               if (open_flags & FMODE_READ)
6211 +                       state->nreaders++;
6212 +               if (open_flags & FMODE_WRITE)
6213 +                       state->nwriters++;
6214 +               spin_unlock(&inode->i_lock);
6215 +               goto out_ok;
6216 +       } else if (state->state != 0)
6217 +               goto out_err;
6218 +
6219 +       lock_kernel();
6220 +       err = _nfs4_do_access(inode, cred, mask);
6221 +       unlock_kernel();
6222 +       if (err != 0)
6223 +               goto out_err;
6224 +       spin_lock(&inode->i_lock);
6225 +       memcpy(state->stateid.data, delegation->stateid.data,
6226 +                       sizeof(state->stateid.data));
6227 +       state->state |= open_flags;
6228 +       if (open_flags & FMODE_READ)
6229 +               state->nreaders++;
6230 +       if (open_flags & FMODE_WRITE)
6231 +               state->nwriters++;
6232 +       set_bit(NFS_DELEGATED_STATE, &state->flags);
6233 +       spin_unlock(&inode->i_lock);
6234 +out_ok:
6235 +       up(&sp->so_sema);
6236 +       nfs4_put_state_owner(sp);
6237 +       up_read(&nfsi->rwsem);
6238 +       up_read(&clp->cl_sem);
6239 +       igrab(inode);
6240 +       *res = state;
6241 +       return 0; 
6242 +out_err:
6243 +       if (sp != NULL) {
6244 +               if (state != NULL)
6245 +                       nfs4_put_open_state(state);
6246 +               up(&sp->so_sema);
6247 +               nfs4_put_state_owner(sp);
6248 +       }
6249 +       up_read(&nfsi->rwsem);
6250 +       up_read(&clp->cl_sem);
6251 +       return err;
6252 +}
6253 +
6254 +static struct nfs4_state *nfs4_open_delegated(struct inode *inode, int flags, struct rpc_cred *cred)
6255 +{
6256 +       struct nfs4_exception exception = { };
6257 +       struct nfs4_state *res;
6258 +       int err;
6259 +
6260 +       do {
6261 +               err = _nfs4_open_delegated(inode, flags, cred, &res);
6262 +               if (err == 0)
6263 +                       break;
6264 +               res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(inode),
6265 +                                       err, &exception));
6266 +       } while (exception.retry);
6267 +       return res;
6268 +}
6269 +
6270  /*
6271   * Returns an nfs4_state + an referenced inode
6272   */
6273 -struct nfs4_state *
6274 -nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred)
6275 +static int _nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred, struct nfs4_state **res)
6276  {
6277         struct nfs4_state_owner  *sp;
6278         struct nfs4_state     *state = NULL;
6279         struct nfs_server       *server = NFS_SERVER(dir);
6280 +       struct nfs4_client *clp = server->nfs4_state;
6281         struct inode *inode = NULL;
6282         int                     status;
6283         struct nfs_fattr        f_attr = {
6284 @@ -243,12 +490,11 @@ nfs4_do_open(struct inode *dir, struct q
6285         };
6286         struct nfs_openargs o_arg = {
6287                 .fh             = NFS_FH(dir),
6288 -               .share_access   = flags & (FMODE_READ|FMODE_WRITE),
6289 -               .opentype       = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE,
6290 -               .createmode     = (flags & O_EXCL) ? NFS4_CREATE_EXCLUSIVE : NFS4_CREATE_UNCHECKED,
6291 +               .open_flags     = flags,
6292                 .name           = name,
6293                 .server         = server,
6294                 .bitmask = server->attr_bitmask,
6295 +               .claim = NFS4_OPEN_CLAIM_NULL,
6296         };
6297         struct nfs_openres o_res = {
6298                 .f_attr         = &f_attr,
6299 @@ -261,60 +507,44 @@ nfs4_do_open(struct inode *dir, struct q
6300                 .rpc_cred       = cred,
6301         };
6302  
6303 -retry:
6304 +       /* Protect against reboot recovery conflicts */
6305 +       down_read(&clp->cl_sem);
6306         status = -ENOMEM;
6307 -       if (!(sp = nfs4_get_state_owner(NFS_SERVER(dir), cred))) {
6308 +       if (!(sp = nfs4_get_state_owner(server, cred))) {
6309                 dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n");
6310 -               goto out;
6311 +               goto out_err;
6312         }
6313 -       if (o_arg.createmode & NFS4_CREATE_EXCLUSIVE){
6314 +       if (flags & O_EXCL) {
6315                 u32 *p = (u32 *) o_arg.u.verifier.data;
6316                 p[0] = jiffies;
6317                 p[1] = current->pid;
6318 -       } else if (o_arg.createmode == NFS4_CREATE_UNCHECKED) {
6319 +       } else
6320                 o_arg.u.attrs = sattr;
6321 -       }
6322         /* Serialization for the sequence id */
6323         down(&sp->so_sema);
6324         o_arg.seqid = sp->so_seqid;
6325         o_arg.id = sp->so_id;
6326 -       o_arg.clientid = NFS_SERVER(dir)->nfs4_state->cl_clientid,
6327 +       o_arg.clientid = clp->cl_clientid;
6328  
6329         status = rpc_call_sync(server->client, &msg, 0);
6330         nfs4_increment_seqid(status, sp);
6331         if (status)
6332 -               goto out_up;
6333 +               goto out_err;
6334         update_changeattr(dir, &o_res.cinfo);
6335 +       if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) {
6336 +               status = _nfs4_proc_open_confirm(server->client, &o_res.fh, sp, &o_res.stateid);
6337 +               if (status)
6338 +                       goto out_err;
6339 +       }
6340  
6341         status = -ENOMEM;
6342         inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr);
6343         if (!inode)
6344 -               goto out_up;
6345 +               goto out_err;
6346         state = nfs4_get_open_state(inode, sp);
6347         if (!state)
6348 -               goto out_up;
6349 -
6350 -       if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) {
6351 -               struct nfs_open_confirmargs oc_arg = {
6352 -                       .fh             = &o_res.fh,
6353 -                       .seqid          = sp->so_seqid,
6354 -               };
6355 -               struct nfs_open_confirmres oc_res;
6356 -               struct  rpc_message msg = {
6357 -                       .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM],
6358 -                       .rpc_argp       = &oc_arg,
6359 -                       .rpc_resp       = &oc_res,
6360 -                       .rpc_cred       = cred,
6361 -               };
6362 -
6363 -               memcpy(&oc_arg.stateid, &o_res.stateid, sizeof(oc_arg.stateid));
6364 -               status = rpc_call_sync(server->client, &msg, 0);
6365 -               nfs4_increment_seqid(status, sp);
6366 -               if (status)
6367 -                       goto out_up;
6368 -               memcpy(&state->stateid, &oc_res.stateid, sizeof(state->stateid));
6369 -       } else
6370 -               memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
6371 +               goto out_err;
6372 +       memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
6373         spin_lock(&inode->i_lock);
6374         if (flags & FMODE_READ)
6375                 state->nreaders++;
6376 @@ -322,47 +552,62 @@ retry:
6377                 state->nwriters++;
6378         state->state |= flags & (FMODE_READ|FMODE_WRITE);
6379         spin_unlock(&inode->i_lock);
6380 -
6381 +       if (o_res.delegation_type != 0)
6382 +               nfs_inode_set_delegation(inode, cred, &o_res);
6383         up(&sp->so_sema);
6384         nfs4_put_state_owner(sp);
6385 -       return state;
6386 -
6387 -out_up:
6388 -       up(&sp->so_sema);
6389 -       nfs4_put_state_owner(sp);
6390 -       if (state) {
6391 -               nfs4_put_open_state(state);
6392 -               state = NULL;
6393 -       }
6394 -       if (inode) {
6395 +       up_read(&clp->cl_sem);
6396 +       *res = state;
6397 +       return 0;
6398 +out_err:
6399 +       if (sp != NULL) {
6400 +               if (state != NULL)
6401 +                       nfs4_put_open_state(state);
6402 +               up(&sp->so_sema);
6403 +               nfs4_put_state_owner(sp);
6404 +       }
6405 +       /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */
6406 +       up_read(&clp->cl_sem);
6407 +       if (inode != NULL)
6408                 iput(inode);
6409 -               inode = NULL;
6410 -       }
6411 -       /* NOTE: BAD_SEQID means the server and client disagree about the
6412 -        * book-keeping w.r.t. state-changing operations
6413 -        * (OPEN/CLOSE/LOCK/LOCKU...)
6414 -        * It is actually a sign of a bug on the client or on the server.
6415 -        *
6416 -        * If we receive a BAD_SEQID error in the particular case of
6417 -        * doing an OPEN, we assume that nfs4_increment_seqid() will
6418 -        * have unhashed the old state_owner for us, and that we can
6419 -        * therefore safely retry using a new one. We should still warn
6420 -        * the user though...
6421 -        */
6422 -       if (status == -NFS4ERR_BAD_SEQID) {
6423 -               printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n");
6424 -               goto retry;
6425 -       }
6426 -       status = nfs4_handle_error(server, status);
6427 -       if (!status)
6428 -               goto retry;
6429 -       BUG_ON(status < -1000 || status > 0);
6430 -out:
6431 -       return ERR_PTR(status);
6432 +       *res = NULL;
6433 +       return status;
6434  }
6435  
6436 -int
6437 -nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
6438 +
6439 +struct nfs4_state *nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred)
6440 +{
6441 +       struct nfs4_exception exception = { };
6442 +       struct nfs4_state *res;
6443 +       int status;
6444 +
6445 +       do {
6446 +               status = _nfs4_do_open(dir, name, flags, sattr, cred, &res);
6447 +               if (status == 0)
6448 +                       break;
6449 +               /* NOTE: BAD_SEQID means the server and client disagree about the
6450 +                * book-keeping w.r.t. state-changing operations
6451 +                * (OPEN/CLOSE/LOCK/LOCKU...)
6452 +                * It is actually a sign of a bug on the client or on the server.
6453 +                *
6454 +                * If we receive a BAD_SEQID error in the particular case of
6455 +                * doing an OPEN, we assume that nfs4_increment_seqid() will
6456 +                * have unhashed the old state_owner for us, and that we can
6457 +                * therefore safely retry using a new one. We should still warn
6458 +                * the user though...
6459 +                */
6460 +               if (status == -NFS4ERR_BAD_SEQID) {
6461 +                       printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n");
6462 +                       exception.retry = 1;
6463 +                       continue;
6464 +               }
6465 +               res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir),
6466 +                                       status, &exception));
6467 +       } while (exception.retry);
6468 +       return res;
6469 +}
6470 +
6471 +static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
6472                  struct nfs_fh *fhandle, struct iattr *sattr,
6473                  struct nfs4_state *state)
6474  {
6475 @@ -381,9 +626,7 @@ nfs4_do_setattr(struct nfs_server *serve
6476                  .rpc_argp       = &arg,
6477                  .rpc_resp       = &res,
6478          };
6479 -       int status;
6480  
6481 -retry:
6482          fattr->valid = 0;
6483  
6484         if (sattr->ia_valid & ATTR_SIZE)
6485 @@ -391,13 +634,22 @@ retry:
6486         else
6487                 memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
6488  
6489 -       status = rpc_call_sync(server->client, &msg, 0);
6490 -       if (status) {
6491 -               status = nfs4_handle_error(server, status);
6492 -               if (!status)
6493 -                       goto retry;
6494 -       }
6495 -       return status;
6496 +       return rpc_call_sync(server->client, &msg, 0);
6497 +}
6498 +
6499 +int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
6500 +                struct nfs_fh *fhandle, struct iattr *sattr,
6501 +                struct nfs4_state *state)
6502 +{
6503 +       struct nfs4_exception exception = { };
6504 +       int err;
6505 +       do {
6506 +               err = nfs4_handle_exception(server,
6507 +                               _nfs4_do_setattr(server, fattr, fhandle, sattr,
6508 +                                       state),
6509 +                               &exception);
6510 +       } while (exception.retry);
6511 +       return err;
6512  }
6513  
6514  /* 
6515 @@ -411,8 +663,7 @@ retry:
6516   *
6517   * NOTE: Caller must be holding the sp->so_owner semaphore!
6518   */
6519 -int
6520 -nfs4_do_close(struct inode *inode, struct nfs4_state *state) 
6521 +static int _nfs4_do_close(struct inode *inode, struct nfs4_state *state) 
6522  {
6523         struct nfs4_state_owner *sp = state->owner;
6524         int status = 0;
6525 @@ -426,6 +677,8 @@ nfs4_do_close(struct inode *inode, struc
6526                 .rpc_resp       = &res,
6527         };
6528  
6529 +       if (test_bit(NFS_DELEGATED_STATE, &state->flags))
6530 +               return 0;
6531         memcpy(&arg.stateid, &state->stateid, sizeof(arg.stateid));
6532         /* Serialization for the sequence id */
6533         arg.seqid = sp->so_seqid,
6534 @@ -441,15 +694,34 @@ nfs4_do_close(struct inode *inode, struc
6535         return status;
6536  }
6537  
6538 -int
6539 -nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode) 
6540 +int nfs4_do_close(struct inode *inode, struct nfs4_state *state) 
6541 +{
6542 +       struct nfs_server *server = NFS_SERVER(state->inode);
6543 +       struct nfs4_exception exception = { };
6544 +       int err;
6545 +       do {
6546 +               err = _nfs4_do_close(inode, state);
6547 +               switch (err) {
6548 +                       case -NFS4ERR_STALE_STATEID:
6549 +                       case -NFS4ERR_EXPIRED:
6550 +                               nfs4_schedule_state_recovery(server->nfs4_state);
6551 +                       case 0:
6552 +                               state->state = 0;
6553 +                               return 0;
6554 +               }
6555 +               err = nfs4_handle_exception(server, err, &exception);
6556 +       } while (exception.retry);
6557 +       return err;
6558 +}
6559 +
6560 +static int _nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode) 
6561  {
6562         struct nfs4_state_owner *sp = state->owner;
6563         int status = 0;
6564         struct nfs_closeargs arg = {
6565                 .fh             = NFS_FH(inode),
6566                 .seqid          = sp->so_seqid,
6567 -               .share_access   = mode,
6568 +               .open_flags     = mode,
6569         };
6570         struct nfs_closeres res;
6571         struct rpc_message msg = {
6572 @@ -458,6 +730,8 @@ nfs4_do_downgrade(struct inode *inode, s
6573                 .rpc_resp       = &res,
6574         };
6575  
6576 +       if (test_bit(NFS_DELEGATED_STATE, &state->flags))
6577 +               return 0;
6578         memcpy(&arg.stateid, &state->stateid, sizeof(arg.stateid));
6579         status = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0);
6580         nfs4_increment_seqid(status, sp);
6581 @@ -467,6 +741,26 @@ nfs4_do_downgrade(struct inode *inode, s
6582         return status;
6583  }
6584  
6585 +int nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode) 
6586 +{
6587 +       struct nfs_server *server = NFS_SERVER(state->inode);
6588 +       struct nfs4_exception exception = { };
6589 +       int err;
6590 +       do {
6591 +               err = _nfs4_do_downgrade(inode, state, mode);
6592 +               switch (err) {
6593 +                       case -NFS4ERR_STALE_STATEID:
6594 +                       case -NFS4ERR_EXPIRED:
6595 +                               nfs4_schedule_state_recovery(server->nfs4_state);
6596 +                       case 0:
6597 +                               state->state = mode;
6598 +                               return 0;
6599 +               }
6600 +               err = nfs4_handle_exception(server, err, &exception);
6601 +       } while (exception.retry);
6602 +       return err;
6603 +}
6604 +
6605  struct inode *
6606  nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
6607  {
6608 @@ -500,7 +794,9 @@ nfs4_open_revalidate(struct inode *dir, 
6609         struct inode *inode;
6610  
6611         cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0);
6612 -       state = nfs4_do_open(dir, &dentry->d_name, openflags, NULL, cred);
6613 +       state = nfs4_open_delegated(dentry->d_inode, openflags, cred);
6614 +       if (IS_ERR(state))
6615 +               state = nfs4_do_open(dir, &dentry->d_name, openflags, NULL, cred);
6616         put_rpccred(cred);
6617         if (state == ERR_PTR(-ENOENT) && dentry->d_inode == 0)
6618                 return 1;
6619 @@ -518,7 +814,7 @@ nfs4_open_revalidate(struct inode *dir, 
6620  }
6621  
6622  
6623 -static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
6624 +static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
6625  {
6626         struct nfs4_server_caps_res res = {};
6627         struct rpc_message msg = {
6628 @@ -542,7 +838,19 @@ static int nfs4_server_capabilities(stru
6629         return status;
6630  }
6631  
6632 -static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
6633 +static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
6634 +{
6635 +       struct nfs4_exception exception = { };
6636 +       int err;
6637 +       do {
6638 +               err = nfs4_handle_exception(server,
6639 +                               _nfs4_server_capabilities(server, fhandle),
6640 +                               &exception);
6641 +       } while (exception.retry);
6642 +       return err;
6643 +}
6644 +
6645 +static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
6646                 struct nfs_fsinfo *info)
6647  {
6648         struct nfs_fattr *      fattr = info->fattr;
6649 @@ -563,6 +871,19 @@ static int nfs4_lookup_root(struct nfs_s
6650         return rpc_call_sync(server->client, &msg, 0);
6651  }
6652  
6653 +static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
6654 +               struct nfs_fsinfo *info)
6655 +{
6656 +       struct nfs4_exception exception = { };
6657 +       int err;
6658 +       do {
6659 +               err = nfs4_handle_exception(server,
6660 +                               _nfs4_lookup_root(server, fhandle, info),
6661 +                               &exception);
6662 +       } while (exception.retry);
6663 +       return err;
6664 +}
6665 +
6666  static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
6667                 struct nfs_fsinfo *info)
6668  {
6669 @@ -597,6 +918,8 @@ static int nfs4_proc_get_root(struct nfs
6670  
6671         p = server->mnt_path;
6672         for (;;) {
6673 +               struct nfs4_exception exception = { };
6674 +
6675                 while (*p == '/')
6676                         p++;
6677                 if (!*p)
6678 @@ -606,9 +929,13 @@ static int nfs4_proc_get_root(struct nfs
6679                         p++;
6680                 q.len = p - q.name;
6681  
6682 -               fattr->valid = 0;
6683 -               status = rpc_call_sync(server->client, &msg, 0);
6684 -               if (!status)
6685 +               do {
6686 +                       fattr->valid = 0;
6687 +                       status = nfs4_handle_exception(server,
6688 +                                       rpc_call_sync(server->client, &msg, 0),
6689 +                                       &exception);
6690 +               } while (exception.retry);
6691 +               if (status == 0)
6692                         continue;
6693                 if (status == -ENOENT) {
6694                         printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path);
6695 @@ -621,10 +948,10 @@ static int nfs4_proc_get_root(struct nfs
6696         if (status == 0)
6697                 status = nfs4_do_fsinfo(server, fhandle, info);
6698  out:
6699 -       return nfs4_map_errors(status);
6700 +       return status;
6701  }
6702  
6703 -static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
6704 +static int _nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
6705  {
6706         struct nfs_server *server = NFS_SERVER(inode);
6707         struct nfs4_getattr_arg args = {
6708 @@ -642,8 +969,19 @@ static int nfs4_proc_getattr(struct inod
6709         };
6710         
6711         fattr->valid = 0;
6712 +       return rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
6713 +}
6714  
6715 -       return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0));
6716 +static int nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
6717 +{
6718 +       struct nfs4_exception exception = { };
6719 +       int err;
6720 +       do {
6721 +               err = nfs4_handle_exception(NFS_SERVER(inode),
6722 +                               _nfs4_proc_getattr(inode, fattr),
6723 +                               &exception);
6724 +       } while (exception.retry);
6725 +       return err;
6726  }
6727  
6728  /* 
6729 @@ -678,9 +1016,13 @@ nfs4_proc_setattr(struct dentry *dentry,
6730         if (size_change) {
6731                 struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
6732                 state = nfs4_find_state(inode, cred, FMODE_WRITE);
6733 -               if (!state) {
6734 -                       state = nfs4_do_open(dentry->d_parent->d_inode, 
6735 -                               &dentry->d_name, FMODE_WRITE, NULL, cred);
6736 +               if (state == NULL) {
6737 +                       state = nfs4_open_delegated(dentry->d_inode,
6738 +                                       FMODE_WRITE, cred);
6739 +                       if (IS_ERR(state))
6740 +                               state = nfs4_do_open(dentry->d_parent->d_inode,
6741 +                                               &dentry->d_name, FMODE_WRITE,
6742 +                                               NULL, cred);
6743                         need_iput = 1;
6744                 }
6745                 put_rpccred(cred);
6746 @@ -705,7 +1047,7 @@ out:
6747         return status;
6748  }
6749  
6750 -static int nfs4_proc_lookup(struct inode *dir, struct qstr *name,
6751 +static int _nfs4_proc_lookup(struct inode *dir, struct qstr *name,
6752                 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
6753  {
6754         int                    status;
6755 @@ -731,12 +1073,23 @@ static int nfs4_proc_lookup(struct inode
6756         dprintk("NFS call  lookup %s\n", name->name);
6757         status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
6758         dprintk("NFS reply lookup: %d\n", status);
6759 -       return nfs4_map_errors(status);
6760 +       return status;
6761  }
6762  
6763 -static int nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
6764 +static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
6765 +{
6766 +       struct nfs4_exception exception = { };
6767 +       int err;
6768 +       do {
6769 +               err = nfs4_handle_exception(NFS_SERVER(dir),
6770 +                               _nfs4_proc_lookup(dir, name, fhandle, fattr),
6771 +                               &exception);
6772 +       } while (exception.retry);
6773 +       return err;
6774 +}
6775 +
6776 +static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
6777  {
6778 -       int                     status;
6779         struct nfs4_accessargs args = {
6780                 .fh = NFS_FH(inode),
6781         };
6782 @@ -745,8 +1098,10 @@ static int nfs4_proc_access(struct inode
6783                 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
6784                 .rpc_argp = &args,
6785                 .rpc_resp = &res,
6786 -               .rpc_cred = cred,
6787 +               .rpc_cred = entry->cred,
6788         };
6789 +       int mode = entry->mask;
6790 +       int status;
6791  
6792         /*
6793          * Determine which access bits we want to ask for...
6794 @@ -758,8 +1113,7 @@ static int nfs4_proc_access(struct inode
6795                         args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE;
6796                 if (mode & MAY_EXEC)
6797                         args.access |= NFS4_ACCESS_LOOKUP;
6798 -       }
6799 -       else {
6800 +       } else {
6801                 if (mode & MAY_WRITE)
6802                         args.access |= NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND;
6803                 if (mode & MAY_EXEC)
6804 @@ -767,13 +1121,27 @@ static int nfs4_proc_access(struct inode
6805         }
6806         status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
6807         if (!status) {
6808 -               if (args.access != res.supported) {
6809 -                       printk(KERN_NOTICE "NFS: server didn't support all access bits!\n");
6810 -                       status = -ENOTSUPP;
6811 -               } else if ((args.access & res.access) != args.access)
6812 -                       status = -EACCES;
6813 +               entry->mask = 0;
6814 +               if (res.access & NFS4_ACCESS_READ)
6815 +                       entry->mask |= MAY_READ;
6816 +               if (res.access & (NFS4_ACCESS_MODIFY | NFS4_ACCESS_EXTEND | NFS4_ACCESS_DELETE))
6817 +                       entry->mask |= MAY_WRITE;
6818 +               if (res.access & (NFS4_ACCESS_LOOKUP|NFS4_ACCESS_EXECUTE))
6819 +                       entry->mask |= MAY_EXEC;
6820         }
6821 -       return nfs4_map_errors(status);
6822 +       return status;
6823 +}
6824 +
6825 +static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
6826 +{
6827 +       struct nfs4_exception exception = { };
6828 +       int err;
6829 +       do {
6830 +               err = nfs4_handle_exception(NFS_SERVER(inode),
6831 +                               _nfs4_proc_access(inode, entry),
6832 +                               &exception);
6833 +       } while (exception.retry);
6834 +       return err;
6835  }
6836  
6837  /*
6838 @@ -800,7 +1168,7 @@ static int nfs4_proc_access(struct inode
6839   * Both of these changes to the XDR layer would in fact be quite
6840   * minor, but I decided to leave them for a subsequent patch.
6841   */
6842 -static int nfs4_proc_readlink(struct inode *inode, struct page *page)
6843 +static int _nfs4_proc_readlink(struct inode *inode, struct page *page)
6844  {
6845         struct nfs4_readlink args = {
6846                 .fh       = NFS_FH(inode),
6847 @@ -813,11 +1181,22 @@ static int nfs4_proc_readlink(struct ino
6848                 .rpc_resp = NULL,
6849         };
6850  
6851 -       return nfs4_map_errors(rpc_call_sync(NFS_CLIENT(inode), &msg, 0));
6852 +       return rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
6853  }
6854  
6855 -static int
6856 -nfs4_proc_read(struct nfs_read_data *rdata, struct file *filp)
6857 +static int nfs4_proc_readlink(struct inode *inode, struct page *page)
6858 +{
6859 +       struct nfs4_exception exception = { };
6860 +       int err;
6861 +       do {
6862 +               err = nfs4_handle_exception(NFS_SERVER(inode),
6863 +                               _nfs4_proc_readlink(inode, page),
6864 +                               &exception);
6865 +       } while (exception.retry);
6866 +       return err;
6867 +}
6868 +
6869 +static int _nfs4_proc_read(struct nfs_read_data *rdata)
6870  {
6871         int flags = rdata->flags;
6872         struct inode *inode = rdata->inode;
6873 @@ -827,6 +1206,7 @@ nfs4_proc_read(struct nfs_read_data *rda
6874                 .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_READ],
6875                 .rpc_argp       = &rdata->args,
6876                 .rpc_resp       = &rdata->res,
6877 +               .rpc_cred       = rdata->cred,
6878         };
6879         unsigned long timestamp = jiffies;
6880         int status;
6881 @@ -834,29 +1214,27 @@ nfs4_proc_read(struct nfs_read_data *rda
6882         dprintk("NFS call  read %d @ %Ld\n", rdata->args.count,
6883                         (long long) rdata->args.offset);
6884  
6885 -       /*
6886 -        * Try first to use O_RDONLY, then O_RDWR stateid.
6887 -        */
6888 -       if (filp) {
6889 -               struct nfs4_state *state;
6890 -               state = (struct nfs4_state *)filp->private_data;
6891 -               rdata->args.state = state;
6892 -               msg.rpc_cred = state->owner->so_cred;
6893 -       } else {
6894 -               rdata->args.state = NULL;
6895 -               msg.rpc_cred = NFS_I(inode)->mm_cred;
6896 -       }
6897 -
6898         fattr->valid = 0;
6899         status = rpc_call_sync(server->client, &msg, flags);
6900         if (!status)
6901                 renew_lease(server, timestamp);
6902         dprintk("NFS reply read: %d\n", status);
6903 -       return nfs4_map_errors(status);
6904 +       return status;
6905  }
6906  
6907 -static int
6908 -nfs4_proc_write(struct nfs_write_data *wdata, struct file *filp)
6909 +static int nfs4_proc_read(struct nfs_read_data *rdata)
6910 +{
6911 +       struct nfs4_exception exception = { };
6912 +       int err;
6913 +       do {
6914 +               err = nfs4_handle_exception(NFS_SERVER(rdata->inode),
6915 +                               _nfs4_proc_read(rdata),
6916 +                               &exception);
6917 +       } while (exception.retry);
6918 +       return err;
6919 +}
6920 +
6921 +static int _nfs4_proc_write(struct nfs_write_data *wdata)
6922  {
6923         int rpcflags = wdata->flags;
6924         struct inode *inode = wdata->inode;
6925 @@ -866,33 +1244,32 @@ nfs4_proc_write(struct nfs_write_data *w
6926                 .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_WRITE],
6927                 .rpc_argp       = &wdata->args,
6928                 .rpc_resp       = &wdata->res,
6929 +               .rpc_cred       = wdata->cred,
6930         };
6931         int status;
6932  
6933         dprintk("NFS call  write %d @ %Ld\n", wdata->args.count,
6934                         (long long) wdata->args.offset);
6935  
6936 -       /*
6937 -        * Try first to use O_WRONLY, then O_RDWR stateid.
6938 -        */
6939 -       if (filp) {
6940 -               struct nfs4_state *state;
6941 -               state = (struct nfs4_state *)filp->private_data;
6942 -               wdata->args.state = state;
6943 -               msg.rpc_cred = state->owner->so_cred;
6944 -       } else {
6945 -               wdata->args.state = NULL;
6946 -               msg.rpc_cred = NFS_I(inode)->mm_cred;
6947 -       }
6948 -
6949         fattr->valid = 0;
6950         status = rpc_call_sync(server->client, &msg, rpcflags);
6951         dprintk("NFS reply write: %d\n", status);
6952 -       return nfs4_map_errors(status);
6953 +       return status;
6954  }
6955  
6956 -static int
6957 -nfs4_proc_commit(struct nfs_write_data *cdata, struct file *filp)
6958 +static int nfs4_proc_write(struct nfs_write_data *wdata)
6959 +{
6960 +       struct nfs4_exception exception = { };
6961 +       int err;
6962 +       do {
6963 +               err = nfs4_handle_exception(NFS_SERVER(wdata->inode),
6964 +                               _nfs4_proc_write(wdata),
6965 +                               &exception);
6966 +       } while (exception.retry);
6967 +       return err;
6968 +}
6969 +
6970 +static int _nfs4_proc_commit(struct nfs_write_data *cdata)
6971  {
6972         struct inode *inode = cdata->inode;
6973         struct nfs_fattr *fattr = cdata->res.fattr;
6974 @@ -901,24 +1278,29 @@ nfs4_proc_commit(struct nfs_write_data *
6975                 .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_COMMIT],
6976                 .rpc_argp       = &cdata->args,
6977                 .rpc_resp       = &cdata->res,
6978 +               .rpc_cred       = cdata->cred,
6979         };
6980         int status;
6981  
6982         dprintk("NFS call  commit %d @ %Ld\n", cdata->args.count,
6983                         (long long) cdata->args.offset);
6984  
6985 -       /*
6986 -        * Try first to use O_WRONLY, then O_RDWR stateid.
6987 -        */
6988 -       if (filp)
6989 -               msg.rpc_cred = ((struct nfs4_state *)filp->private_data)->owner->so_cred;
6990 -       else
6991 -               msg.rpc_cred = NFS_I(inode)->mm_cred;
6992 -
6993         fattr->valid = 0;
6994         status = rpc_call_sync(server->client, &msg, 0);
6995         dprintk("NFS reply commit: %d\n", status);
6996 -       return nfs4_map_errors(status);
6997 +       return status;
6998 +}
6999 +
7000 +static int nfs4_proc_commit(struct nfs_write_data *cdata)
7001 +{
7002 +       struct nfs4_exception exception = { };
7003 +       int err;
7004 +       do {
7005 +               err = nfs4_handle_exception(NFS_SERVER(cdata->inode),
7006 +                               _nfs4_proc_commit(cdata),
7007 +                               &exception);
7008 +       } while (exception.retry);
7009 +       return err;
7010  }
7011  
7012  /*
7013 @@ -965,7 +1347,7 @@ nfs4_proc_create(struct inode *dir, stru
7014         return inode;
7015  }
7016  
7017 -static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
7018 +static int _nfs4_proc_remove(struct inode *dir, struct qstr *name)
7019  {
7020         struct nfs4_remove_arg args = {
7021                 .fh = NFS_FH(dir),
7022 @@ -982,7 +1364,19 @@ static int nfs4_proc_remove(struct inode
7023         status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
7024         if (status == 0)
7025                 update_changeattr(dir, &res);
7026 -       return nfs4_map_errors(status);
7027 +       return status;
7028 +}
7029 +
7030 +static int nfs4_proc_remove(struct inode *dir, struct qstr *name)
7031 +{
7032 +       struct nfs4_exception exception = { };
7033 +       int err;
7034 +       do {
7035 +               err = nfs4_handle_exception(NFS_SERVER(dir),
7036 +                               _nfs4_proc_remove(dir, name),
7037 +                               &exception);
7038 +       } while (exception.retry);
7039 +       return err;
7040  }
7041  
7042  struct unlink_desc {
7043 @@ -1023,7 +1417,7 @@ static int nfs4_proc_unlink_done(struct 
7044         return 0;
7045  }
7046  
7047 -static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
7048 +static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
7049                 struct inode *new_dir, struct qstr *new_name)
7050  {
7051         struct nfs4_rename_arg arg = {
7052 @@ -1046,10 +1440,24 @@ static int nfs4_proc_rename(struct inode
7053                 update_changeattr(old_dir, &res.old_cinfo);
7054                 update_changeattr(new_dir, &res.new_cinfo);
7055         }
7056 -       return nfs4_map_errors(status);
7057 +       return status;
7058  }
7059  
7060 -static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
7061 +static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
7062 +               struct inode *new_dir, struct qstr *new_name)
7063 +{
7064 +       struct nfs4_exception exception = { };
7065 +       int err;
7066 +       do {
7067 +               err = nfs4_handle_exception(NFS_SERVER(old_dir),
7068 +                               _nfs4_proc_rename(old_dir, old_name,
7069 +                                       new_dir, new_name),
7070 +                               &exception);
7071 +       } while (exception.retry);
7072 +       return err;
7073 +}
7074 +
7075 +static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
7076  {
7077         struct nfs4_link_arg arg = {
7078                 .fh     = NFS_FH(inode),
7079 @@ -1068,10 +1476,22 @@ static int nfs4_proc_link(struct inode *
7080         if (!status)
7081                 update_changeattr(dir, &cinfo);
7082  
7083 -       return nfs4_map_errors(status);
7084 +       return status;
7085 +}
7086 +
7087 +static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
7088 +{
7089 +       struct nfs4_exception exception = { };
7090 +       int err;
7091 +       do {
7092 +               err = nfs4_handle_exception(NFS_SERVER(inode),
7093 +                               _nfs4_proc_link(inode, dir, name),
7094 +                               &exception);
7095 +       } while (exception.retry);
7096 +       return err;
7097  }
7098  
7099 -static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
7100 +static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
7101                 struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
7102                 struct nfs_fattr *fattr)
7103  {
7104 @@ -1090,22 +1510,39 @@ static int nfs4_proc_symlink(struct inod
7105                 .fattr = fattr,
7106         };
7107         struct rpc_message msg = {
7108 -               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
7109 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SYMLINK],
7110                 .rpc_argp = &arg,
7111                 .rpc_resp = &res,
7112         };
7113         int                     status;
7114  
7115 +       if (path->len > NFS4_MAXPATHLEN)
7116 +               return -ENAMETOOLONG;
7117         arg.u.symlink = path;
7118         fattr->valid = 0;
7119         
7120         status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
7121         if (!status)
7122                 update_changeattr(dir, &res.dir_cinfo);
7123 -       return nfs4_map_errors(status);
7124 +       return status;
7125  }
7126  
7127 -static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
7128 +static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
7129 +               struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
7130 +               struct nfs_fattr *fattr)
7131 +{
7132 +       struct nfs4_exception exception = { };
7133 +       int err;
7134 +       do {
7135 +               err = nfs4_handle_exception(NFS_SERVER(dir),
7136 +                               _nfs4_proc_symlink(dir, name, path, sattr,
7137 +                                       fhandle, fattr),
7138 +                               &exception);
7139 +       } while (exception.retry);
7140 +       return err;
7141 +}
7142 +
7143 +static int _nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
7144                 struct iattr *sattr, struct nfs_fh *fhandle,
7145                 struct nfs_fattr *fattr)
7146  {
7147 @@ -1135,10 +1572,25 @@ static int nfs4_proc_mkdir(struct inode 
7148         status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
7149         if (!status)
7150                 update_changeattr(dir, &res.dir_cinfo);
7151 -       return nfs4_map_errors(status);
7152 +       return status;
7153  }
7154  
7155 -static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
7156 +static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
7157 +               struct iattr *sattr, struct nfs_fh *fhandle,
7158 +               struct nfs_fattr *fattr)
7159 +{
7160 +       struct nfs4_exception exception = { };
7161 +       int err;
7162 +       do {
7163 +               err = nfs4_handle_exception(NFS_SERVER(dir),
7164 +                               _nfs4_proc_mkdir(dir, name, sattr,
7165 +                                       fhandle, fattr),
7166 +                               &exception);
7167 +       } while (exception.retry);
7168 +       return err;
7169 +}
7170 +
7171 +static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
7172                    u64 cookie, struct page *page, unsigned int count, int plus)
7173  {
7174         struct inode            *dir = dentry->d_inode;
7175 @@ -1164,10 +1616,24 @@ static int nfs4_proc_readdir(struct dent
7176         if (status == 0)
7177                 memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
7178         unlock_kernel();
7179 -       return nfs4_map_errors(status);
7180 +       return status;
7181  }
7182  
7183 -static int nfs4_proc_mknod(struct inode *dir, struct qstr *name,
7184 +static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
7185 +                  u64 cookie, struct page *page, unsigned int count, int plus)
7186 +{
7187 +       struct nfs4_exception exception = { };
7188 +       int err;
7189 +       do {
7190 +               err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode),
7191 +                               _nfs4_proc_readdir(dentry, cred, cookie,
7192 +                                       page, count, plus),
7193 +                               &exception);
7194 +       } while (exception.retry);
7195 +       return err;
7196 +}
7197 +
7198 +static int _nfs4_proc_mknod(struct inode *dir, struct qstr *name,
7199                 struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
7200                 struct nfs_fattr *fattr)
7201  {
7202 @@ -1214,10 +1680,25 @@ static int nfs4_proc_mknod(struct inode 
7203         status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
7204         if (!status)
7205                 update_changeattr(dir, &res.dir_cinfo);
7206 -       return nfs4_map_errors(status);
7207 +       return status;
7208 +}
7209 +
7210 +static int nfs4_proc_mknod(struct inode *dir, struct qstr *name,
7211 +               struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
7212 +               struct nfs_fattr *fattr)
7213 +{
7214 +       struct nfs4_exception exception = { };
7215 +       int err;
7216 +       do {
7217 +               err = nfs4_handle_exception(NFS_SERVER(dir),
7218 +                               _nfs4_proc_mknod(dir, name, sattr, rdev,
7219 +                                       fh, fattr),
7220 +                               &exception);
7221 +       } while (exception.retry);
7222 +       return err;
7223  }
7224  
7225 -static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
7226 +static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
7227                  struct nfs_fsstat *fsstat)
7228  {
7229         struct nfs4_statfs_arg args = {
7230 @@ -1231,10 +1712,22 @@ static int nfs4_proc_statfs(struct nfs_s
7231         };
7232  
7233         fsstat->fattr->valid = 0;
7234 -       return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
7235 +       return rpc_call_sync(server->client, &msg, 0);
7236  }
7237  
7238 -static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
7239 +static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
7240 +{
7241 +       struct nfs4_exception exception = { };
7242 +       int err;
7243 +       do {
7244 +               err = nfs4_handle_exception(server,
7245 +                               _nfs4_proc_statfs(server, fhandle, fsstat),
7246 +                               &exception);
7247 +       } while (exception.retry);
7248 +       return err;
7249 +}
7250 +
7251 +static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
7252                 struct nfs_fsinfo *fsinfo)
7253  {
7254         struct nfs4_fsinfo_arg args = {
7255 @@ -1247,16 +1740,29 @@ static int nfs4_do_fsinfo(struct nfs_ser
7256                 .rpc_resp = fsinfo,
7257         };
7258  
7259 -       return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
7260 +       return rpc_call_sync(server->client, &msg, 0);
7261 +}
7262 +
7263 +static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
7264 +{
7265 +       struct nfs4_exception exception = { };
7266 +       int err;
7267 +
7268 +       do {
7269 +               err = nfs4_handle_exception(server,
7270 +                               _nfs4_do_fsinfo(server, fhandle, fsinfo),
7271 +                               &exception);
7272 +       } while (exception.retry);
7273 +       return err;
7274  }
7275  
7276  static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
7277  {
7278         fsinfo->fattr->valid = 0;
7279 -       return nfs4_map_errors(nfs4_do_fsinfo(server, fhandle, fsinfo));
7280 +       return nfs4_do_fsinfo(server, fhandle, fsinfo);
7281  }
7282  
7283 -static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
7284 +static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
7285                 struct nfs_pathconf *pathconf)
7286  {
7287         struct nfs4_pathconf_arg args = {
7288 @@ -1276,7 +1782,21 @@ static int nfs4_proc_pathconf(struct nfs
7289         }
7290  
7291         pathconf->fattr->valid = 0;
7292 -       return nfs4_map_errors(rpc_call_sync(server->client, &msg, 0));
7293 +       return rpc_call_sync(server->client, &msg, 0);
7294 +}
7295 +
7296 +static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
7297 +               struct nfs_pathconf *pathconf)
7298 +{
7299 +       struct nfs4_exception exception = { };
7300 +       int err;
7301 +
7302 +       do {
7303 +               err = nfs4_handle_exception(server,
7304 +                               _nfs4_proc_pathconf(server, fhandle, pathconf),
7305 +                               &exception);
7306 +       } while (exception.retry);
7307 +       return err;
7308  }
7309  
7310  static void
7311 @@ -1467,8 +1987,10 @@ static int
7312  nfs4_proc_file_open(struct inode *inode, struct file *filp)
7313  {
7314         struct dentry *dentry = filp->f_dentry;
7315 -       struct nfs4_state *state;
7316 +       struct nfs_open_context *ctx;
7317 +       struct nfs4_state *state = NULL;
7318         struct rpc_cred *cred;
7319 +       int status = -ENOMEM;
7320  
7321         dprintk("nfs4_proc_file_open: starting on (%.*s/%.*s)\n",
7322                                (int)dentry->d_parent->d_name.len,
7323 @@ -1478,21 +2000,28 @@ nfs4_proc_file_open(struct inode *inode,
7324  
7325         /* Find our open stateid */
7326         cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
7327 -       state = nfs4_find_state(inode, cred, filp->f_mode);
7328 +       if (unlikely(cred == NULL))
7329 +               return -ENOMEM;
7330 +       ctx = alloc_nfs_open_context(dentry, cred);
7331         put_rpccred(cred);
7332 -       if (state == NULL) {
7333 -               printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__);
7334 -               return -EIO; /* ERACE actually */
7335 -       }
7336 +       if (unlikely(ctx == NULL))
7337 +               return -ENOMEM;
7338 +       status = -EIO; /* ERACE actually */
7339 +       state = nfs4_find_state(inode, cred, filp->f_mode);
7340 +       if (unlikely(state == NULL))
7341 +               goto no_state;
7342 +       ctx->state = state;
7343         nfs4_close_state(state, filp->f_mode);
7344 -       if (filp->f_mode & FMODE_WRITE) {
7345 -               lock_kernel();
7346 -               nfs_set_mmcred(inode, state->owner->so_cred);
7347 +       ctx->mode = filp->f_mode;
7348 +       nfs_file_set_open_context(filp, ctx);
7349 +       put_nfs_open_context(ctx);
7350 +       if (filp->f_mode & FMODE_WRITE)
7351                 nfs_begin_data_update(inode);
7352 -               unlock_kernel();
7353 -       }
7354 -       filp->private_data = state;
7355         return 0;
7356 +no_state:
7357 +       printk(KERN_WARNING "NFS: v4 raced in function %s\n", __FUNCTION__);
7358 +       put_nfs_open_context(ctx);
7359 +       return status;
7360  }
7361  
7362  /*
7363 @@ -1501,35 +2030,148 @@ nfs4_proc_file_open(struct inode *inode,
7364  static int
7365  nfs4_proc_file_release(struct inode *inode, struct file *filp)
7366  {
7367 -       struct nfs4_state *state = (struct nfs4_state *)filp->private_data;
7368 -
7369 -       if (state)
7370 -               nfs4_close_state(state, filp->f_mode);
7371 -       if (filp->f_mode & FMODE_WRITE) {
7372 -               lock_kernel();
7373 +       if (filp->f_mode & FMODE_WRITE)
7374                 nfs_end_data_update(inode);
7375 -               unlock_kernel();
7376 -       }
7377 +       nfs_file_clear_open_context(filp);
7378         return 0;
7379  }
7380  
7381 -/*
7382 - * Set up the nfspage struct with the right state info and credentials
7383 - */
7384 +static ssize_t
7385 +nfs4_read_acl_attr(struct inode *inode, char *buf, ssize_t buflen)
7386 +{
7387 +       struct nfs_inode *nfsi = NFS_I(inode);
7388 +       int ret;
7389 +
7390 +       spin_lock(&inode->i_lock);
7391 +       if (buf == NULL && nfsi->acl_len)
7392 +               goto out_len;
7393 +       ret = -ENOENT;
7394 +       if (nfsi->acl_len == 0)
7395 +               goto out;
7396 +       ret = -ERANGE; /* see getxattr(2) man page */
7397 +       if (nfsi->acl_len > buflen)
7398 +               goto out;
7399 +       memcpy(buf, nfsi->acl, nfsi->acl_len);
7400 +out_len:
7401 +       ret = nfsi->acl_len;
7402 +out:
7403 +       spin_unlock(&inode->i_lock);
7404 +       return ret;
7405 +}
7406 +
7407  static void
7408 -nfs4_request_init(struct nfs_page *req, struct file *filp)
7409 +nfs4_set_acl_attr(struct inode *inode, char *buf, ssize_t buflen)
7410  {
7411 -       struct nfs4_state *state;
7412 +       struct nfs_inode *nfsi = NFS_I(inode);
7413  
7414 -       if (!filp) {
7415 -               req->wb_cred = get_rpccred(NFS_I(req->wb_inode)->mm_cred);
7416 -               req->wb_state = NULL;
7417 -               return;
7418 +       spin_lock(&inode->i_lock);
7419 +       kfree(nfsi->acl);
7420 +       nfsi->acl = buf;
7421 +       nfsi->acl_len = buflen;
7422 +       spin_unlock(&inode->i_lock);
7423 +}
7424 +
7425 +static int
7426 +nfs4_write_acl_attr(struct inode *inode, const char *buf, ssize_t buflen)
7427 +{
7428 +       void *abuf = NULL;
7429 +
7430 +       if (buflen > PAGE_SIZE)
7431 +               goto out_nomem;
7432 +       abuf = kmalloc(buflen, GFP_KERNEL);
7433 +       if (abuf == NULL)
7434 +               goto out_nomem;
7435 +       memcpy(abuf, buf, buflen);
7436 +       nfs4_set_acl_attr(inode, abuf, buflen);
7437 +       return 0;
7438 +out_nomem:
7439 +       nfs4_set_acl_attr(inode, NULL, 0);
7440 +       return -ENOMEM;
7441 +}
7442 +
7443 +void
7444 +nfs4_zap_acl_attr(struct inode *inode)
7445 +{
7446 +       nfs4_set_acl_attr(inode, NULL, 0);
7447 +}
7448 +
7449 +static int
7450 +nfs4_server_supports_acls(struct nfs_server *server)
7451 +{
7452 +       return (server->caps & NFS_CAP_ACLS)
7453 +               && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
7454 +               && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
7455 +}
7456 +
7457 +ssize_t
7458 +nfs4_proc_get_acl(struct inode *inode, void *buf, ssize_t buflen)
7459 +{
7460 +       struct nfs_server *server = NFS_SERVER(inode);
7461 +       struct nfs_getaclres res = {
7462 +               .acl = buf,
7463 +               .acl_len = buflen,
7464 +               .server = server,
7465 +       };
7466 +       struct rpc_message msg = {
7467 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],
7468 +               .rpc_argp = NFS_FH(inode),
7469 +               .rpc_resp = &res,
7470 +       };
7471 +       int ret;
7472 +
7473 +       if (!nfs4_server_supports_acls(server))
7474 +               return -EOPNOTSUPP;
7475 +       lock_kernel();
7476 +       ret = nfs_revalidate_inode(NFS_SERVER(inode), inode);
7477 +       if (ret < 0)
7478 +               goto out;
7479 +       ret = nfs4_read_acl_attr(inode, buf, buflen);
7480 +       if (ret == -ENOENT) {
7481 +               ret = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
7482 +               if (ret == 0) {
7483 +                       nfs4_write_acl_attr(inode, res.acl, res.acl_len);
7484 +                       ret = res.acl_len;
7485 +               }
7486 +               if (res.acl != buf) {
7487 +                       /* xdr decode allocated the memory: */
7488 +                       kfree(res.acl);
7489 +               }
7490         }
7491 -       state = (struct nfs4_state *)filp->private_data;
7492 -       req->wb_state = state;
7493 -       req->wb_cred = get_rpccred(state->owner->so_cred);
7494 -       req->wb_lockowner = current->files;
7495 +out:
7496 +       unlock_kernel();
7497 +       return ret;
7498 +}
7499 +
7500 +int
7501 +nfs4_proc_set_acl(struct inode *inode, const void *buf, ssize_t buflen)
7502 +{
7503 +       struct nfs_server *server = NFS_SERVER(inode);
7504 +       struct nfs_setaclargs arg = {
7505 +               .fh             = NFS_FH(inode),
7506 +               .server         = server,
7507 +               .acl            = buf,
7508 +               .acl_len        = buflen,
7509 +       };
7510 +       struct rpc_message msg = {
7511 +               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETACL],
7512 +               .rpc_argp       = &arg,
7513 +               .rpc_resp       = NULL,
7514 +       };
7515 +       int ret;
7516 +
7517 +       if (!nfs4_server_supports_acls(server))
7518 +               return -EOPNOTSUPP;
7519 +
7520 +       /* XXX: should check for buflen too large? */
7521 +
7522 +       lock_kernel();
7523 +       ret = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0);
7524 +       unlock_kernel();
7525 +
7526 +       if (ret == 0)
7527 +               nfs4_write_acl_attr(inode, buf, buflen);
7528 +
7529 +       return ret;
7530  }
7531  
7532  static int
7533 @@ -1545,11 +2187,13 @@ nfs4_async_handle_error(struct rpc_task 
7534                 case -NFS4ERR_EXPIRED:
7535                         rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL, NULL);
7536                         nfs4_schedule_state_recovery(clp);
7537 +                       if (test_bit(NFS4CLNT_OK, &clp->cl_state))
7538 +                               rpc_wake_up_task(task);
7539                         task->tk_status = 0;
7540                         return -EAGAIN;
7541                 case -NFS4ERR_GRACE:
7542                 case -NFS4ERR_DELAY:
7543 -                       rpc_delay(task, NFS4_POLL_RETRY_TIME);
7544 +                       rpc_delay(task, NFS4_POLL_RETRY_MAX);
7545                         task->tk_status = 0;
7546                         return -EAGAIN;
7547                 case -NFS4ERR_OLD_STATEID:
7548 @@ -1560,12 +2204,11 @@ nfs4_async_handle_error(struct rpc_task 
7549         return 0;
7550  }
7551  
7552 -int
7553 -nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
7554 +int nfs4_wait_clnt_recover(struct rpc_clnt *clnt, struct nfs4_client *clp)
7555  {
7556         DEFINE_WAIT(wait);
7557         sigset_t oldset;
7558 -       int interruptible, res;
7559 +       int interruptible, res = 0;
7560  
7561         might_sleep();
7562  
7563 @@ -1573,101 +2216,85 @@ nfs4_wait_clnt_recover(struct rpc_clnt *
7564         interruptible = TASK_UNINTERRUPTIBLE;
7565         if (clnt->cl_intr)
7566                 interruptible = TASK_INTERRUPTIBLE;
7567 -       do {
7568 -               res = 0;
7569 -               prepare_to_wait(&clp->cl_waitq, &wait, interruptible);
7570 -               nfs4_schedule_state_recovery(clp);
7571 -               if (test_bit(NFS4CLNT_OK, &clp->cl_state) &&
7572 -                               !test_bit(NFS4CLNT_SETUP_STATE, &clp->cl_state))
7573 -                       break;
7574 -               if (clnt->cl_intr && signalled()) {
7575 -                       res = -ERESTARTSYS;
7576 -                       break;
7577 -               }
7578 +       prepare_to_wait(&clp->cl_waitq, &wait, interruptible);
7579 +       nfs4_schedule_state_recovery(clp);
7580 +       if (clnt->cl_intr && signalled())
7581 +               res = -ERESTARTSYS;
7582 +       else if (!test_bit(NFS4CLNT_OK, &clp->cl_state))
7583                 schedule();
7584 -       } while(!test_bit(NFS4CLNT_OK, &clp->cl_state));
7585         finish_wait(&clp->cl_waitq, &wait);
7586         rpc_clnt_sigunmask(clnt, &oldset);
7587         return res;
7588  }
7589  
7590 -static int
7591 -nfs4_delay(struct rpc_clnt *clnt)
7592 +static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
7593  {
7594         sigset_t oldset;
7595         int res = 0;
7596  
7597         might_sleep();
7598  
7599 +       if (*timeout <= 0)
7600 +               *timeout = NFS4_POLL_RETRY_MIN;
7601 +       if (*timeout > NFS4_POLL_RETRY_MAX)
7602 +               *timeout = NFS4_POLL_RETRY_MAX;
7603         rpc_clnt_sigmask(clnt, &oldset);
7604         if (clnt->cl_intr) {
7605                 set_current_state(TASK_INTERRUPTIBLE);
7606 -               schedule_timeout(NFS4_POLL_RETRY_TIME);
7607 +               schedule_timeout(*timeout);
7608                 if (signalled())
7609                         res = -ERESTARTSYS;
7610         } else {
7611                 set_current_state(TASK_UNINTERRUPTIBLE);
7612 -               schedule_timeout(NFS4_POLL_RETRY_TIME);
7613 +               schedule_timeout(*timeout);
7614         }
7615         rpc_clnt_sigunmask(clnt, &oldset);
7616 +       *timeout <<= 1;
7617         return res;
7618  }
7619  
7620  /* This is the error handling routine for processes that are allowed
7621   * to sleep.
7622   */
7623 -int
7624 -nfs4_handle_error(struct nfs_server *server, int errorcode)
7625 +int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
7626  {
7627         struct nfs4_client *clp = server->nfs4_state;
7628         int ret = errorcode;
7629  
7630 +       exception->retry = 0;
7631         switch(errorcode) {
7632 +               case 0:
7633 +                       return 0;
7634                 case -NFS4ERR_STALE_CLIENTID:
7635                 case -NFS4ERR_STALE_STATEID:
7636                 case -NFS4ERR_EXPIRED:
7637                         ret = nfs4_wait_clnt_recover(server->client, clp);
7638 +                       if (ret == 0)
7639 +                               exception->retry = 1;
7640                         break;
7641                 case -NFS4ERR_GRACE:
7642                 case -NFS4ERR_DELAY:
7643 -                       ret = nfs4_delay(server->client);
7644 +                       ret = nfs4_delay(server->client, &exception->timeout);
7645 +                       if (ret == 0)
7646 +                               exception->retry = 1;
7647                         break;
7648                 case -NFS4ERR_OLD_STATEID:
7649 -                       ret = 0;
7650 +                       if (ret == 0)
7651 +                               exception->retry = 1;
7652         }
7653         /* We failed to handle the error */
7654         return nfs4_map_errors(ret);
7655  }
7656  
7657 -
7658 -static int
7659 -nfs4_request_compatible(struct nfs_page *req, struct file *filp, struct page *page)
7660 -{
7661 -       struct nfs4_state *state = NULL;
7662 -       struct rpc_cred *cred = NULL;
7663 -
7664 -       if (req->wb_file != filp)
7665 -               return 0;
7666 -       if (req->wb_page != page)
7667 -               return 0;
7668 -       state = (struct nfs4_state *)filp->private_data;
7669 -       if (req->wb_state != state)
7670 -               return 0;
7671 -       if (req->wb_lockowner != current->files)
7672 -               return 0;
7673 -       cred = state->owner->so_cred;
7674 -       if (req->wb_cred != cred)
7675 -               return 0;
7676 -       return 1;
7677 -}
7678 -
7679 -int
7680 -nfs4_proc_setclientid(struct nfs4_client *clp,
7681 -               u32 program, unsigned short port)
7682 +int nfs4_proc_setclientid(struct nfs4_client *clp, u32 program, unsigned short port)
7683  {
7684 -       u32 *p;
7685 -       struct nfs4_setclientid setclientid;
7686 -       struct timespec tv;
7687 +       static nfs4_verifier sc_verifier;
7688 +       static int initialized;
7689 +       
7690 +       struct nfs4_setclientid setclientid = {
7691 +               .sc_verifier = &sc_verifier,
7692 +               .sc_prog = program,
7693 +       };
7694         struct rpc_message msg = {
7695                 .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETCLIENTID],
7696                 .rpc_argp = &setclientid,
7697 @@ -1675,15 +2302,24 @@ nfs4_proc_setclientid(struct nfs4_client
7698                 .rpc_cred = clp->cl_cred,
7699         };
7700  
7701 -       tv = CURRENT_TIME;
7702 -       p = (u32*)setclientid.sc_verifier.data;
7703 -       *p++ = (u32)tv.tv_sec;
7704 -       *p = (u32)tv.tv_nsec;
7705 -       setclientid.sc_name = clp->cl_ipaddr;
7706 -       sprintf(setclientid.sc_netid, "tcp");
7707 -       sprintf(setclientid.sc_uaddr, "%s.%d.%d", clp->cl_ipaddr, port >> 8, port & 255);
7708 -       setclientid.sc_prog = htonl(program);
7709 -       setclientid.sc_cb_ident = 0;
7710 +       if (!initialized) {
7711 +               struct timespec boot_time;
7712 +               u32 *p;
7713 +
7714 +               initialized = 1;
7715 +               boot_time = CURRENT_TIME;
7716 +               p = (u32*)sc_verifier.data;
7717 +               *p++ = htonl((u32)boot_time.tv_sec);
7718 +               *p = htonl((u32)boot_time.tv_nsec);
7719 +       }
7720 +       setclientid.sc_name_len = scnprintf(setclientid.sc_name,
7721 +                       sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u",
7722 +                       clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr));
7723 +       setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
7724 +                       sizeof(setclientid.sc_netid), "tcp");
7725 +       setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
7726 +                       sizeof(setclientid.sc_uaddr), "%s.%d.%d",
7727 +                       clp->cl_ipaddr, port >> 8, port & 255);
7728  
7729         return rpc_call_sync(clp->cl_rpcclient, &msg, 0);
7730  }
7731 @@ -1712,6 +2348,40 @@ nfs4_proc_setclientid_confirm(struct nfs
7732         return status;
7733  }
7734  
7735 +static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid)
7736 +{
7737 +       struct nfs4_delegreturnargs args = {
7738 +               .fhandle = NFS_FH(inode),
7739 +               .stateid = stateid,
7740 +       };
7741 +       struct rpc_message msg = {
7742 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DELEGRETURN],
7743 +               .rpc_argp = &args,
7744 +               .rpc_cred = cred,
7745 +       };
7746 +
7747 +       return rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
7748 +}
7749 +
7750 +int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid)
7751 +{
7752 +       struct nfs_server *server = NFS_SERVER(inode);
7753 +       struct nfs4_exception exception = { };
7754 +       int err;
7755 +       do {
7756 +               err = _nfs4_proc_delegreturn(inode, cred, stateid);
7757 +               switch (err) {
7758 +                       case -NFS4ERR_STALE_STATEID:
7759 +                       case -NFS4ERR_EXPIRED:
7760 +                               nfs4_schedule_state_recovery(server->nfs4_state);
7761 +                       case 0:
7762 +                               return 0;
7763 +               }
7764 +               err = nfs4_handle_exception(server, err, &exception);
7765 +       } while (exception.retry);
7766 +       return err;
7767 +}
7768 +
7769  #define NFS4_LOCK_MINTIMEOUT (1 * HZ)
7770  #define NFS4_LOCK_MAXTIMEOUT (30 * HZ)
7771  
7772 @@ -1753,8 +2423,7 @@ nfs4_lck_length(struct file_lock *reques
7773         return request->fl_end - request->fl_start + 1;
7774  }
7775  
7776 -int
7777 -nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7778 +static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7779  {
7780         struct inode *inode = state->inode;
7781         struct nfs_server *server = NFS_SERVER(inode);
7782 @@ -1778,9 +2447,10 @@ nfs4_proc_getlk(struct nfs4_state *state
7783         struct nfs4_lock_state *lsp;
7784         int status;
7785  
7786 +       down_read(&clp->cl_sem);
7787         nlo.clientid = clp->cl_clientid;
7788         down(&state->lock_sema);
7789 -       lsp = nfs4_find_lock_state(state, request->fl_owner);
7790 +       lsp = nfs4_find_lock_state(state, request->fl_pid);
7791         if (lsp)
7792                 nlo.id = lsp->ls_id; 
7793         else {
7794 @@ -1811,14 +2481,28 @@ nfs4_proc_getlk(struct nfs4_state *state
7795         if (lsp)
7796                 nfs4_put_lock_state(lsp);
7797         up(&state->lock_sema);
7798 -       return nfs4_map_errors(status);
7799 +       up_read(&clp->cl_sem);
7800 +       return status;
7801  }
7802  
7803 -int
7804 -nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
7805 +static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7806 +{
7807 +       struct nfs4_exception exception = { };
7808 +       int err;
7809 +
7810 +       do {
7811 +               err = nfs4_handle_exception(NFS_SERVER(state->inode),
7812 +                               _nfs4_proc_getlk(state, cmd, request),
7813 +                               &exception);
7814 +       } while (exception.retry);
7815 +       return err;
7816 +}
7817 +
7818 +static int _nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
7819  {
7820         struct inode *inode = state->inode;
7821         struct nfs_server *server = NFS_SERVER(inode);
7822 +       struct nfs4_client *clp = server->nfs4_state;
7823         struct nfs_lockargs arg = {
7824                 .fh = NFS_FH(inode),
7825                 .type = nfs4_lck_type(cmd, request),
7826 @@ -1838,29 +2522,46 @@ nfs4_proc_unlck(struct nfs4_state *state
7827         struct nfs_locku_opargs luargs;
7828         int status = 0;
7829                         
7830 +       down_read(&clp->cl_sem);
7831         down(&state->lock_sema);
7832 -       lsp = nfs4_find_lock_state(state, request->fl_owner);
7833 +       lsp = nfs4_find_lock_state(state, request->fl_pid);
7834         if (!lsp)
7835                 goto out;
7836 -       luargs.seqid = lsp->ls_seqid;
7837 -       memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid));
7838 -       arg.u.locku = &luargs;
7839 -       status = rpc_call_sync(server->client, &msg, 0);
7840 -       nfs4_increment_lock_seqid(status, lsp);
7841 +       /* We might have lost the locks! */
7842 +       if ((lsp->flags & NFS_LOCK_INITIALIZED) != 0) {
7843 +               luargs.seqid = lsp->ls_seqid;
7844 +               memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid));
7845 +               arg.u.locku = &luargs;
7846 +               status = rpc_call_sync(server->client, &msg, 0);
7847 +               nfs4_increment_lock_seqid(status, lsp);
7848 +       }
7849  
7850         if (status == 0) {
7851                 memcpy(&lsp->ls_stateid,  &res.u.stateid, 
7852                                 sizeof(lsp->ls_stateid));
7853 -               nfs4_notify_unlck(inode, request, lsp);
7854 +               nfs4_notify_unlck(state, request, lsp);
7855         }
7856         nfs4_put_lock_state(lsp);
7857  out:
7858         up(&state->lock_sema);
7859 -       return nfs4_map_errors(status);
7860 +       up_read(&clp->cl_sem);
7861 +       return status;
7862  }
7863  
7864 -static int
7865 -nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7866 +static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
7867 +{
7868 +       struct nfs4_exception exception = { };
7869 +       int err;
7870 +
7871 +       do {
7872 +               err = nfs4_handle_exception(NFS_SERVER(state->inode),
7873 +                               _nfs4_proc_unlck(state, cmd, request),
7874 +                               &exception);
7875 +       } while (exception.retry);
7876 +       return err;
7877 +}
7878 +
7879 +static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *request, int reclaim)
7880  {
7881         struct inode *inode = state->inode;
7882         struct nfs_server *server = NFS_SERVER(inode);
7883 @@ -1881,23 +2582,22 @@ nfs4_proc_setlk(struct nfs4_state *state
7884                 .rpc_cred       = state->owner->so_cred,
7885         };
7886         struct nfs_lock_opargs largs = {
7887 +               .reclaim = reclaim,
7888                 .new_lock_owner = 0,
7889         };
7890         int status;
7891  
7892 -       down(&state->lock_sema);
7893 -       lsp = nfs4_find_lock_state(state, request->fl_owner);
7894 -       if (lsp == NULL) {
7895 +       lsp = nfs4_get_lock_state(state, request->fl_pid);
7896 +       if (lsp == NULL)
7897 +               return -ENOMEM;
7898 +       if (!(lsp->flags & NFS_LOCK_INITIALIZED)) {
7899                 struct nfs4_state_owner *owner = state->owner;
7900                 struct nfs_open_to_lock otl = {
7901                         .lock_owner = {
7902                                 .clientid = server->nfs4_state->cl_clientid,
7903                         },
7904                 };
7905 -               status = -ENOMEM;
7906 -               lsp = nfs4_alloc_lock_state(state, request->fl_owner);
7907 -               if (!lsp)
7908 -                       goto out;
7909 +
7910                 otl.lock_seqid = lsp->ls_seqid;
7911                 otl.lock_owner.id = lsp->ls_id;
7912                 memcpy(&otl.open_stateid, &state->stateid, sizeof(otl.open_stateid));
7913 @@ -1926,25 +2626,60 @@ nfs4_proc_setlk(struct nfs4_state *state
7914         /* save the returned stateid. */
7915         if (status == 0) {
7916                 memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid));
7917 -               nfs4_notify_setlk(inode, request, lsp);
7918 +               if (!reclaim)
7919 +                       nfs4_notify_setlk(state, request, lsp);
7920         } else if (status == -NFS4ERR_DENIED)
7921                 status = -EAGAIN;
7922         nfs4_put_lock_state(lsp);
7923 -out:
7924 +       return status;
7925 +}
7926 +
7927 +int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
7928 +{
7929 +#ifdef F_SETLK64
7930 +       return _nfs4_do_setlk(state, F_SETLK64, request, 1);
7931 +#else
7932 +       return _nfs4_do_setlk(state, F_SETLK, request, 1);
7933 +#endif
7934 +}
7935 +
7936 +static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7937 +{
7938 +       struct nfs4_client *clp = state->owner->so_client;
7939 +       int status;
7940 +
7941 +       down_read(&clp->cl_sem);
7942 +       down(&state->lock_sema);
7943 +       status = _nfs4_do_setlk(state, cmd, request, 0);
7944         up(&state->lock_sema);
7945 -       return nfs4_map_errors(status);
7946 +       up_read(&clp->cl_sem);
7947 +       return status;
7948 +}
7949 +
7950 +static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
7951 +{
7952 +       struct nfs4_exception exception = { };
7953 +       int err;
7954 +
7955 +       do {
7956 +               err = nfs4_handle_exception(NFS_SERVER(state->inode),
7957 +                               _nfs4_proc_setlk(state, cmd, request),
7958 +                               &exception);
7959 +       } while (exception.retry);
7960 +       return err;
7961  }
7962  
7963  static int
7964  nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
7965  {
7966 +       struct nfs_open_context *ctx;
7967         struct nfs4_state *state;
7968         unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
7969         int status;
7970  
7971         /* verify open state */
7972 -       state = (struct nfs4_state *)filp->private_data;
7973 -       BUG_ON(!state);
7974 +       ctx = (struct nfs_open_context *)filp->private_data;
7975 +       state = ctx->state;
7976  
7977         if (request->fl_start < 0 || request->fl_end < 0)
7978                 return -EINVAL;
7979 @@ -1975,6 +2710,7 @@ struct nfs_rpc_ops        nfs_v4_clientops = {
7980         .version        = 4,                    /* protocol version */
7981         .dentry_ops     = &nfs4_dentry_operations,
7982         .dir_inode_ops  = &nfs4_dir_inode_operations,
7983 +       .file_inode_ops = &nfs4_file_inode_operations,
7984         .getroot        = nfs4_proc_get_root,
7985         .getattr        = nfs4_proc_getattr,
7986         .setattr        = nfs4_proc_setattr,
7987 @@ -2004,8 +2740,6 @@ struct nfs_rpc_ops        nfs_v4_clientops = {
7988         .commit_setup   = nfs4_proc_commit_setup,
7989         .file_open      = nfs4_proc_file_open,
7990         .file_release   = nfs4_proc_file_release,
7991 -       .request_init   = nfs4_request_init,
7992 -       .request_compatible = nfs4_request_compatible,
7993         .lock           = nfs4_proc_lock,
7994  };
7995  
7996 --- linux-2.6.7/fs/nfs/callback.h.lsec  2005-03-23 14:28:22.484631512 -0700
7997 +++ linux-2.6.7/fs/nfs/callback.h       2005-03-23 14:28:22.484631512 -0700
7998 @@ -0,0 +1,70 @@
7999 +/*
8000 + * linux/fs/nfs/callback.h
8001 + *
8002 + * Copyright (C) 2004 Trond Myklebust
8003 + *
8004 + * NFSv4 callback definitions
8005 + */
8006 +#ifndef __LINUX_FS_NFS_CALLBACK_H
8007 +#define __LINUX_FS_NFS_CALLBACK_H
8008 +
8009 +#define NFS4_CALLBACK 0x40000000
8010 +#define NFS4_CALLBACK_XDRSIZE 2048
8011 +#define NFS4_CALLBACK_BUFSIZE (1024 + NFS4_CALLBACK_XDRSIZE)
8012 +
8013 +enum nfs4_callback_procnum {
8014 +       CB_NULL = 0,
8015 +       CB_COMPOUND = 1,
8016 +};
8017 +
8018 +enum nfs4_callback_opnum {
8019 +       OP_CB_GETATTR = 3,
8020 +       OP_CB_RECALL  = 4,
8021 +       OP_CB_ILLEGAL = 10044,
8022 +};
8023 +
8024 +struct cb_compound_hdr_arg {
8025 +       int taglen;
8026 +       const char *tag;
8027 +       unsigned int callback_ident;
8028 +       unsigned nops;
8029 +};
8030 +
8031 +struct cb_compound_hdr_res {
8032 +       uint32_t *status;
8033 +       int taglen;
8034 +       const char *tag;
8035 +       uint32_t *nops;
8036 +};
8037 +
8038 +struct cb_getattrargs {
8039 +       struct sockaddr_in *addr;
8040 +       struct nfs_fh fh;
8041 +       uint32_t bitmap[2];
8042 +};
8043 +
8044 +struct cb_getattrres {
8045 +       uint32_t status;
8046 +       uint32_t bitmap[2];
8047 +       uint64_t size;
8048 +       uint64_t change_attr;
8049 +       struct timespec ctime;
8050 +       struct timespec mtime;
8051 +};
8052 +
8053 +struct cb_recallargs {
8054 +       struct sockaddr_in *addr;
8055 +       struct nfs_fh fh;
8056 +       nfs4_stateid stateid;
8057 +       uint32_t truncate;
8058 +};
8059 +
8060 +extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
8061 +extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
8062 +
8063 +extern int nfs_callback_up(void);
8064 +extern int nfs_callback_down(void);
8065 +
8066 +extern unsigned short nfs_callback_tcpport;
8067 +
8068 +#endif /* __LINUX_FS_NFS_CALLBACK_H */
8069 --- linux-2.6.7/fs/nfs/direct.c.lsec    2004-06-15 23:19:53.000000000 -0600
8070 +++ linux-2.6.7/fs/nfs/direct.c 2005-03-23 14:28:22.702598376 -0700
8071 @@ -110,7 +110,7 @@ nfs_free_user_pages(struct page **pages,
8072   * nfs_direct_read_seg - Read in one iov segment.  Generate separate
8073   *                        read RPCs for each "rsize" bytes.
8074   * @inode: target inode
8075 - * @file: target file (may be NULL)
8076 + * @ctx: target file open context
8077   * user_addr: starting address of this segment of user's buffer
8078   * count: size of this segment
8079   * file_offset: offset in file to begin the operation
8080 @@ -118,7 +118,7 @@ nfs_free_user_pages(struct page **pages,
8081   * nr_pages: size of pages array
8082   */
8083  static int
8084 -nfs_direct_read_seg(struct inode *inode, struct file *file,
8085 +nfs_direct_read_seg(struct inode *inode, struct nfs_open_context *ctx,
8086                 unsigned long user_addr, size_t count, loff_t file_offset,
8087                 struct page **pages, int nr_pages)
8088  {
8089 @@ -127,9 +127,10 @@ nfs_direct_read_seg(struct inode *inode,
8090         int curpage = 0;
8091         struct nfs_read_data    rdata = {
8092                 .inode          = inode,
8093 +               .cred           = ctx->cred,
8094                 .args           = {
8095                         .fh             = NFS_FH(inode),
8096 -                       .lockowner      = current->files,
8097 +                       .context        = ctx,
8098                 },
8099                 .res            = {
8100                         .fattr          = &rdata.fattr,
8101 @@ -151,7 +152,7 @@ nfs_direct_read_seg(struct inode *inode,
8102                         user_addr + tot_bytes, rdata.args.pgbase, curpage);
8103  
8104                 lock_kernel();
8105 -               result = NFS_PROTO(inode)->read(&rdata, file);
8106 +               result = NFS_PROTO(inode)->read(&rdata);
8107                 unlock_kernel();
8108  
8109                 if (result <= 0) {
8110 @@ -183,7 +184,7 @@ nfs_direct_read_seg(struct inode *inode,
8111   * nfs_direct_read - For each iov segment, map the user's buffer
8112   *                   then generate read RPCs.
8113   * @inode: target inode
8114 - * @file: target file (may be NULL)
8115 + * @ctx: target file open context
8116   * @iov: array of vectors that define I/O buffer
8117   * file_offset: offset in file to begin the operation
8118   * nr_segs: size of iovec array
8119 @@ -193,7 +194,7 @@ nfs_direct_read_seg(struct inode *inode,
8120   * server.
8121   */
8122  static ssize_t
8123 -nfs_direct_read(struct inode *inode, struct file *file,
8124 +nfs_direct_read(struct inode *inode, struct nfs_open_context *ctx,
8125                 const struct iovec *iov, loff_t file_offset,
8126                 unsigned long nr_segs)
8127  {
8128 @@ -216,7 +217,7 @@ nfs_direct_read(struct inode *inode, str
8129                          return page_count;
8130                  }
8131  
8132 -               result = nfs_direct_read_seg(inode, file, user_addr, size,
8133 +               result = nfs_direct_read_seg(inode, ctx, user_addr, size,
8134                                 file_offset, pages, page_count);
8135  
8136                 nfs_free_user_pages(pages, page_count, 1);
8137 @@ -239,7 +240,7 @@ nfs_direct_read(struct inode *inode, str
8138   * nfs_direct_write_seg - Write out one iov segment.  Generate separate
8139   *                        write RPCs for each "wsize" bytes, then commit.
8140   * @inode: target inode
8141 - * @file: target file (may be NULL)
8142 + * @ctx: target file open context
8143   * user_addr: starting address of this segment of user's buffer
8144   * count: size of this segment
8145   * file_offset: offset in file to begin the operation
8146 @@ -247,7 +248,7 @@ nfs_direct_read(struct inode *inode, str
8147   * nr_pages: size of pages array
8148   */
8149  static int
8150 -nfs_direct_write_seg(struct inode *inode, struct file *file,
8151 +nfs_direct_write_seg(struct inode *inode, struct nfs_open_context *ctx,
8152                 unsigned long user_addr, size_t count, loff_t file_offset,
8153                 struct page **pages, int nr_pages)
8154  {
8155 @@ -257,9 +258,10 @@ nfs_direct_write_seg(struct inode *inode
8156         struct nfs_writeverf first_verf;
8157         struct nfs_write_data   wdata = {
8158                 .inode          = inode,
8159 +               .cred           = ctx->cred,
8160                 .args           = {
8161                         .fh             = NFS_FH(inode),
8162 -                       .lockowner      = current->files,
8163 +                       .context        = ctx,
8164                 },
8165                 .res            = {
8166                         .fattr          = &wdata.fattr,
8167 @@ -290,7 +292,7 @@ retry:
8168                         user_addr + tot_bytes, wdata.args.pgbase, curpage);
8169  
8170                 lock_kernel();
8171 -               result = NFS_PROTO(inode)->write(&wdata, file);
8172 +               result = NFS_PROTO(inode)->write(&wdata);
8173                 unlock_kernel();
8174  
8175                 if (result <= 0) {
8176 @@ -325,7 +327,7 @@ retry:
8177                 wdata.args.offset = file_offset;
8178  
8179                 lock_kernel();
8180 -               result = NFS_PROTO(inode)->commit(&wdata, file);
8181 +               result = NFS_PROTO(inode)->commit(&wdata);
8182                 unlock_kernel();
8183  
8184                 if (result < 0 || memcmp(&first_verf.verifier,
8185 @@ -349,7 +351,7 @@ sync_retry:
8186   * nfs_direct_write - For each iov segment, map the user's buffer
8187   *                    then generate write and commit RPCs.
8188   * @inode: target inode
8189 - * @file: target file (may be NULL)
8190 + * @ctx: target file open context
8191   * @iov: array of vectors that define I/O buffer
8192   * file_offset: offset in file to begin the operation
8193   * nr_segs: size of iovec array
8194 @@ -358,8 +360,7 @@ sync_retry:
8195   * that non-direct readers might access, so they will pick up these
8196   * writes immediately.
8197   */
8198 -static ssize_t
8199 -nfs_direct_write(struct inode *inode, struct file *file,
8200 +static int nfs_direct_write(struct inode *inode, struct nfs_open_context *ctx,
8201                 const struct iovec *iov, loff_t file_offset,
8202                 unsigned long nr_segs)
8203  {
8204 @@ -382,7 +383,7 @@ nfs_direct_write(struct inode *inode, st
8205                          return page_count;
8206                  }
8207  
8208 -               result = nfs_direct_write_seg(inode, file, user_addr, size,
8209 +               result = nfs_direct_write_seg(inode, ctx, user_addr, size,
8210                                 file_offset, pages, page_count);
8211                 nfs_free_user_pages(pages, page_count, 0);
8212  
8213 @@ -414,6 +415,7 @@ nfs_direct_IO(int rw, struct kiocb *iocb
8214  {
8215         ssize_t result = -EINVAL;
8216         struct file *file = iocb->ki_filp;
8217 +       struct nfs_open_context *ctx;
8218         struct dentry *dentry = file->f_dentry;
8219         struct inode *inode = dentry->d_inode;
8220  
8221 @@ -423,19 +425,20 @@ nfs_direct_IO(int rw, struct kiocb *iocb
8222         if (!is_sync_kiocb(iocb))
8223                 return result;
8224  
8225 +       ctx = (struct nfs_open_context *)file->private_data;
8226         switch (rw) {
8227         case READ:
8228                 dprintk("NFS: direct_IO(read) (%s) off/no(%Lu/%lu)\n",
8229                                 dentry->d_name.name, file_offset, nr_segs);
8230  
8231 -               result = nfs_direct_read(inode, file, iov,
8232 +               result = nfs_direct_read(inode, ctx, iov,
8233                                                 file_offset, nr_segs);
8234                 break;
8235         case WRITE:
8236                 dprintk("NFS: direct_IO(write) (%s) off/no(%Lu/%lu)\n",
8237                                 dentry->d_name.name, file_offset, nr_segs);
8238  
8239 -               result = nfs_direct_write(inode, file, iov,
8240 +               result = nfs_direct_write(inode, ctx, iov,
8241                                                 file_offset, nr_segs);
8242                 break;
8243         default:
8244 @@ -471,6 +474,8 @@ nfs_file_direct_read(struct kiocb *iocb,
8245         ssize_t retval = -EINVAL;
8246         loff_t *ppos = &iocb->ki_pos;
8247         struct file *file = iocb->ki_filp;
8248 +       struct nfs_open_context *ctx =
8249 +                       (struct nfs_open_context *) file->private_data;
8250         struct dentry *dentry = file->f_dentry;
8251         struct address_space *mapping = file->f_mapping;
8252         struct inode *inode = mapping->host;
8253 @@ -502,7 +507,7 @@ nfs_file_direct_read(struct kiocb *iocb,
8254                         goto out;
8255         }
8256  
8257 -       retval = nfs_direct_read(inode, file, &iov, pos, 1);
8258 +       retval = nfs_direct_read(inode, ctx, &iov, pos, 1);
8259         if (retval > 0)
8260                 *ppos = pos + retval;
8261  
8262 @@ -542,6 +547,8 @@ nfs_file_direct_write(struct kiocb *iocb
8263         loff_t *ppos = &iocb->ki_pos;
8264         unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
8265         struct file *file = iocb->ki_filp;
8266 +       struct nfs_open_context *ctx =
8267 +                       (struct nfs_open_context *) file->private_data;
8268         struct dentry *dentry = file->f_dentry;
8269         struct address_space *mapping = file->f_mapping;
8270         struct inode *inode = mapping->host;
8271 @@ -589,7 +596,7 @@ nfs_file_direct_write(struct kiocb *iocb
8272                         goto out;
8273         }
8274  
8275 -       retval = nfs_direct_write(inode, file, &iov, pos, 1);
8276 +       retval = nfs_direct_write(inode, ctx, &iov, pos, 1);
8277         if (mapping->nrpages)
8278                 invalidate_inode_pages2(mapping);
8279         if (retval > 0)
8280 --- linux-2.6.7/fs/nfs/nfs4state.c.lsec 2004-06-15 23:18:47.000000000 -0600
8281 +++ linux-2.6.7/fs/nfs/nfs4state.c      2005-03-23 14:28:22.939562352 -0700
8282 @@ -40,11 +40,15 @@
8283  
8284  #include <linux/config.h>
8285  #include <linux/slab.h>
8286 +#include <linux/smp_lock.h>
8287  #include <linux/nfs_fs.h>
8288  #include <linux/nfs_idmap.h>
8289  #include <linux/workqueue.h>
8290  #include <linux/bitops.h>
8291  
8292 +#include "callback.h"
8293 +#include "delegation.h"
8294 +
8295  #define OPENOWNER_POOL_SIZE    8
8296  
8297  static spinlock_t              state_spinlock = SPIN_LOCK_UNLOCKED;
8298 @@ -93,21 +97,26 @@ nfs4_alloc_client(struct in_addr *addr)
8299  {
8300         struct nfs4_client *clp;
8301  
8302 -       if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL))) {
8303 -               memset(clp, 0, sizeof(*clp));
8304 -               memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
8305 -               init_rwsem(&clp->cl_sem);
8306 -               INIT_LIST_HEAD(&clp->cl_state_owners);
8307 -               INIT_LIST_HEAD(&clp->cl_unused);
8308 -               spin_lock_init(&clp->cl_lock);
8309 -               atomic_set(&clp->cl_count, 1);
8310 -               INIT_WORK(&clp->cl_recoverd, nfs4_recover_state, clp);
8311 -               INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
8312 -               INIT_LIST_HEAD(&clp->cl_superblocks);
8313 -               init_waitqueue_head(&clp->cl_waitq);
8314 -               rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
8315 -               clp->cl_state = 1 << NFS4CLNT_NEW;
8316 +       if (nfs_callback_up() < 0)
8317 +               return NULL;
8318 +       if ((clp = kmalloc(sizeof(*clp), GFP_KERNEL)) == NULL) {
8319 +               nfs_callback_down();
8320 +               return NULL;
8321         }
8322 +       memset(clp, 0, sizeof(*clp));
8323 +       memcpy(&clp->cl_addr, addr, sizeof(clp->cl_addr));
8324 +       init_rwsem(&clp->cl_sem);
8325 +       INIT_LIST_HEAD(&clp->cl_delegations);
8326 +       INIT_LIST_HEAD(&clp->cl_state_owners);
8327 +       INIT_LIST_HEAD(&clp->cl_unused);
8328 +       spin_lock_init(&clp->cl_lock);
8329 +       atomic_set(&clp->cl_count, 1);
8330 +       INIT_WORK(&clp->cl_recoverd, nfs4_recover_state, clp);
8331 +       INIT_WORK(&clp->cl_renewd, nfs4_renew_state, clp);
8332 +       INIT_LIST_HEAD(&clp->cl_superblocks);
8333 +       init_waitqueue_head(&clp->cl_waitq);
8334 +       rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS4 client");
8335 +       clp->cl_state = 1 << NFS4CLNT_OK;
8336         return clp;
8337  }
8338  
8339 @@ -130,25 +139,52 @@ nfs4_free_client(struct nfs4_client *clp
8340         if (clp->cl_rpcclient)
8341                 rpc_shutdown_client(clp->cl_rpcclient);
8342         kfree(clp);
8343 +       nfs_callback_down();
8344 +}
8345 +
8346 +static struct nfs4_client *__nfs4_find_client(struct in_addr *addr)
8347 +{
8348 +       struct nfs4_client *clp;
8349 +       list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) {
8350 +               if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0) {
8351 +                       atomic_inc(&clp->cl_count);
8352 +                       return clp;
8353 +               }
8354 +       }
8355 +       return NULL;
8356 +}
8357 +
8358 +struct nfs4_client *nfs4_find_client(struct in_addr *addr)
8359 +{
8360 +       struct nfs4_client *clp;
8361 +       spin_lock(&state_spinlock);
8362 +       clp = __nfs4_find_client(addr);
8363 +       spin_unlock(&state_spinlock);
8364 +       return clp;
8365  }
8366  
8367  struct nfs4_client *
8368  nfs4_get_client(struct in_addr *addr)
8369  {
8370 -       struct nfs4_client *new, *clp = NULL;
8371 +       struct nfs4_client *clp, *new = NULL;
8372  
8373 -       new = nfs4_alloc_client(addr);
8374         spin_lock(&state_spinlock);
8375 -       list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) {
8376 -               if (memcmp(&clp->cl_addr, addr, sizeof(clp->cl_addr)) == 0)
8377 -                       goto found;
8378 +       for (;;) {
8379 +               clp = __nfs4_find_client(addr);
8380 +               if (clp != NULL)
8381 +                       break;
8382 +               clp = new;
8383 +               if (clp != NULL) {
8384 +                       list_add(&clp->cl_servers, &nfs4_clientid_list);
8385 +                       new = NULL;
8386 +                       break;
8387 +               }
8388 +               spin_unlock(&state_spinlock);
8389 +               new = nfs4_alloc_client(addr);
8390 +               spin_lock(&state_spinlock);
8391 +               if (new == NULL)
8392 +                       break;
8393         }
8394 -       if (new)
8395 -               list_add(&new->cl_servers, &nfs4_clientid_list);
8396 -       spin_unlock(&state_spinlock);
8397 -       return new;
8398 -found:
8399 -       atomic_inc(&clp->cl_count);
8400         spin_unlock(&state_spinlock);
8401         if (new)
8402                 nfs4_free_client(new);
8403 @@ -169,6 +205,16 @@ nfs4_put_client(struct nfs4_client *clp)
8404         nfs4_free_client(clp);
8405  }
8406  
8407 +int nfs4_init_client(struct nfs4_client *clp)
8408 +{
8409 +       int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, nfs_callback_tcpport);
8410 +       if (status == 0)
8411 +               status = nfs4_proc_setclientid_confirm(clp);
8412 +       if (status == 0)
8413 +               nfs4_schedule_state_renewal(clp);
8414 +       return status;
8415 +}
8416 +
8417  u32
8418  nfs4_alloc_lockowner_id(struct nfs4_client *clp)
8419  {
8420 @@ -185,7 +231,6 @@ nfs4_client_grab_unused(struct nfs4_clie
8421                 atomic_inc(&sp->so_count);
8422                 sp->so_cred = cred;
8423                 list_move(&sp->so_list, &clp->cl_state_owners);
8424 -               sp->so_generation = clp->cl_generation;
8425                 clp->cl_nunused--;
8426         }
8427         return sp;
8428 @@ -224,6 +269,7 @@ nfs4_alloc_state_owner(void)
8429         init_MUTEX(&sp->so_sema);
8430         sp->so_seqid = 0;                 /* arbitrary */
8431         INIT_LIST_HEAD(&sp->so_states);
8432 +       INIT_LIST_HEAD(&sp->so_delegations);
8433         atomic_set(&sp->so_count, 1);
8434         return sp;
8435  }
8436 @@ -237,8 +283,11 @@ nfs4_unhash_state_owner(struct nfs4_stat
8437         spin_unlock(&clp->cl_lock);
8438  }
8439  
8440 -struct nfs4_state_owner *
8441 -nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
8442 +/*
8443 + * Note: must be called with clp->cl_sem held in order to prevent races
8444 + *       with reboot recovery!
8445 + */
8446 +struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
8447  {
8448         struct nfs4_client *clp = server->nfs4_state;
8449         struct nfs4_state_owner *sp, *new;
8450 @@ -254,23 +303,23 @@ nfs4_get_state_owner(struct nfs_server *
8451                 new->so_client = clp;
8452                 new->so_id = nfs4_alloc_lockowner_id(clp);
8453                 new->so_cred = cred;
8454 -               new->so_generation = clp->cl_generation;
8455                 sp = new;
8456                 new = NULL;
8457         }
8458         spin_unlock(&clp->cl_lock);
8459         if (new)
8460                 kfree(new);
8461 -       if (sp) {
8462 -               if (!test_bit(NFS4CLNT_OK, &clp->cl_state))
8463 -                       nfs4_wait_clnt_recover(server->client, clp);
8464 -       } else
8465 -               put_rpccred(cred);
8466 -       return sp;
8467 +       if (sp != NULL)
8468 +               return sp;
8469 +       put_rpccred(cred);
8470 +       return NULL;
8471  }
8472  
8473 -void
8474 -nfs4_put_state_owner(struct nfs4_state_owner *sp)
8475 +/*
8476 + * Must be called with clp->cl_sem held in order to avoid races
8477 + * with state recovery...
8478 + */
8479 +void nfs4_put_state_owner(struct nfs4_state_owner *sp)
8480  {
8481         struct nfs4_client *clp = sp->so_client;
8482         struct rpc_cred *cred = sp->so_cred;
8483 @@ -330,8 +379,6 @@ __nfs4_find_state(struct inode *inode, s
8484                         continue;
8485                 if ((state->state & mode) != mode)
8486                         continue;
8487 -               /* Add the state to the head of the inode's list */
8488 -               list_move(&state->inode_states, &nfsi->open_states);
8489                 atomic_inc(&state->count);
8490                 if (mode & FMODE_READ)
8491                         state->nreaders++;
8492 @@ -353,8 +400,6 @@ __nfs4_find_state_byowner(struct inode *
8493                 if (state->nreaders == 0 && state->nwriters == 0)
8494                         continue;
8495                 if (state->owner == owner) {
8496 -                       /* Add the state to the head of the inode's list */
8497 -                       list_move(&state->inode_states, &nfsi->open_states);
8498                         atomic_inc(&state->count);
8499                         return state;
8500                 }
8501 @@ -411,51 +456,40 @@ out:
8502         return state;
8503  }
8504  
8505 -static void
8506 -__nfs4_put_open_state(struct nfs4_state *state)
8507 +/*
8508 + * Beware! Caller must be holding exactly one
8509 + * reference to clp->cl_sem and owner->so_sema!
8510 + */
8511 +void nfs4_put_open_state(struct nfs4_state *state)
8512  {
8513         struct inode *inode = state->inode;
8514         struct nfs4_state_owner *owner = state->owner;
8515 -       int status = 0;
8516  
8517 -       if (!atomic_dec_and_lock(&state->count, &inode->i_lock)) {
8518 -               up(&owner->so_sema);
8519 +       if (!atomic_dec_and_lock(&state->count, &inode->i_lock))
8520                 return;
8521 -       }
8522         if (!list_empty(&state->inode_states))
8523                 list_del(&state->inode_states);
8524         spin_unlock(&inode->i_lock);
8525         list_del(&state->open_states);
8526 -       if (state->state != 0) {
8527 -               do {
8528 -                       status = nfs4_do_close(inode, state);
8529 -                       if (!status)
8530 -                               break;
8531 -                       up(&owner->so_sema);
8532 -                       status = nfs4_handle_error(NFS_SERVER(inode), status);
8533 -                       down(&owner->so_sema);
8534 -               } while (!status);
8535 -       }
8536 -       up(&owner->so_sema);
8537 +       BUG_ON (state->state != 0);
8538         nfs4_free_open_state(state);
8539         nfs4_put_state_owner(owner);
8540  }
8541  
8542 -void
8543 -nfs4_put_open_state(struct nfs4_state *state)
8544 -{
8545 -       down(&state->owner->so_sema);
8546 -       __nfs4_put_open_state(state);
8547 -}
8548 -
8549 -void
8550 -nfs4_close_state(struct nfs4_state *state, mode_t mode)
8551 +/*
8552 + * Beware! Caller must be holding no references to clp->cl_sem!
8553 + * of owner->so_sema!
8554 + */
8555 +void nfs4_close_state(struct nfs4_state *state, mode_t mode)
8556  {
8557         struct inode *inode = state->inode;
8558         struct nfs4_state_owner *owner = state->owner;
8559 +       struct nfs4_client *clp = owner->so_client;
8560         int newstate;
8561         int status = 0;
8562  
8563 +       atomic_inc(&owner->so_count);
8564 +       down_read(&clp->cl_sem);
8565         down(&owner->so_sema);
8566         /* Protect against nfs4_find_state() */
8567         spin_lock(&inode->i_lock);
8568 @@ -466,29 +500,24 @@ nfs4_close_state(struct nfs4_state *stat
8569         if (state->nwriters == 0 && state->nreaders == 0)
8570                 list_del_init(&state->inode_states);
8571         spin_unlock(&inode->i_lock);
8572 -       do {
8573 -               newstate = 0;
8574 -               if (state->state == 0)
8575 -                       break;
8576 +       newstate = 0;
8577 +       if (state->state != 0) {
8578                 if (state->nreaders)
8579                         newstate |= FMODE_READ;
8580                 if (state->nwriters)
8581                         newstate |= FMODE_WRITE;
8582                 if (state->state == newstate)
8583 -                       break;
8584 +                       goto out;
8585                 if (newstate != 0)
8586                         status = nfs4_do_downgrade(inode, state, newstate);
8587                 else
8588                         status = nfs4_do_close(inode, state);
8589 -               if (!status) {
8590 -                       state->state = newstate;
8591 -                       break;
8592 -               }
8593 -               up(&owner->so_sema);
8594 -               status = nfs4_handle_error(NFS_SERVER(inode), status);
8595 -               down(&owner->so_sema);
8596 -       } while (!status);
8597 -       __nfs4_put_open_state(state);
8598 +       }
8599 +out:
8600 +       nfs4_put_open_state(state);
8601 +       up(&owner->so_sema);
8602 +       nfs4_put_state_owner(owner);
8603 +       up_read(&clp->cl_sem);
8604  }
8605  
8606  /*
8607 @@ -496,11 +525,11 @@ nfs4_close_state(struct nfs4_state *stat
8608   * that is compatible with current->files
8609   */
8610  static struct nfs4_lock_state *
8611 -__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
8612 +__nfs4_find_lock_state(struct nfs4_state *state, unsigned int pid)
8613  {
8614         struct nfs4_lock_state *pos;
8615         list_for_each_entry(pos, &state->lock_states, ls_locks) {
8616 -               if (pos->ls_owner != fl_owner)
8617 +               if (pos->ls_pid != pid)
8618                         continue;
8619                 atomic_inc(&pos->ls_count);
8620                 return pos;
8621 @@ -509,23 +538,16 @@ __nfs4_find_lock_state(struct nfs4_state
8622  }
8623  
8624  struct nfs4_lock_state *
8625 -nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
8626 +nfs4_find_lock_state(struct nfs4_state *state, unsigned int pid)
8627  {
8628         struct nfs4_lock_state *lsp;
8629         read_lock(&state->state_lock);
8630 -       lsp = __nfs4_find_lock_state(state, fl_owner);
8631 +       lsp = __nfs4_find_lock_state(state, pid);
8632         read_unlock(&state->state_lock);
8633         return lsp;
8634  }
8635  
8636 -/*
8637 - * Return a compatible lock_state. If no initialized lock_state structure
8638 - * exists, return an uninitialized one.
8639 - *
8640 - * The caller must be holding state->lock_sema
8641 - */
8642 -struct nfs4_lock_state *
8643 -nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
8644 +static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, unsigned int pid)
8645  {
8646         struct nfs4_lock_state *lsp;
8647         struct nfs4_client *clp = state->owner->so_client;
8648 @@ -533,12 +555,12 @@ nfs4_alloc_lock_state(struct nfs4_state 
8649         lsp = kmalloc(sizeof(*lsp), GFP_KERNEL);
8650         if (lsp == NULL)
8651                 return NULL;
8652 +       lsp->flags = 0;
8653         lsp->ls_seqid = 0;      /* arbitrary */
8654         lsp->ls_id = -1; 
8655         memset(lsp->ls_stateid.data, 0, sizeof(lsp->ls_stateid.data));
8656         atomic_set(&lsp->ls_count, 1);
8657 -       lsp->ls_owner = fl_owner;
8658 -       lsp->ls_parent = state;
8659 +       lsp->ls_pid = pid;
8660         INIT_LIST_HEAD(&lsp->ls_locks);
8661         spin_lock(&clp->cl_lock);
8662         lsp->ls_id = nfs4_alloc_lockowner_id(clp);
8663 @@ -547,16 +569,32 @@ nfs4_alloc_lock_state(struct nfs4_state 
8664  }
8665  
8666  /*
8667 + * Return a compatible lock_state. If no initialized lock_state structure
8668 + * exists, return an uninitialized one.
8669 + *
8670 + * The caller must be holding state->lock_sema and clp->cl_sem
8671 + */
8672 +struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, unsigned int pid)
8673 +{
8674 +       struct nfs4_lock_state * lsp;
8675 +       
8676 +       lsp = nfs4_find_lock_state(state, pid);
8677 +       if (lsp == NULL)
8678 +               lsp = nfs4_alloc_lock_state(state, pid);
8679 +       return lsp;
8680 +}
8681 +
8682 +/*
8683   * Byte-range lock aware utility to initialize the stateid of read/write
8684   * requests.
8685   */
8686  void
8687 -nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner)
8688 +nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, unsigned int pid)
8689  {
8690         if (test_bit(LK_STATE_IN_USE, &state->flags)) {
8691                 struct nfs4_lock_state *lsp;
8692  
8693 -               lsp = nfs4_find_lock_state(state, fl_owner);
8694 +               lsp = nfs4_find_lock_state(state, pid);
8695                 if (lsp) {
8696                         memcpy(dst, &lsp->ls_stateid, sizeof(*dst));
8697                         nfs4_put_lock_state(lsp);
8698 @@ -567,13 +605,14 @@ nfs4_copy_stateid(nfs4_stateid *dst, str
8699  }
8700  
8701  /*
8702 -* Called with state->lock_sema held.
8703 +* Called with state->lock_sema and clp->cl_sem held.
8704  */
8705 -void
8706 -nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp)
8707 +void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *lsp)
8708  {
8709 -       if (status == NFS_OK || seqid_mutating_err(-status))
8710 +       if (status == NFS_OK || seqid_mutating_err(-status)) {
8711                 lsp->ls_seqid++;
8712 +               lsp->flags |= NFS_LOCK_INITIALIZED;
8713 +       }
8714  }
8715  
8716  /* 
8717 @@ -598,12 +637,11 @@ nfs4_check_unlock(struct file_lock *fl, 
8718   * Post an initialized lock_state on the state->lock_states list.
8719   */
8720  void
8721 -nfs4_notify_setlk(struct inode *inode, struct file_lock *request, struct nfs4_lock_state *lsp)
8722 +nfs4_notify_setlk(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp)
8723  {
8724 -       struct nfs4_state *state = lsp->ls_parent;
8725 -
8726         if (!list_empty(&lsp->ls_locks))
8727                 return;
8728 +       atomic_inc(&lsp->ls_count);
8729         write_lock(&state->state_lock);
8730         list_add(&lsp->ls_locks, &state->lock_states);
8731         set_bit(LK_STATE_IN_USE, &state->flags);
8732 @@ -620,15 +658,15 @@ nfs4_notify_setlk(struct inode *inode, s
8733   *
8734   */
8735  void
8736 -nfs4_notify_unlck(struct inode *inode, struct file_lock *request, struct nfs4_lock_state *lsp)
8737 +nfs4_notify_unlck(struct nfs4_state *state, struct file_lock *request, struct nfs4_lock_state *lsp)
8738  {
8739 -       struct nfs4_state *state = lsp->ls_parent;
8740 +       struct inode *inode = state->inode;
8741         struct file_lock *fl;
8742  
8743         for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
8744                 if (!(fl->fl_flags & FL_POSIX))
8745                         continue;
8746 -               if (fl->fl_owner != lsp->ls_owner)
8747 +               if (fl->fl_pid != lsp->ls_pid)
8748                         continue;
8749                 /* Exit if we find at least one lock which is not consumed */
8750                 if (nfs4_check_unlock(fl,request) == 0)
8751 @@ -640,6 +678,7 @@ nfs4_notify_unlck(struct inode *inode, s
8752         if (list_empty(&state->lock_states))
8753                 clear_bit(LK_STATE_IN_USE, &state->flags);
8754         write_unlock(&state->state_lock);
8755 +       nfs4_put_lock_state(lsp);
8756  }
8757  
8758  /*
8759 @@ -651,20 +690,18 @@ nfs4_put_lock_state(struct nfs4_lock_sta
8760  {
8761         if (!atomic_dec_and_test(&lsp->ls_count))
8762                 return;
8763 -       if (!list_empty(&lsp->ls_locks))
8764 -               return;
8765 +       BUG_ON (!list_empty(&lsp->ls_locks));
8766         kfree(lsp);
8767  }
8768  
8769  /*
8770 -* Called with sp->so_sema held.
8771 +* Called with sp->so_sema and clp->cl_sem held.
8772  *
8773  * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
8774  * failed with a seqid incrementing error -
8775  * see comments nfs_fs.h:seqid_mutating_error()
8776  */
8777 -void
8778 -nfs4_increment_seqid(int status, struct nfs4_state_owner *sp)
8779 +void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp)
8780  {
8781         if (status == NFS_OK || seqid_mutating_err(-status))
8782                 sp->so_seqid++;
8783 @@ -693,21 +730,14 @@ nfs4_recover_state(void *data)
8784  
8785         init_completion(&args.complete);
8786  
8787 -       down_read(&clp->cl_sem);
8788 -       if (test_and_set_bit(NFS4CLNT_SETUP_STATE, &clp->cl_state))
8789 -               goto out_failed;
8790         if (kernel_thread(reclaimer, &args, CLONE_KERNEL) < 0)
8791                 goto out_failed_clear;
8792         wait_for_completion(&args.complete);
8793         return;
8794  out_failed_clear:
8795 -       smp_mb__before_clear_bit();
8796 -       clear_bit(NFS4CLNT_SETUP_STATE, &clp->cl_state);
8797 -       smp_mb__after_clear_bit();
8798 +       set_bit(NFS4CLNT_OK, &clp->cl_state);
8799         wake_up_all(&clp->cl_waitq);
8800         rpc_wake_up(&clp->cl_rpcwaitq);
8801 -out_failed:
8802 -       up_read(&clp->cl_sem);
8803  }
8804  
8805  /*
8806 @@ -718,24 +748,66 @@ nfs4_schedule_state_recovery(struct nfs4
8807  {
8808         if (!clp)
8809                 return;
8810 -       smp_mb__before_clear_bit();
8811 -       clear_bit(NFS4CLNT_OK, &clp->cl_state);
8812 -       smp_mb__after_clear_bit();
8813 -       schedule_work(&clp->cl_recoverd);
8814 +       if (test_and_clear_bit(NFS4CLNT_OK, &clp->cl_state))
8815 +               schedule_work(&clp->cl_recoverd);
8816  }
8817  
8818 -static int
8819 -nfs4_reclaim_open_state(struct nfs4_state_owner *sp)
8820 +static int nfs4_reclaim_locks(struct nfs4_state *state)
8821 +{
8822 +       struct inode *inode = state->inode;
8823 +       struct file_lock *fl;
8824 +       int status = 0;
8825 +
8826 +       for (fl = inode->i_flock; fl != 0; fl = fl->fl_next) {
8827 +               if (!(fl->fl_flags & FL_POSIX))
8828 +                       continue;
8829 +               if (((struct nfs_open_context *)fl->fl_file->private_data)->state != state)
8830 +                       continue;
8831 +               status = nfs4_lock_reclaim(state, fl);
8832 +               if (status >= 0)
8833 +                       continue;
8834 +               switch (status) {
8835 +                       default:
8836 +                               printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
8837 +                                               __FUNCTION__, status);
8838 +                       case -NFS4ERR_EXPIRED:
8839 +                       case -NFS4ERR_NO_GRACE:
8840 +                       case -NFS4ERR_RECLAIM_BAD:
8841 +                       case -NFS4ERR_RECLAIM_CONFLICT:
8842 +                               /* kill_proc(fl->fl_pid, SIGLOST, 1); */
8843 +                               break;
8844 +                       case -NFS4ERR_STALE_CLIENTID:
8845 +                               goto out_err;
8846 +               }
8847 +       }
8848 +       return 0;
8849 +out_err:
8850 +       return status;
8851 +}
8852 +
8853 +static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp)
8854  {
8855         struct nfs4_state *state;
8856 +       struct nfs4_lock_state *lock;
8857         int status = 0;
8858  
8859         list_for_each_entry(state, &sp->so_states, open_states) {
8860                 if (state->state == 0)
8861                         continue;
8862                 status = nfs4_open_reclaim(sp, state);
8863 -               if (status >= 0)
8864 +               list_for_each_entry(lock, &state->lock_states, ls_locks)
8865 +                       lock->flags &= ~NFS_LOCK_INITIALIZED;
8866 +               if (status >= 0) {
8867 +                       status = nfs4_reclaim_locks(state);
8868 +                       if (status < 0)
8869 +                               goto out_err;
8870 +                       list_for_each_entry(lock, &state->lock_states, ls_locks) {
8871 +                               if (!(lock->flags & NFS_LOCK_INITIALIZED))
8872 +                                       printk("%s: Lock reclaim failed!\n",
8873 +                                                       __FUNCTION__);
8874 +                       }
8875                         continue;
8876 +               }
8877                 switch (status) {
8878                         default:
8879                                 printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
8880 @@ -762,75 +834,55 @@ out_err:
8881         return status;
8882  }
8883  
8884 -static int
8885 -reclaimer(void *ptr)
8886 +static int reclaimer(void *ptr)
8887  {
8888         struct reclaimer_args *args = (struct reclaimer_args *)ptr;
8889         struct nfs4_client *clp = args->clp;
8890         struct nfs4_state_owner *sp;
8891 -       int generation;
8892         int status;
8893  
8894         daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr));
8895         allow_signal(SIGKILL);
8896  
8897 +       atomic_inc(&clp->cl_count);
8898         complete(&args->complete);
8899  
8900 +       /* Ensure exclusive access to NFSv4 state */
8901 +       lock_kernel();
8902 +       down_write(&clp->cl_sem);
8903         /* Are there any NFS mounts out there? */
8904         if (list_empty(&clp->cl_superblocks))
8905                 goto out;
8906 -       if (!test_bit(NFS4CLNT_NEW, &clp->cl_state)) {
8907 -               status = nfs4_proc_renew(clp);
8908 -               if (status == 0) {
8909 -                       set_bit(NFS4CLNT_OK, &clp->cl_state);
8910 -                       goto out;
8911 -               }
8912 -       }
8913 -       status = nfs4_proc_setclientid(clp, 0, 0);
8914 -       if (status)
8915 -               goto out_error;
8916 -       status = nfs4_proc_setclientid_confirm(clp);
8917 +restart_loop:
8918 +       status = nfs4_proc_renew(clp);
8919 +       if (status == 0)
8920 +               goto out;
8921 +       status = nfs4_init_client(clp);
8922         if (status)
8923                 goto out_error;
8924 -       generation = ++(clp->cl_generation);
8925 -       clear_bit(NFS4CLNT_NEW, &clp->cl_state);
8926 -       set_bit(NFS4CLNT_OK, &clp->cl_state);
8927 -       up_read(&clp->cl_sem);
8928 -       nfs4_schedule_state_renewal(clp);
8929 -restart_loop:
8930 -       spin_lock(&clp->cl_lock);
8931 +       /* Mark all delagations for reclaim */
8932 +       nfs_delegation_mark_reclaim(clp);
8933 +       /* Note: list is protected by exclusive lock on cl->cl_sem */
8934         list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
8935 -               if (sp->so_generation - generation >= 0)
8936 -                       continue;
8937 -               atomic_inc(&sp->so_count);
8938 -               spin_unlock(&clp->cl_lock);
8939 -               down(&sp->so_sema);
8940 -               if (sp->so_generation - generation < 0) {
8941 -                       smp_rmb();
8942 -                       sp->so_generation = clp->cl_generation;
8943 -                       status = nfs4_reclaim_open_state(sp);
8944 -               }
8945 -               up(&sp->so_sema);
8946 -               nfs4_put_state_owner(sp);
8947 +               status = nfs4_reclaim_open_state(sp);
8948                 if (status < 0) {
8949                         if (status == -NFS4ERR_STALE_CLIENTID)
8950 -                               nfs4_schedule_state_recovery(clp);
8951 -                       goto out;
8952 +                               goto restart_loop;
8953 +                       goto out_error;
8954                 }
8955 -               goto restart_loop;
8956         }
8957 -       spin_unlock(&clp->cl_lock);
8958 +       nfs_delegation_reap_unclaimed(clp);
8959  out:
8960 -       smp_mb__before_clear_bit();
8961 -       clear_bit(NFS4CLNT_SETUP_STATE, &clp->cl_state);
8962 -       smp_mb__after_clear_bit();
8963 +       set_bit(NFS4CLNT_OK, &clp->cl_state);
8964 +       up_write(&clp->cl_sem);
8965 +       unlock_kernel();
8966         wake_up_all(&clp->cl_waitq);
8967         rpc_wake_up(&clp->cl_rpcwaitq);
8968 +       nfs4_put_client(clp);
8969         return 0;
8970  out_error:
8971 -       printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u\n",
8972 -                               NIPQUAD(clp->cl_addr.s_addr));
8973 -       up_read(&clp->cl_sem);
8974 +       printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n",
8975 +                               NIPQUAD(clp->cl_addr.s_addr), -status);
8976         goto out;
8977  }
8978  
8979 --- linux-2.6.7/fs/nfs/inode.c.lsec     2004-06-15 23:19:44.000000000 -0600
8980 +++ linux-2.6.7/fs/nfs/inode.c  2005-03-23 14:28:22.818580744 -0700
8981 @@ -39,6 +39,8 @@
8982  #include <asm/system.h>
8983  #include <asm/uaccess.h>
8984  
8985 +#include "delegation.h"
8986 +
8987  #define NFSDBG_FACILITY                NFSDBG_VFS
8988  #define NFS_PARANOIA 1
8989  
8990 @@ -123,8 +125,9 @@ nfs_delete_inode(struct inode * inode)
8991  {
8992         dprintk("NFS: delete_inode(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
8993  
8994 +       nfs_wb_all(inode);
8995         /*
8996 -        * The following can never actually happen...
8997 +        * The following should never happen...
8998          */
8999         if (nfs_have_writebacks(inode)) {
9000                 printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
9001 @@ -133,18 +136,15 @@ nfs_delete_inode(struct inode * inode)
9002         clear_inode(inode);
9003  }
9004  
9005 -/*
9006 - * For the moment, the only task for the NFS clear_inode method is to
9007 - * release the mmap credential
9008 - */
9009  static void
9010  nfs_clear_inode(struct inode *inode)
9011  {
9012         struct nfs_inode *nfsi = NFS_I(inode);
9013 -       struct rpc_cred *cred = nfsi->mm_cred;
9014 +       struct rpc_cred *cred;
9015  
9016 -       if (cred)
9017 -               put_rpccred(cred);
9018 +       nfs4_zap_acl_attr(inode);
9019 +       nfs_wb_all(inode);
9020 +       BUG_ON (!list_empty(&nfsi->open_files));
9021         cred = nfsi->cache_access.cred;
9022         if (cred)
9023                 put_rpccred(cred);
9024 @@ -704,7 +704,7 @@ nfs_fhget(struct super_block *sb, struct
9025                 /* Why so? Because we want revalidate for devices/FIFOs, and
9026                  * that's precisely what we have in nfs_file_inode_operations.
9027                  */
9028 -               inode->i_op = &nfs_file_inode_operations;
9029 +               inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops;
9030                 if (S_ISREG(inode->i_mode)) {
9031                         inode->i_fop = &nfs_file_operations;
9032                         inode->i_data.a_ops = &nfs_file_aops;
9033 @@ -859,53 +859,114 @@ int nfs_getattr(struct vfsmount *mnt, st
9034         return err;
9035  }
9036  
9037 +struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred)
9038 +{
9039 +       struct nfs_open_context *ctx;
9040 +
9041 +       ctx = (struct nfs_open_context *)kmalloc(sizeof(*ctx), GFP_KERNEL);
9042 +       if (ctx != NULL) {
9043 +               atomic_set(&ctx->count, 1);
9044 +               ctx->dentry = dget(dentry);
9045 +               ctx->cred = get_rpccred(cred);
9046 +               ctx->state = NULL;
9047 +               ctx->pid = current->tgid;
9048 +               ctx->error = 0;
9049 +               init_waitqueue_head(&ctx->waitq);
9050 +       }
9051 +       return ctx;
9052 +}
9053 +
9054 +struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx)
9055 +{
9056 +       if (ctx != NULL)
9057 +               atomic_inc(&ctx->count);
9058 +       return ctx;
9059 +}
9060 +
9061 +void put_nfs_open_context(struct nfs_open_context *ctx)
9062 +{
9063 +       if (atomic_dec_and_test(&ctx->count)) {
9064 +               if (ctx->state != NULL)
9065 +                       nfs4_close_state(ctx->state, ctx->mode);
9066 +               if (ctx->cred != NULL)
9067 +                       put_rpccred(ctx->cred);
9068 +               dput(ctx->dentry);
9069 +               kfree(ctx);
9070 +       }
9071 +}
9072 +
9073  /*
9074   * Ensure that mmap has a recent RPC credential for use when writing out
9075   * shared pages
9076   */
9077 -void
9078 -nfs_set_mmcred(struct inode *inode, struct rpc_cred *cred)
9079 +void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx)
9080 +{
9081 +       struct inode *inode = filp->f_dentry->d_inode;
9082 +       struct nfs_inode *nfsi = NFS_I(inode);
9083 +
9084 +       filp->private_data = get_nfs_open_context(ctx);
9085 +       spin_lock(&inode->i_lock);
9086 +       list_add(&ctx->list, &nfsi->open_files);
9087 +       spin_unlock(&inode->i_lock);
9088 +}
9089 +
9090 +struct nfs_open_context *nfs_find_open_context(struct inode *inode, int mode)
9091 +{
9092 +       struct nfs_inode *nfsi = NFS_I(inode);
9093 +       struct nfs_open_context *pos, *ctx = NULL;
9094 +
9095 +       spin_lock(&inode->i_lock);
9096 +       list_for_each_entry(pos, &nfsi->open_files, list) {
9097 +               if ((pos->mode & mode) == mode) {
9098 +                       ctx = get_nfs_open_context(pos);
9099 +                       break;
9100 +               }
9101 +       }
9102 +       spin_unlock(&inode->i_lock);
9103 +       return ctx;
9104 +}
9105 +
9106 +void nfs_file_clear_open_context(struct file *filp)
9107  {
9108 -       struct rpc_cred **p = &NFS_I(inode)->mm_cred,
9109 -                       *oldcred = *p;
9110 +       struct inode *inode = filp->f_dentry->d_inode;
9111 +       struct nfs_open_context *ctx = (struct nfs_open_context *)filp->private_data;
9112  
9113 -       *p = get_rpccred(cred);
9114 -       if (oldcred)
9115 -               put_rpccred(oldcred);
9116 +       if (ctx) {
9117 +               filp->private_data = NULL;
9118 +               spin_lock(&inode->i_lock);
9119 +               list_del(&ctx->list);
9120 +               spin_unlock(&inode->i_lock);
9121 +               put_nfs_open_context(ctx);
9122 +       }
9123  }
9124  
9125  /*
9126 - * These are probably going to contain hooks for
9127 - * allocating and releasing RPC credentials for
9128 - * the file. I'll have to think about Tronds patch
9129 - * a bit more..
9130 + * These allocate and release file read/write context information.
9131   */
9132  int nfs_open(struct inode *inode, struct file *filp)
9133  {
9134 -       struct rpc_auth *auth;
9135 +       struct nfs_open_context *ctx;
9136         struct rpc_cred *cred;
9137  
9138 -       auth = NFS_CLIENT(inode)->cl_auth;
9139 -       cred = rpcauth_lookupcred(auth, 0);
9140 -       filp->private_data = cred;
9141 -       if ((filp->f_mode & FMODE_WRITE) != 0) {
9142 -               nfs_set_mmcred(inode, cred);
9143 +       if ((cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0)) == NULL)
9144 +               return -ENOMEM;
9145 +       ctx = alloc_nfs_open_context(filp->f_dentry, cred);
9146 +       put_rpccred(cred);
9147 +       if (ctx == NULL)
9148 +               return -ENOMEM;
9149 +       ctx->mode = filp->f_mode;
9150 +       nfs_file_set_open_context(filp, ctx);
9151 +       put_nfs_open_context(ctx);
9152 +       if ((filp->f_mode & FMODE_WRITE) != 0)
9153                 nfs_begin_data_update(inode);
9154 -       }
9155         return 0;
9156  }
9157  
9158  int nfs_release(struct inode *inode, struct file *filp)
9159  {
9160 -       struct rpc_cred *cred;
9161 -
9162 -       lock_kernel();
9163         if ((filp->f_mode & FMODE_WRITE) != 0)
9164                 nfs_end_data_update(inode);
9165 -       cred = nfs_file_cred(filp);
9166 -       if (cred)
9167 -               put_rpccred(cred);
9168 -       unlock_kernel();
9169 +       nfs_file_clear_open_context(filp);
9170         return 0;
9171  }
9172  
9173 @@ -1002,6 +1063,30 @@ out:
9174         return status;
9175  }
9176  
9177 +int nfs_attribute_timeout(struct inode *inode)
9178 +{
9179 +       struct nfs_inode *nfsi = NFS_I(inode);
9180 +
9181 +       if (nfs_have_delegation(inode, FMODE_READ))
9182 +               return 0;
9183 +       return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
9184 +}
9185 +
9186 +/**
9187 + * nfs_revalidate_inode - Revalidate the inode attributes
9188 + * @server - pointer to nfs_server struct
9189 + * @inode - pointer to inode struct
9190 + *
9191 + * Updates inode attribute information by retrieving the data from the server.
9192 + */
9193 +int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
9194 +{
9195 +       if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
9196 +                       && !nfs_attribute_timeout(inode))
9197 +               return NFS_STALE(inode) ? -ESTALE : 0;
9198 +       return __nfs_revalidate_inode(server, inode);
9199 +}
9200 +
9201  /**
9202   * nfs_begin_data_update
9203   * @inode - pointer to inode
9204 @@ -1023,11 +1108,13 @@ void nfs_end_data_update(struct inode *i
9205  {
9206         struct nfs_inode *nfsi = NFS_I(inode);
9207  
9208 -       /* Mark the attribute cache for revalidation */
9209 -       nfsi->flags |= NFS_INO_INVALID_ATTR;
9210 -       /* Directories and symlinks: invalidate page cache too */
9211 -       if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
9212 -               nfsi->flags |= NFS_INO_INVALID_DATA;
9213 +       if (!nfs_have_delegation(inode, FMODE_READ)) {
9214 +               /* Mark the attribute cache for revalidation */
9215 +               nfsi->flags |= NFS_INO_INVALID_ATTR;
9216 +               /* Directories and symlinks: invalidate page cache too */
9217 +               if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
9218 +                       nfsi->flags |= NFS_INO_INVALID_DATA;
9219 +       }
9220         nfsi->cache_change_attribute ++;
9221         atomic_dec(&nfsi->data_updates);
9222  }
9223 @@ -1068,6 +1155,10 @@ int nfs_refresh_inode(struct inode *inod
9224         loff_t cur_size, new_isize;
9225         int data_unstable;
9226  
9227 +       /* Do we hold a delegation? */
9228 +       if (nfs_have_delegation(inode, FMODE_READ))
9229 +               return 0;
9230 +
9231         /* Are we in the process of updating data on the server? */
9232         data_unstable = nfs_caches_unstable(inode);
9233  
9234 @@ -1240,6 +1331,7 @@ static int nfs_update_inode(struct inode
9235         inode->i_nlink = fattr->nlink;
9236         inode->i_uid = fattr->uid;
9237         inode->i_gid = fattr->gid;
9238 +       nfs4_zap_acl_attr(inode);
9239  
9240         if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
9241                 /*
9242 @@ -1265,7 +1357,8 @@ static int nfs_update_inode(struct inode
9243         if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
9244                                 || S_ISLNK(inode->i_mode)))
9245                 invalid &= ~NFS_INO_INVALID_DATA;
9246 -       nfsi->flags |= invalid;
9247 +       if (!nfs_have_delegation(inode, FMODE_READ))
9248 +               nfsi->flags |= invalid;
9249  
9250         return 0;
9251   out_changed:
9252 @@ -1400,6 +1493,52 @@ static struct file_system_type nfs_fs_ty
9253  
9254  #ifdef CONFIG_NFS_V4
9255  
9256 +#define XATTR_NAME_NFSV4_ACL "system.nfs4_acl"
9257 +
9258 +int
9259 +nfs_setxattr(struct dentry *dentry, const char *key, const void *buf,
9260 +               size_t buflen, int flags)
9261 +{
9262 +       struct inode *inode = dentry->d_inode;
9263 +
9264 +       if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
9265 +               return -EINVAL;
9266 +
9267 +        if (!S_ISREG(inode->i_mode) &&
9268 +            (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
9269 +                return -EPERM;
9270 +
9271 +       return nfs4_proc_set_acl(inode, buf, buflen);
9272 +}
9273 +
9274 +/* The getxattr man page suggests returning -ENODATA for unknown attributes,
9275 + * and that's what we'll do for e.g. user attributes that haven't been set.
9276 + * But we'll follow ext2/ext3's lead by returning -EOPNOTSUPP for unsupported
9277 + * attributes in kernel-managed attribute namespaces. */
9278 +ssize_t
9279 +nfs_getxattr(struct dentry *dentry, const char *key, void *buf,
9280 +               size_t buflen)
9281 +{
9282 +       struct inode *inode = dentry->d_inode;
9283 +
9284 +       if (strcmp(key, XATTR_NAME_NFSV4_ACL) != 0)
9285 +               return -EOPNOTSUPP;
9286 +
9287 +       return nfs4_proc_get_acl(inode, buf, buflen);
9288 +}
9289 +
9290 +ssize_t
9291 +nfs_listxattr(struct dentry *dentry, char *buf, size_t buflen)
9292 +{
9293 +       ssize_t len = strlen(XATTR_NAME_NFSV4_ACL) + 1;
9294 +
9295 +       if (buf && buflen < len)
9296 +               return -ERANGE;
9297 +       if (buf)
9298 +               memcpy(buf, XATTR_NAME_NFSV4_ACL, len);
9299 +       return len;
9300 +}
9301 +
9302  static void nfs4_clear_inode(struct inode *);
9303  
9304  static struct super_operations nfs4_sops = { 
9305 @@ -1423,6 +1562,12 @@ static void nfs4_clear_inode(struct inod
9306  {
9307         struct nfs_inode *nfsi = NFS_I(inode);
9308  
9309 +       /* If we are holding a delegation, return it! */
9310 +       if (nfsi->delegation != NULL)
9311 +               nfs_inode_return_delegation(inode);
9312 +       /* First call standard NFS clear_inode() code */
9313 +       nfs_clear_inode(inode);
9314 +       /* Now clear out any remaining state */
9315         while (!list_empty(&nfsi->open_states)) {
9316                 struct nfs4_state *state;
9317                 
9318 @@ -1437,8 +1582,6 @@ static void nfs4_clear_inode(struct inod
9319                 BUG_ON(atomic_read(&state->count) != 1);
9320                 nfs4_close_state(state, state->state);
9321         }
9322 -       /* Now call standard NFS clear_inode() code */
9323 -       nfs_clear_inode(inode);
9324  }
9325  
9326  
9327 @@ -1536,8 +1679,19 @@ static int nfs4_fill_super(struct super_
9328                 memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
9329                 nfs_idmap_new(clp);
9330         }
9331 -       if (list_empty(&clp->cl_superblocks))
9332 -               clear_bit(NFS4CLNT_OK, &clp->cl_state);
9333 +       /* Fire up rpciod if not yet running */
9334 +       if (rpciod_up() != 0) {
9335 +               printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
9336 +               goto out_fail;
9337 +       }
9338 +
9339 +       if (list_empty(&clp->cl_superblocks)) {
9340 +               err = nfs4_init_client(clp);
9341 +               if (err != 0) {
9342 +                       up_write(&clp->cl_sem);
9343 +                       goto out_rpciod;
9344 +               }
9345 +       }
9346         list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
9347         clnt = rpc_clone_client(clp->cl_rpcclient);
9348         if (!IS_ERR(clnt))
9349 @@ -1567,17 +1721,10 @@ static int nfs4_fill_super(struct super_
9350                 }
9351         }
9352  
9353 -       /* Fire up rpciod if not yet running */
9354 -       if (rpciod_up() != 0) {
9355 -               printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
9356 -               goto out_shutdown;
9357 -       }
9358 -
9359         sb->s_op = &nfs4_sops;
9360         err = nfs_sb_init(sb, authflavour);
9361         if (err == 0)
9362                 return 0;
9363 -       rpciod_down();
9364  out_shutdown:
9365         rpc_shutdown_client(server->client);
9366  out_remove_list:
9367 @@ -1585,6 +1732,8 @@ out_remove_list:
9368         list_del_init(&server->nfs4_siblings);
9369         up_write(&server->nfs4_state->cl_sem);
9370         destroy_nfsv4_state(server);
9371 +out_rpciod:
9372 +       rpciod_down();
9373  out_fail:
9374         if (clp)
9375                 nfs4_put_client(clp);
9376 @@ -1709,22 +1858,31 @@ out_free:
9377         return s;
9378  }
9379  
9380 +static void nfs4_kill_super(struct super_block *sb)
9381 +{
9382 +       nfs_return_all_delegations(sb);
9383 +       nfs_kill_super(sb);
9384 +}
9385 +
9386  static struct file_system_type nfs4_fs_type = {
9387         .owner          = THIS_MODULE,
9388         .name           = "nfs4",
9389         .get_sb         = nfs4_get_sb,
9390 -       .kill_sb        = nfs_kill_super,
9391 +       .kill_sb        = nfs4_kill_super,
9392         .fs_flags       = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
9393  };
9394  
9395 -#define nfs4_zero_state(nfsi) \
9396 +#define nfs4_init_once(nfsi) \
9397         do { \
9398                 INIT_LIST_HEAD(&(nfsi)->open_states); \
9399 +               nfsi->delegation = NULL; \
9400 +               nfsi->delegation_state = 0; \
9401 +               init_rwsem(&nfsi->rwsem); \
9402         } while(0)
9403  #define register_nfs4fs() register_filesystem(&nfs4_fs_type)
9404  #define unregister_nfs4fs() unregister_filesystem(&nfs4_fs_type)
9405  #else
9406 -#define nfs4_zero_state(nfsi) \
9407 +#define nfs4_init_once(nfsi) \
9408         do { } while (0)
9409  #define register_nfs4fs() (0)
9410  #define unregister_nfs4fs()
9411 @@ -1746,8 +1904,8 @@ static struct inode *nfs_alloc_inode(str
9412         if (!nfsi)
9413                 return NULL;
9414         nfsi->flags = 0;
9415 -       nfsi->mm_cred = NULL;
9416 -       nfs4_zero_state(nfsi);
9417 +       nfsi->acl_len = 0;
9418 +       nfsi->acl = NULL;
9419         return &nfsi->vfs_inode;
9420  }
9421  
9422 @@ -1765,12 +1923,14 @@ static void init_once(void * foo, kmem_c
9423                 inode_init_once(&nfsi->vfs_inode);
9424                 INIT_LIST_HEAD(&nfsi->dirty);
9425                 INIT_LIST_HEAD(&nfsi->commit);
9426 +               INIT_LIST_HEAD(&nfsi->open_files);
9427                 INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
9428                 atomic_set(&nfsi->data_updates, 0);
9429                 nfsi->ndirty = 0;
9430                 nfsi->ncommit = 0;
9431                 nfsi->npages = 0;
9432                 init_waitqueue_head(&nfsi->nfs_i_wait);
9433 +               nfs4_init_once(nfsi);
9434         }
9435  }
9436   
9437 --- linux-2.6.7/fs/nfs/dir.c.lsec       2004-06-15 23:19:23.000000000 -0600
9438 +++ linux-2.6.7/fs/nfs/dir.c    2005-03-23 14:28:22.701598528 -0700
9439 @@ -32,6 +32,8 @@
9440  #include <linux/smp_lock.h>
9441  #include <linux/namei.h>
9442  
9443 +#include "delegation.h"
9444 +
9445  #define NFS_PARANOIA 1
9446  /* #define NFS_DEBUG_VERBOSE 1 */
9447  
9448 @@ -88,6 +90,9 @@ struct inode_operations nfs4_dir_inode_o
9449         .permission     = nfs_permission,
9450         .getattr        = nfs_getattr,
9451         .setattr        = nfs_setattr,
9452 +       .getxattr       = nfs_getxattr,
9453 +       .setxattr       = nfs_setxattr,
9454 +       .listxattr      = nfs_listxattr,
9455  };
9456  
9457  #endif /* CONFIG_NFS_V4 */
9458 @@ -850,22 +855,22 @@ static int nfs_open_revalidate(struct de
9459         unsigned long verifier;
9460         int openflags, ret = 0;
9461  
9462 -       /* NFS only supports OPEN for regular files */
9463 -       if (inode && !S_ISREG(inode->i_mode))
9464 -               goto no_open;
9465         parent = dget_parent(dentry);
9466         dir = parent->d_inode;
9467         if (!is_atomic_open(dir, nd))
9468                 goto no_open;
9469 +       /* We can't create new files in nfs_open_revalidate(), so we
9470 +        * optimize away revalidation of negative dentries.
9471 +        */
9472 +       if (inode == NULL)
9473 +               goto out;
9474 +       /* NFS only supports OPEN on regular files */
9475 +       if (!S_ISREG(inode->i_mode))
9476 +               goto no_open;
9477         openflags = nd->intent.open.flags;
9478 -       if (openflags & O_CREAT) {
9479 -               /* If this is a negative dentry, just drop it */
9480 -               if (!inode)
9481 -                       goto out;
9482 -               /* If this is exclusive open, just revalidate */
9483 -               if (openflags & O_EXCL)
9484 -                       goto no_open;
9485 -       }
9486 +       /* We cannot do exclusive creation on a positive dentry */
9487 +       if ((openflags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL))
9488 +               goto no_open;
9489         /* We can't create new files, or truncate existing ones here */
9490         openflags &= ~(O_CREAT|O_TRUNC);
9491  
9492 @@ -887,6 +892,8 @@ out:
9493         return ret;
9494  no_open:
9495         dput(parent);
9496 +       if (inode != NULL && nfs_have_delegation(inode, FMODE_READ))
9497 +               return 1;
9498         return nfs_lookup_revalidate(dentry, nd);
9499  }
9500  #endif /* CONFIG_NFSV4 */
9501 @@ -1299,19 +1306,6 @@ nfs_symlink(struct inode *dir, struct de
9502         dfprintk(VFS, "NFS: symlink(%s/%ld, %s, %s)\n", dir->i_sb->s_id,
9503                 dir->i_ino, dentry->d_name.name, symname);
9504  
9505 -       error = -ENAMETOOLONG;
9506 -       switch (NFS_PROTO(dir)->version) {
9507 -               case 2:
9508 -                       if (strlen(symname) > NFS2_MAXPATHLEN)
9509 -                               goto out;
9510 -                       break;
9511 -               case 3:
9512 -                       if (strlen(symname) > NFS3_MAXPATHLEN)
9513 -                               goto out;
9514 -               default:
9515 -                       break;
9516 -       }
9517 -
9518  #ifdef NFS_PARANOIA
9519  if (dentry->d_inode)
9520  printk("nfs_proc_symlink: %s/%s not negative!\n",
9521 @@ -1341,8 +1335,6 @@ dentry->d_parent->d_name.name, dentry->d
9522                 d_drop(dentry);
9523         }
9524         unlock_kernel();
9525 -
9526 -out:
9527         return error;
9528  }
9529  
9530 @@ -1498,10 +1490,56 @@ out:
9531         return error;
9532  }
9533  
9534 -int
9535 -nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
9536 +int nfs_access_get_cached(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res)
9537 +{
9538 +       struct nfs_access_entry *cache = &NFS_I(inode)->cache_access;
9539 +
9540 +       if (cache->cred != cred
9541 +                       || time_after(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))
9542 +                       || (NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR))
9543 +               return -ENOENT;
9544 +       memcpy(res, cache, sizeof(*res));
9545 +       return 0;
9546 +}
9547 +
9548 +void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set)
9549 +{
9550 +       struct nfs_access_entry *cache = &NFS_I(inode)->cache_access;
9551 +
9552 +       if (cache->cred != set->cred) {
9553 +               if (cache->cred)
9554 +                       put_rpccred(cache->cred);
9555 +               cache->cred = get_rpccred(set->cred);
9556 +       }
9557 +       cache->jiffies = set->jiffies;
9558 +       cache->mask = set->mask;
9559 +}
9560 +
9561 +static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask)
9562 +{
9563 +       struct nfs_access_entry cache;
9564 +       int status;
9565 +
9566 +       status = nfs_access_get_cached(inode, cred, &cache);
9567 +       if (status == 0)
9568 +               goto out;
9569 +
9570 +       /* Be clever: ask server to check for all possible rights */
9571 +       cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ;
9572 +       cache.cred = cred;
9573 +       cache.jiffies = jiffies;
9574 +       status = NFS_PROTO(inode)->access(inode, &cache);
9575 +       if (status != 0)
9576 +               return status;
9577 +       nfs_access_add_cache(inode, &cache);
9578 +out:
9579 +       if ((cache.mask & mask) == mask)
9580 +               return 0;
9581 +       return -EACCES;
9582 +}
9583 +
9584 +int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
9585  {
9586 -       struct nfs_access_cache *cache = &NFS_I(inode)->cache_access;
9587         struct rpc_cred *cred;
9588         int mode = inode->i_mode;
9589         int res;
9590 @@ -1542,24 +1580,7 @@ nfs_permission(struct inode *inode, int 
9591                 goto out_notsup;
9592  
9593         cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
9594 -       if (cache->cred == cred
9595 -           && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))
9596 -           && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) {
9597 -               if (!(res = cache->err)) {
9598 -                       /* Is the mask a subset of an accepted mask? */
9599 -                       if ((cache->mask & mask) == mask)
9600 -                               goto out;
9601 -               } else {
9602 -                       /* ...or is it a superset of a rejected mask? */
9603 -                       if ((cache->mask & mask) == cache->mask)
9604 -                               goto out;
9605 -               }
9606 -       }
9607 -
9608 -       res = NFS_PROTO(inode)->access(inode, cred, mask);
9609 -       if (!res || res == -EACCES)
9610 -               goto add_cache;
9611 -out:
9612 +       res = nfs_do_access(inode, cred, mask);
9613         put_rpccred(cred);
9614         unlock_kernel();
9615         return res;
9616 @@ -1568,15 +1589,6 @@ out_notsup:
9617         res = vfs_permission(inode, mask);
9618         unlock_kernel();
9619         return res;
9620 -add_cache:
9621 -       cache->jiffies = jiffies;
9622 -       if (cache->cred)
9623 -               put_rpccred(cache->cred);
9624 -       cache->cred = cred;
9625 -       cache->mask = mask;
9626 -       cache->err = res;
9627 -       unlock_kernel();
9628 -       return res;
9629  }
9630  
9631  /*
9632 --- linux-2.6.7/fs/nfs/unlink.c.lsec    2004-06-15 23:20:04.000000000 -0600
9633 +++ linux-2.6.7/fs/nfs/unlink.c 2005-03-23 14:28:23.170527240 -0700
9634 @@ -215,7 +215,6 @@ nfs_complete_unlink(struct dentry *dentr
9635         spin_lock(&dentry->d_lock);
9636         dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
9637         spin_unlock(&dentry->d_lock);
9638 -       if (data->task.tk_rpcwait == &nfs_delete_queue)
9639 -               rpc_wake_up_task(&data->task);
9640 +       rpc_wake_up_task(&data->task);
9641         nfs_put_unlinkdata(data);
9642  }
9643 --- linux-2.6.7/fs/nfs/callback_xdr.c.lsec      2005-03-23 14:28:22.545622240 -0700
9644 +++ linux-2.6.7/fs/nfs/callback_xdr.c   2005-03-23 14:28:22.544622392 -0700
9645 @@ -0,0 +1,481 @@
9646 +/*
9647 + * linux/fs/nfs/callback_xdr.c
9648 + *
9649 + * Copyright (C) 2004 Trond Myklebust
9650 + *
9651 + * NFSv4 callback encode/decode procedures
9652 + */
9653 +#include <linux/config.h>
9654 +#include <linux/kernel.h>
9655 +#include <linux/sunrpc/svc.h>
9656 +#include <linux/nfs4.h>
9657 +#include <linux/nfs_fs.h>
9658 +#include "callback.h"
9659 +
9660 +#define CB_OP_TAGLEN_MAXSZ     (512)
9661 +#define CB_OP_HDR_RES_MAXSZ    (2 + CB_OP_TAGLEN_MAXSZ)
9662 +#define CB_OP_GETATTR_BITMAP_MAXSZ     (4)
9663 +#define CB_OP_GETATTR_RES_MAXSZ        (CB_OP_HDR_RES_MAXSZ + \
9664 +                               CB_OP_GETATTR_BITMAP_MAXSZ + \
9665 +                               2 + 2 + 3 + 3)
9666 +#define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
9667 +
9668 +#define NFSDBG_FACILITY NFSDBG_CALLBACK
9669 +
9670 +typedef unsigned (*callback_process_op_t)(void *, void *);
9671 +typedef unsigned (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
9672 +typedef unsigned (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
9673 +
9674 +
9675 +struct callback_op {
9676 +       callback_process_op_t process_op;
9677 +       callback_decode_arg_t decode_args;
9678 +       callback_encode_res_t encode_res;
9679 +       long res_maxsize;
9680 +};
9681 +
9682 +static struct callback_op callback_ops[];
9683 +
9684 +static int nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
9685 +{
9686 +       return htonl(NFS4_OK);
9687 +}
9688 +
9689 +static int nfs4_decode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
9690 +{
9691 +       return xdr_argsize_check(rqstp, p);
9692 +}
9693 +
9694 +static int nfs4_encode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
9695 +{
9696 +       return xdr_ressize_check(rqstp, p);
9697 +}
9698 +
9699 +static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes)
9700 +{
9701 +       uint32_t *p;
9702 +
9703 +       p = xdr_inline_decode(xdr, nbytes);
9704 +       if (unlikely(p == NULL))
9705 +               printk(KERN_WARNING "NFSv4 callback reply buffer overflowed!\n");
9706 +       return p;
9707 +}
9708 +
9709 +static unsigned decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
9710 +{
9711 +       uint32_t *p;
9712 +
9713 +       p = read_buf(xdr, 4);
9714 +       if (unlikely(p == NULL))
9715 +               return htonl(NFS4ERR_RESOURCE);
9716 +       *len = ntohl(*p);
9717 +
9718 +       if (*len != 0) {
9719 +               p = read_buf(xdr, *len);
9720 +               if (unlikely(p == NULL))
9721 +                       return htonl(NFS4ERR_RESOURCE);
9722 +               *str = (const char *)p;
9723 +       } else
9724 +               *str = NULL;
9725 +
9726 +       return 0;
9727 +}
9728 +
9729 +static unsigned decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
9730 +{
9731 +       uint32_t *p;
9732 +
9733 +       p = read_buf(xdr, 4);
9734 +       if (unlikely(p == NULL))
9735 +               return htonl(NFS4ERR_RESOURCE);
9736 +       fh->size = ntohl(*p);
9737 +       if (fh->size > NFS4_FHSIZE)
9738 +               return htonl(NFS4ERR_BADHANDLE);
9739 +       p = read_buf(xdr, fh->size);
9740 +       if (unlikely(p == NULL))
9741 +               return htonl(NFS4ERR_RESOURCE);
9742 +       memcpy(&fh->data[0], p, fh->size);
9743 +       memset(&fh->data[fh->size], 0, sizeof(fh->data) - fh->size);
9744 +       return 0;
9745 +}
9746 +
9747 +static unsigned decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
9748 +{
9749 +       uint32_t *p;
9750 +       unsigned int attrlen;
9751 +
9752 +       p = read_buf(xdr, 4);
9753 +       if (unlikely(p == NULL))
9754 +               return htonl(NFS4ERR_RESOURCE);
9755 +       attrlen = ntohl(*p);
9756 +       p = read_buf(xdr, attrlen << 2);
9757 +       if (unlikely(p == NULL))
9758 +               return htonl(NFS4ERR_RESOURCE);
9759 +       if (likely(attrlen > 0))
9760 +               bitmap[0] = ntohl(*p++);
9761 +       if (attrlen > 1)
9762 +               bitmap[1] = ntohl(*p);
9763 +       return 0;
9764 +}
9765 +
9766 +static unsigned decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
9767 +{
9768 +       uint32_t *p;
9769 +
9770 +       p = read_buf(xdr, 16);
9771 +       if (unlikely(p == NULL))
9772 +               return htonl(NFS4ERR_RESOURCE);
9773 +       memcpy(stateid->data, p, 16);
9774 +       return 0;
9775 +}
9776 +
9777 +static unsigned decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
9778 +{
9779 +       uint32_t *p;
9780 +       unsigned int minor_version;
9781 +       unsigned status;
9782 +
9783 +       status = decode_string(xdr, &hdr->taglen, &hdr->tag);
9784 +       if (unlikely(status != 0))
9785 +               return status;
9786 +       /* We do not like overly long tags! */
9787 +       if (hdr->taglen > CB_OP_TAGLEN_MAXSZ-12 || hdr->taglen < 0) {
9788 +               printk("NFSv4 CALLBACK %s: client sent tag of length %u\n",
9789 +                               __FUNCTION__, hdr->taglen);
9790 +               return htonl(NFS4ERR_RESOURCE);
9791 +       }
9792 +       p = read_buf(xdr, 12);
9793 +       if (unlikely(p == NULL))
9794 +               return htonl(NFS4ERR_RESOURCE);
9795 +       minor_version = ntohl(*p++);
9796 +       /* Check minor version is zero. */
9797 +       if (minor_version != 0) {
9798 +               printk(KERN_WARNING "%s: NFSv4 server callback with illegal minor version %u!\n",
9799 +                               __FUNCTION__, minor_version);
9800 +               return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
9801 +       }
9802 +       hdr->callback_ident = ntohl(*p++);
9803 +       hdr->nops = ntohl(*p);
9804 +       return 0;
9805 +}
9806 +
9807 +static unsigned decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
9808 +{
9809 +       uint32_t *p;
9810 +       p = read_buf(xdr, 4);
9811 +       if (unlikely(p == NULL))
9812 +               return htonl(NFS4ERR_RESOURCE);
9813 +       *op = ntohl(*p);
9814 +       return 0;
9815 +}
9816 +
9817 +static unsigned decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
9818 +{
9819 +       unsigned status;
9820 +
9821 +       status = decode_fh(xdr, &args->fh);
9822 +       if (unlikely(status != 0))
9823 +               goto out;
9824 +       args->addr = &rqstp->rq_addr;
9825 +       status = decode_bitmap(xdr, args->bitmap);
9826 +out:
9827 +       dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
9828 +       return status;
9829 +}
9830 +
9831 +static unsigned decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
9832 +{
9833 +       uint32_t *p;
9834 +       unsigned status;
9835 +
9836 +       args->addr = &rqstp->rq_addr;
9837 +       status = decode_stateid(xdr, &args->stateid);
9838 +       if (unlikely(status != 0))
9839 +               goto out;
9840 +       p = read_buf(xdr, 4);
9841 +       if (unlikely(p == NULL)) {
9842 +               status = htonl(NFS4ERR_RESOURCE);
9843 +               goto out;
9844 +       }
9845 +       args->truncate = ntohl(*p);
9846 +       status = decode_fh(xdr, &args->fh);
9847 +out:
9848 +       dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
9849 +       return 0;
9850 +}
9851 +
9852 +static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
9853 +{
9854 +       uint32_t *p;
9855 +
9856 +       p = xdr_reserve_space(xdr, 4 + len);
9857 +       if (unlikely(p == NULL))
9858 +               return htonl(NFS4ERR_RESOURCE);
9859 +       xdr_encode_opaque(p, str, len);
9860 +       return 0;
9861 +}
9862 +
9863 +#define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE)
9864 +#define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
9865 +static unsigned encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, uint32_t **savep)
9866 +{
9867 +       uint32_t bm[2];
9868 +       uint32_t *p;
9869 +
9870 +       bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0);
9871 +       bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1);
9872 +       if (bm[1] != 0) {
9873 +               p = xdr_reserve_space(xdr, 16);
9874 +               if (unlikely(p == NULL))
9875 +                       return htonl(NFS4ERR_RESOURCE);
9876 +               *p++ = htonl(2);
9877 +               *p++ = bm[0];
9878 +               *p++ = bm[1];
9879 +       } else if (bm[0] != 0) {
9880 +               p = xdr_reserve_space(xdr, 12);
9881 +               if (unlikely(p == NULL))
9882 +                       return htonl(NFS4ERR_RESOURCE);
9883 +               *p++ = htonl(1);
9884 +               *p++ = bm[0];
9885 +       } else {
9886 +               p = xdr_reserve_space(xdr, 8);
9887 +               if (unlikely(p == NULL))
9888 +                       return htonl(NFS4ERR_RESOURCE);
9889 +               *p++ = htonl(0);
9890 +       }
9891 +       *savep = p;
9892 +       return 0;
9893 +}
9894 +
9895 +static unsigned encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
9896 +{
9897 +       uint32_t *p;
9898 +
9899 +       if (!(bitmap[0] & FATTR4_WORD0_CHANGE))
9900 +               return 0;
9901 +       p = xdr_reserve_space(xdr, 8);
9902 +       if (unlikely(p == 0))
9903 +               return htonl(NFS4ERR_RESOURCE);
9904 +       p = xdr_encode_hyper(p, change);
9905 +       return 0;
9906 +}
9907 +
9908 +static unsigned encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
9909 +{
9910 +       uint32_t *p;
9911 +
9912 +       if (!(bitmap[0] & FATTR4_WORD0_SIZE))
9913 +               return 0;
9914 +       p = xdr_reserve_space(xdr, 8);
9915 +       if (unlikely(p == 0))
9916 +               return htonl(NFS4ERR_RESOURCE);
9917 +       p = xdr_encode_hyper(p, size);
9918 +       return 0;
9919 +}
9920 +
9921 +static unsigned encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
9922 +{
9923 +       uint32_t *p;
9924 +
9925 +       p = xdr_reserve_space(xdr, 12);
9926 +       if (unlikely(p == 0))
9927 +               return htonl(NFS4ERR_RESOURCE);
9928 +       p = xdr_encode_hyper(p, time->tv_sec);
9929 +       *p = htonl(time->tv_nsec);
9930 +       return 0;
9931 +}
9932 +
9933 +static unsigned encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
9934 +{
9935 +       if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA))
9936 +               return 0;
9937 +       return encode_attr_time(xdr,time);
9938 +}
9939 +
9940 +static unsigned encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
9941 +{
9942 +       if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY))
9943 +               return 0;
9944 +       return encode_attr_time(xdr,time);
9945 +}
9946 +
9947 +static unsigned encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
9948 +{
9949 +       unsigned status;
9950 +
9951 +       hdr->status = xdr_reserve_space(xdr, 4);
9952 +       if (unlikely(hdr->status == NULL))
9953 +               return htonl(NFS4ERR_RESOURCE);
9954 +       status = encode_string(xdr, hdr->taglen, hdr->tag);
9955 +       if (unlikely(status != 0))
9956 +               return status;
9957 +       hdr->nops = xdr_reserve_space(xdr, 4);
9958 +       if (unlikely(hdr->nops == NULL))
9959 +               return htonl(NFS4ERR_RESOURCE);
9960 +       return 0;
9961 +}
9962 +
9963 +static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res)
9964 +{
9965 +       uint32_t *p;
9966 +       
9967 +       p = xdr_reserve_space(xdr, 8);
9968 +       if (unlikely(p == NULL))
9969 +               return htonl(NFS4ERR_RESOURCE);
9970 +       *p++ = htonl(op);
9971 +       *p = htonl(res);
9972 +       return 0;
9973 +}
9974 +
9975 +static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
9976 +{
9977 +       uint32_t *savep;
9978 +       unsigned status = res->status;
9979 +       
9980 +       if (unlikely(status != 0))
9981 +               goto out;
9982 +       status = encode_attr_bitmap(xdr, res->bitmap, &savep);
9983 +       if (unlikely(status != 0))
9984 +               goto out;
9985 +       status = encode_attr_change(xdr, res->bitmap, res->change_attr);
9986 +       if (unlikely(status != 0))
9987 +               goto out;
9988 +       status = encode_attr_size(xdr, res->bitmap, res->size);
9989 +       if (unlikely(status != 0))
9990 +               goto out;
9991 +       status = encode_attr_ctime(xdr, res->bitmap, &res->ctime);
9992 +       if (unlikely(status != 0))
9993 +               goto out;
9994 +       status = encode_attr_mtime(xdr, res->bitmap, &res->mtime);
9995 +       *savep = htonl((unsigned int)((char *)xdr->p - (char *)(savep+1)));
9996 +out:
9997 +       dprintk("%s: exit with status = %d\n", __FUNCTION__, status);
9998 +       return status;
9999 +}
10000 +
10001 +static unsigned process_op(struct svc_rqst *rqstp,
10002 +               struct xdr_stream *xdr_in, void *argp,
10003 +               struct xdr_stream *xdr_out, void *resp)
10004 +{
10005 +       struct callback_op *op;
10006 +       unsigned int op_nr;
10007 +       unsigned int status = 0;
10008 +       long maxlen;
10009 +       unsigned res;
10010 +
10011 +       dprintk("%s: start\n", __FUNCTION__);
10012 +       status = decode_op_hdr(xdr_in, &op_nr);
10013 +       if (unlikely(status != 0)) {
10014 +               op_nr = OP_CB_ILLEGAL;
10015 +               op = &callback_ops[0];
10016 +       } else if (unlikely(op_nr != OP_CB_GETATTR && op_nr != OP_CB_RECALL)) {
10017 +               op_nr = OP_CB_ILLEGAL;
10018 +               op = &callback_ops[0];
10019 +               status = htonl(NFS4ERR_OP_ILLEGAL);
10020 +       } else
10021 +               op = &callback_ops[op_nr];
10022 +
10023 +       maxlen = xdr_out->end - xdr_out->p;
10024 +       if (maxlen > 0 && maxlen < PAGE_SIZE) {
10025 +               if (likely(status == 0 && op->decode_args != NULL))
10026 +                       status = op->decode_args(rqstp, xdr_in, argp);
10027 +               if (likely(status == 0 && op->process_op != NULL))
10028 +                       status = op->process_op(argp, resp);
10029 +       } else
10030 +               status = htonl(NFS4ERR_RESOURCE);
10031 +
10032 +       res = encode_op_hdr(xdr_out, op_nr, status);
10033 +       if (status == 0)
10034 +               status = res;
10035 +       if (op->encode_res != NULL && status == 0)
10036 +               status = op->encode_res(rqstp, xdr_out, resp);
10037 +       dprintk("%s: done, status = %d\n", __FUNCTION__, status);
10038 +       return status;
10039 +}
10040 +
10041 +/*
10042 + * Decode, process and encode a COMPOUND
10043 + */
10044 +static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
10045 +{
10046 +       struct cb_compound_hdr_arg hdr_arg;
10047 +       struct cb_compound_hdr_res hdr_res;
10048 +       struct xdr_stream xdr_in, xdr_out;
10049 +       uint32_t *p;
10050 +       unsigned int status;
10051 +       unsigned int nops = 1;
10052 +
10053 +       dprintk("%s: start\n", __FUNCTION__);
10054 +
10055 +       xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);
10056 +
10057 +       p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
10058 +       rqstp->rq_res.head[0].iov_len = PAGE_SIZE;
10059 +       xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
10060 +
10061 +       decode_compound_hdr_arg(&xdr_in, &hdr_arg);
10062 +       hdr_res.taglen = hdr_arg.taglen;
10063 +       hdr_res.tag = hdr_arg.tag;
10064 +       encode_compound_hdr_res(&xdr_out, &hdr_res);
10065 +
10066 +       for (;;) {
10067 +               status = process_op(rqstp, &xdr_in, argp, &xdr_out, resp);
10068 +               if (status != 0)
10069 +                       break;
10070 +               if (nops == hdr_arg.nops)
10071 +                       break;
10072 +               nops++;
10073 +       }
10074 +       *hdr_res.status = status;
10075 +       *hdr_res.nops = htonl(nops);
10076 +       dprintk("%s: done, status = %u\n", __FUNCTION__, status);
10077 +       return rpc_success;
10078 +}
10079 +
10080 +/*
10081 + * Define NFS4 callback COMPOUND ops.
10082 + */
10083 +static struct callback_op callback_ops[] = {
10084 +       [0] = {
10085 +               .res_maxsize = CB_OP_HDR_RES_MAXSZ,
10086 +       },
10087 +       [OP_CB_GETATTR] = {
10088 +               .process_op = (callback_process_op_t)nfs4_callback_getattr,
10089 +               .decode_args = (callback_decode_arg_t)decode_getattr_args,
10090 +               .encode_res = (callback_encode_res_t)encode_getattr_res,
10091 +               .res_maxsize = CB_OP_GETATTR_RES_MAXSZ,
10092 +       },
10093 +       [OP_CB_RECALL] = {
10094 +               .process_op = (callback_process_op_t)nfs4_callback_recall,
10095 +               .decode_args = (callback_decode_arg_t)decode_recall_args,
10096 +               .res_maxsize = CB_OP_RECALL_RES_MAXSZ,
10097 +       }
10098 +};
10099 +
10100 +/*
10101 + * Define NFS4 callback procedures
10102 + */
10103 +static struct svc_procedure nfs4_callback_procedures1[] = {
10104 +       [CB_NULL] = {
10105 +               .pc_func = nfs4_callback_null,
10106 +               .pc_decode = (kxdrproc_t)nfs4_decode_void,
10107 +               .pc_encode = (kxdrproc_t)nfs4_encode_void,
10108 +               .pc_xdrressize = 1,
10109 +       },
10110 +       [CB_COMPOUND] = {
10111 +               .pc_func = nfs4_callback_compound,
10112 +               .pc_encode = (kxdrproc_t)nfs4_encode_void,
10113 +               .pc_argsize = 256,
10114 +               .pc_ressize = 256,
10115 +               .pc_xdrressize = NFS4_CALLBACK_BUFSIZE,
10116 +       }
10117 +};
10118 +
10119 +struct svc_version nfs4_callback_version1 = {
10120 +       .vs_vers = 1,
10121 +       .vs_nproc = ARRAY_SIZE(nfs4_callback_procedures1),
10122 +       .vs_proc = nfs4_callback_procedures1,
10123 +       .vs_xdrsize = NFS4_CALLBACK_XDRSIZE,
10124 +       .vs_dispatch = NULL,
10125 +};
10126 +
10127 --- linux-2.6.7/fs/nfs/callback.c.lsec  2005-03-23 14:28:22.484631512 -0700
10128 +++ linux-2.6.7/fs/nfs/callback.c       2005-03-23 14:28:22.483631664 -0700
10129 @@ -0,0 +1,325 @@
10130 +/*
10131 + * linux/fs/nfs/callback.c
10132 + *
10133 + * Copyright (C) 2004 Trond Myklebust
10134 + *
10135 + * NFSv4 callback handling
10136 + */
10137 +
10138 +#include <linux/config.h>
10139 +#include <linux/completion.h>
10140 +#include <linux/ip.h>
10141 +#include <linux/module.h>
10142 +#include <linux/smp_lock.h>
10143 +#include <linux/sunrpc/svc.h>
10144 +#include <linux/sunrpc/svcsock.h>
10145 +#include <linux/nfs_fs.h>
10146 +#include "callback.h"
10147 +
10148 +#define NFSDBG_FACILITY NFSDBG_CALLBACK
10149 +
10150 +struct nfs_callback_data {
10151 +       unsigned int users;
10152 +       struct svc_serv *serv;
10153 +       pid_t pid;
10154 +       struct completion started;
10155 +       struct completion stopped;
10156 +};
10157 +
10158 +static struct nfs_callback_data nfs_callback_info;
10159 +static DECLARE_MUTEX(nfs_callback_sema);
10160 +static struct svc_program nfs4_callback_program;
10161 +
10162 +unsigned short nfs_callback_tcpport;
10163 +
10164 +/*
10165 + * This is the callback kernel thread.
10166 + */
10167 +static void nfs_callback_svc(struct svc_rqst *rqstp)
10168 +{
10169 +       struct svc_serv *serv = rqstp->rq_server;
10170 +       int err;
10171 +
10172 +       __module_get(THIS_MODULE);
10173 +       lock_kernel();
10174 +
10175 +       nfs_callback_info.pid = current->pid;
10176 +       daemonize("nfsv4-svc");
10177 +       /* Process request with signals blocked, but allow SIGKILL.  */
10178 +       allow_signal(SIGKILL);
10179 +
10180 +       complete(&nfs_callback_info.started);
10181 +
10182 +       while (nfs_callback_info.users != 0 || !signalled()) {
10183 +               /*
10184 +                * Listen for a request on the socket
10185 +                */
10186 +               err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT);
10187 +               if (err == -EAGAIN || err == -EINTR)
10188 +                       continue;
10189 +               if (err < 0) {
10190 +                       printk(KERN_WARNING
10191 +                                       "%s: terminating on error %d\n",
10192 +                                       __FUNCTION__, -err);
10193 +                       break;
10194 +               }
10195 +               dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__,
10196 +                               NIPQUAD(rqstp->rq_addr.sin_addr.s_addr));
10197 +               svc_process(serv, rqstp);
10198 +       }
10199 +
10200 +       nfs_callback_info.pid = 0;
10201 +       complete(&nfs_callback_info.stopped);
10202 +       unlock_kernel();
10203 +       module_put_and_exit(0);
10204 +}
10205 +
10206 +/*
10207 + * Bring up the server process if it is not already up.
10208 + */
10209 +int nfs_callback_up(void)
10210 +{
10211 +       struct svc_serv *serv;
10212 +       struct svc_sock *svsk;
10213 +       int ret = 0;
10214 +
10215 +       lock_kernel();
10216 +       down(&nfs_callback_sema);
10217 +       if (nfs_callback_info.users++ || nfs_callback_info.pid != 0)
10218 +               goto out;
10219 +       init_completion(&nfs_callback_info.started);
10220 +       init_completion(&nfs_callback_info.stopped);
10221 +       serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE);
10222 +       ret = -ENOMEM;
10223 +       if (!serv)
10224 +               goto out_err;
10225 +       /* FIXME: We don't want to register this socket with the portmapper */
10226 +       ret = svc_makesock(serv, IPPROTO_TCP, 0);
10227 +       if (ret < 0)
10228 +               goto out_destroy;
10229 +       if (!list_empty(&serv->sv_permsocks)) {
10230 +               svsk = list_entry(serv->sv_permsocks.next,
10231 +                               struct svc_sock, sk_list);
10232 +               nfs_callback_tcpport = ntohs(inet_sk(svsk->sk_sk)->sport);
10233 +               dprintk ("Callback port = 0x%x\n", nfs_callback_tcpport);
10234 +       } else
10235 +               BUG();
10236 +       ret = svc_create_thread(nfs_callback_svc, serv);
10237 +       if (ret < 0)
10238 +               goto out_destroy;
10239 +       nfs_callback_info.serv = serv;
10240 +       wait_for_completion(&nfs_callback_info.started);
10241 +out:
10242 +       up(&nfs_callback_sema);
10243 +       unlock_kernel();
10244 +       return ret;
10245 +out_destroy:
10246 +       svc_destroy(serv);
10247 +out_err:
10248 +       nfs_callback_info.users--;
10249 +       goto out;
10250 +}
10251 +
10252 +/*
10253 + * Kill the server process if it is not already up.
10254 + */
10255 +int nfs_callback_down(void)
10256 +{
10257 +       int ret = 0;
10258 +
10259 +       lock_kernel();
10260 +       down(&nfs_callback_sema);
10261 +       if (--nfs_callback_info.users || nfs_callback_info.pid == 0)
10262 +               goto out;
10263 +       kill_proc(nfs_callback_info.pid, SIGKILL, 1);
10264 +       wait_for_completion(&nfs_callback_info.stopped);
10265 +out:
10266 +       up(&nfs_callback_sema);
10267 +       unlock_kernel();
10268 +       return ret;
10269 +}
10270 +
10271 +/*
10272 + * AUTH_NULL authentication
10273 + */
10274 +static int nfs_callback_null_accept(struct svc_rqst *rqstp, u32 *authp)
10275 +{
10276 +       struct iovec    *argv = &rqstp->rq_arg.head[0];
10277 +       struct iovec    *resv = &rqstp->rq_res.head[0];
10278 +
10279 +       if (argv->iov_len < 3*4)
10280 +               return SVC_GARBAGE;
10281 +
10282 +       if (svc_getu32(argv) != 0) {
10283 +               dprintk("svc: bad null cred\n");
10284 +               *authp = rpc_autherr_badcred;
10285 +               return SVC_DENIED;
10286 +       }
10287 +       if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
10288 +               dprintk("svc: bad null verf\n");
10289 +                *authp = rpc_autherr_badverf;
10290 +                return SVC_DENIED;
10291 +       }
10292 +
10293 +       /* Signal that mapping to nobody uid/gid is required */
10294 +       rqstp->rq_cred.cr_uid = (uid_t) -1;
10295 +       rqstp->rq_cred.cr_gid = (gid_t) -1;
10296 +       rqstp->rq_cred.cr_group_info = groups_alloc(0);
10297 +       if (rqstp->rq_cred.cr_group_info == NULL)
10298 +               return SVC_DROP; /* kmalloc failure - client must retry */
10299 +
10300 +       /* Put NULL verifier */
10301 +       svc_putu32(resv, RPC_AUTH_NULL);
10302 +       svc_putu32(resv, 0);
10303 +       dprintk("%s: success, returning %d!\n", __FUNCTION__, SVC_OK);
10304 +       return SVC_OK;
10305 +}
10306 +
10307 +static int nfs_callback_null_release(struct svc_rqst *rqstp)
10308 +{
10309 +       if (rqstp->rq_cred.cr_group_info)
10310 +               put_group_info(rqstp->rq_cred.cr_group_info);
10311 +       rqstp->rq_cred.cr_group_info = NULL;
10312 +       return 0; /* don't drop */
10313 +}
10314 +
10315 +static struct auth_ops nfs_callback_auth_null = {
10316 +       .name = "null",
10317 +       .flavour = RPC_AUTH_NULL,
10318 +       .accept = nfs_callback_null_accept,
10319 +       .release = nfs_callback_null_release,
10320 +};
10321 +
10322 +/*
10323 + * AUTH_SYS authentication
10324 + */
10325 +static int nfs_callback_unix_accept(struct svc_rqst *rqstp, u32 *authp)
10326 +{
10327 +       struct iovec    *argv = &rqstp->rq_arg.head[0];
10328 +       struct iovec    *resv = &rqstp->rq_res.head[0];
10329 +       struct svc_cred *cred = &rqstp->rq_cred;
10330 +       u32 slen, i;
10331 +       int len = argv->iov_len;
10332 +
10333 +       dprintk("%s: start\n", __FUNCTION__);
10334 +       cred->cr_group_info = NULL;
10335 +       rqstp->rq_client = NULL;
10336 +       if ((len -= 3*4) < 0)
10337 +               return SVC_GARBAGE;
10338 +
10339 +       /* Get length, time stamp and machine name */
10340 +       svc_getu32(argv);
10341 +       svc_getu32(argv);
10342 +       slen = XDR_QUADLEN(ntohl(svc_getu32(argv)));
10343 +       if (slen > 64 || (len -= (slen + 3)*4) < 0)
10344 +               goto badcred;
10345 +       argv->iov_base = (void*)((u32*)argv->iov_base + slen);
10346 +       argv->iov_len -= slen*4;
10347 +
10348 +       cred->cr_uid = ntohl(svc_getu32(argv));
10349 +       cred->cr_gid = ntohl(svc_getu32(argv));
10350 +       slen = ntohl(svc_getu32(argv));
10351 +       if (slen > 16 || (len -= (slen + 2)*4) < 0)
10352 +               goto badcred;
10353 +       cred->cr_group_info = groups_alloc(slen);
10354 +       if (cred->cr_group_info == NULL)
10355 +               return SVC_DROP;
10356 +       for (i = 0; i < slen; i++)
10357 +               GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv));
10358 +
10359 +       if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
10360 +               *authp = rpc_autherr_badverf;
10361 +               return SVC_DENIED;
10362 +       }
10363 +       /* Put NULL verifier */
10364 +       svc_putu32(resv, RPC_AUTH_NULL);
10365 +       svc_putu32(resv, 0);
10366 +       dprintk("%s: success, returning %d!\n", __FUNCTION__, SVC_OK);
10367 +       return SVC_OK;
10368 +badcred:
10369 +       *authp = rpc_autherr_badcred;
10370 +       return SVC_DENIED;
10371 +}
10372 +
10373 +static int nfs_callback_unix_release(struct svc_rqst *rqstp)
10374 +{
10375 +       if (rqstp->rq_cred.cr_group_info)
10376 +               put_group_info(rqstp->rq_cred.cr_group_info);
10377 +       rqstp->rq_cred.cr_group_info = NULL;
10378 +       return 0;
10379 +}
10380 +
10381 +static struct auth_ops nfs_callback_auth_unix = {
10382 +       .name = "unix",
10383 +       .flavour = RPC_AUTH_UNIX,
10384 +       .accept = nfs_callback_unix_accept,
10385 +       .release = nfs_callback_unix_release,
10386 +};
10387 +
10388 +/*
10389 + * Hook the authentication protocol
10390 + */
10391 +static int nfs_callback_auth(struct svc_rqst *rqstp, u32 *authp)
10392 +{
10393 +       struct in_addr *addr = &rqstp->rq_addr.sin_addr;
10394 +       struct nfs4_client *clp;
10395 +       struct iovec *argv = &rqstp->rq_arg.head[0];
10396 +       int flavour;
10397 +       int retval;
10398 +
10399 +       /* Don't talk to strangers */
10400 +       clp = nfs4_find_client(addr);
10401 +       if (clp == NULL)
10402 +               return SVC_DROP;
10403 +       dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr));
10404 +       nfs4_put_client(clp);
10405 +       flavour = ntohl(svc_getu32(argv));
10406 +       switch(flavour) {
10407 +               case RPC_AUTH_NULL:
10408 +                       if (rqstp->rq_proc != CB_NULL) {
10409 +                               *authp = rpc_autherr_tooweak;
10410 +                               retval = SVC_DENIED;
10411 +                               break;
10412 +                       }
10413 +                       rqstp->rq_authop = &nfs_callback_auth_null;
10414 +                       retval = nfs_callback_null_accept(rqstp, authp);
10415 +                       break;
10416 +               case RPC_AUTH_UNIX:
10417 +                       /* Eat the authentication flavour */
10418 +                       rqstp->rq_authop = &nfs_callback_auth_unix;
10419 +                       retval = nfs_callback_unix_accept(rqstp, authp);
10420 +                       break;
10421 +               default:
10422 +                       /* FIXME: need to add RPCSEC_GSS upcalls */
10423 +#if 0
10424 +                       svc_ungetu32(argv);
10425 +                       retval = svc_authenticate(rqstp, authp);
10426 +#else
10427 +                       *authp = rpc_autherr_rejectedcred;
10428 +                       retval = SVC_DENIED;
10429 +#endif
10430 +       }
10431 +       dprintk("%s: flavour %d returning error %d\n", __FUNCTION__, flavour, retval);
10432 +       return retval;
10433 +}
10434 +
10435 +/*
10436 + * Define NFS4 callback program
10437 + */
10438 +extern struct svc_version nfs4_callback_version1;
10439 +
10440 +static struct svc_version *nfs4_callback_version[] = {
10441 +       [1] = &nfs4_callback_version1,
10442 +};
10443 +
10444 +static struct svc_stat nfs4_callback_stats;
10445 +
10446 +static struct svc_program nfs4_callback_program = {
10447 +       .pg_prog = NFS4_CALLBACK,                       /* RPC service number */
10448 +       .pg_nvers = ARRAY_SIZE(nfs4_callback_version),  /* Number of entries */
10449 +       .pg_vers = nfs4_callback_version,               /* version table */
10450 +       .pg_name = "NFSv4 callback",                    /* service name */
10451 +       .pg_class = "nfs",                              /* authentication class */
10452 +       .pg_stats = &nfs4_callback_stats,
10453 +       .pg_authenticate = nfs_callback_auth,
10454 +};
10455 --- linux-2.6.7/fs/nfs/read.c.lsec      2004-06-15 23:18:37.000000000 -0600
10456 +++ linux-2.6.7/fs/nfs/read.c   2005-03-23 14:28:23.114535752 -0700
10457 @@ -91,8 +91,8 @@ int nfs_return_empty_page(struct page *p
10458  /*
10459   * Read a page synchronously.
10460   */
10461 -static int
10462 -nfs_readpage_sync(struct file *file, struct inode *inode, struct page *page)
10463 +static int nfs_readpage_sync(struct nfs_open_context *ctx, struct inode *inode,
10464 +               struct page *page)
10465  {
10466         unsigned int    rsize = NFS_SERVER(inode)->rsize;
10467         unsigned int    count = PAGE_CACHE_SIZE;
10468 @@ -105,10 +105,11 @@ nfs_readpage_sync(struct file *file, str
10469  
10470         memset(rdata, 0, sizeof(*rdata));
10471         rdata->flags = (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
10472 +       rdata->cred = ctx->cred;
10473         rdata->inode = inode;
10474         INIT_LIST_HEAD(&rdata->pages);
10475         rdata->args.fh = NFS_FH(inode);
10476 -       rdata->args.lockowner = current->files;
10477 +       rdata->args.context = ctx;
10478         rdata->args.pages = &page;
10479         rdata->args.pgbase = 0UL;
10480         rdata->args.count = rsize;
10481 @@ -134,7 +135,7 @@ nfs_readpage_sync(struct file *file, str
10482                         rdata->args.count);
10483  
10484                 lock_kernel();
10485 -               result = NFS_PROTO(inode)->read(rdata, file);
10486 +               result = NFS_PROTO(inode)->read(rdata);
10487                 unlock_kernel();
10488  
10489                 /*
10490 @@ -169,8 +170,8 @@ io_error:
10491         return result;
10492  }
10493  
10494 -static int
10495 -nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
10496 +static int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode,
10497 +               struct page *page)
10498  {
10499         LIST_HEAD(one_request);
10500         struct nfs_page *new;
10501 @@ -179,7 +180,7 @@ nfs_readpage_async(struct file *file, st
10502         len = nfs_page_length(inode, page);
10503         if (len == 0)
10504                 return nfs_return_empty_page(page);
10505 -       new = nfs_create_request(file, inode, page, 0, len);
10506 +       new = nfs_create_request(ctx, inode, page, 0, len);
10507         if (IS_ERR(new)) {
10508                 unlock_page(page);
10509                 return PTR_ERR(new);
10510 @@ -202,8 +203,8 @@ static void nfs_readpage_release(struct 
10511         nfs_unlock_request(req);
10512  
10513         dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
10514 -                       req->wb_inode->i_sb->s_id,
10515 -                       (long long)NFS_FILEID(req->wb_inode),
10516 +                       req->wb_context->dentry->d_inode->i_sb->s_id,
10517 +                       (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
10518                         req->wb_bytes,
10519                         (long long)req_offset(req));
10520  }
10521 @@ -217,16 +218,15 @@ static void nfs_read_rpcsetup(struct nfs
10522         struct inode            *inode;
10523  
10524         data->req         = req;
10525 -       data->inode       = inode = req->wb_inode;
10526 -       data->cred        = req->wb_cred;
10527 +       data->inode       = inode = req->wb_context->dentry->d_inode;
10528 +       data->cred        = req->wb_context->cred;
10529  
10530         data->args.fh     = NFS_FH(inode);
10531         data->args.offset = req_offset(req) + offset;
10532         data->args.pgbase = req->wb_pgbase + offset;
10533         data->args.pages  = data->pagevec;
10534         data->args.count  = count;
10535 -       data->args.lockowner = req->wb_lockowner;
10536 -       data->args.state  = req->wb_state;
10537 +       data->args.context = req->wb_context;
10538  
10539         data->res.fattr   = &data->fattr;
10540         data->res.count   = count;
10541 @@ -396,7 +396,7 @@ nfs_pagein_list(struct list_head *head, 
10542         while (!list_empty(head)) {
10543                 pages += nfs_coalesce_requests(head, &one_request, rpages);
10544                 req = nfs_list_entry(one_request.next);
10545 -               error = nfs_pagein_one(&one_request, req->wb_inode);
10546 +               error = nfs_pagein_one(&one_request, req->wb_context->dentry->d_inode);
10547                 if (error < 0)
10548                         break;
10549         }
10550 @@ -500,9 +500,9 @@ void nfs_readpage_result(struct rpc_task
10551   *  -  The error flag is set for this page. This happens only when a
10552   *     previous async read operation failed.
10553   */
10554 -int
10555 -nfs_readpage(struct file *file, struct page *page)
10556 +int nfs_readpage(struct file *file, struct page *page)
10557  {
10558 +       struct nfs_open_context *ctx;
10559         struct inode *inode = page->mapping->host;
10560         int             error;
10561  
10562 @@ -519,25 +519,33 @@ nfs_readpage(struct file *file, struct p
10563         if (error)
10564                 goto out_error;
10565  
10566 +       if (file == NULL) {
10567 +               ctx = nfs_find_open_context(inode, FMODE_READ);
10568 +               if (ctx == NULL)
10569 +                       return -EBADF;
10570 +       } else
10571 +               ctx = get_nfs_open_context((struct nfs_open_context *)
10572 +                               file->private_data);
10573         if (!IS_SYNC(inode)) {
10574 -               error = nfs_readpage_async(file, inode, page);
10575 +               error = nfs_readpage_async(ctx, inode, page);
10576                 goto out;
10577         }
10578  
10579 -       error = nfs_readpage_sync(file, inode, page);
10580 +       error = nfs_readpage_sync(ctx, inode, page);
10581         if (error < 0 && IS_SWAPFILE(inode))
10582                 printk("Aiee.. nfs swap-in of page failed!\n");
10583  out:
10584 +       put_nfs_open_context(ctx);
10585         return error;
10586  
10587  out_error:
10588         unlock_page(page);
10589 -       goto out;
10590 +       return error;
10591  }
10592  
10593  struct nfs_readdesc {
10594         struct list_head *head;
10595 -       struct file *filp;
10596 +       struct nfs_open_context *ctx;
10597  };
10598  
10599  static int
10600 @@ -552,7 +560,7 @@ readpage_async_filler(void *data, struct
10601         len = nfs_page_length(inode, page);
10602         if (len == 0)
10603                 return nfs_return_empty_page(page);
10604 -       new = nfs_create_request(desc->filp, inode, page, 0, len);
10605 +       new = nfs_create_request(desc->ctx, inode, page, 0, len);
10606         if (IS_ERR(new)) {
10607                         SetPageError(page);
10608                         unlock_page(page);
10609 @@ -565,13 +573,11 @@ readpage_async_filler(void *data, struct
10610         return 0;
10611  }
10612  
10613 -int
10614 -nfs_readpages(struct file *filp, struct address_space *mapping,
10615 +int nfs_readpages(struct file *filp, struct address_space *mapping,
10616                 struct list_head *pages, unsigned nr_pages)
10617  {
10618         LIST_HEAD(head);
10619         struct nfs_readdesc desc = {
10620 -               .filp           = filp,
10621                 .head           = &head,
10622         };
10623         struct inode *inode = mapping->host;
10624 @@ -583,12 +589,20 @@ nfs_readpages(struct file *filp, struct 
10625                         (long long)NFS_FILEID(inode),
10626                         nr_pages);
10627  
10628 +       if (filp == NULL) {
10629 +               desc.ctx = nfs_find_open_context(inode, FMODE_READ);
10630 +               if (desc.ctx == NULL)
10631 +                       return -EBADF;
10632 +       } else
10633 +               desc.ctx = get_nfs_open_context((struct nfs_open_context *)
10634 +                               filp->private_data);
10635         ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc);
10636         if (!list_empty(&head)) {
10637                 int err = nfs_pagein_list(&head, server->rpages);
10638                 if (!ret)
10639                         ret = err;
10640         }
10641 +       put_nfs_open_context(desc.ctx);
10642         return ret;
10643  }
10644  
10645 --- linux-2.6.7/fs/nfs/Makefile.lsec    2004-06-15 23:19:01.000000000 -0600
10646 +++ linux-2.6.7/fs/nfs/Makefile 2005-03-23 14:28:22.819580592 -0700
10647 @@ -9,6 +9,7 @@ nfs-y                   := dir.o file.o inode.o nfs2xdr
10648  nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o      
10649  nfs-$(CONFIG_NFS_V3)   += nfs3proc.o nfs3xdr.o
10650  nfs-$(CONFIG_NFS_V4)   += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
10651 -                          idmap.o
10652 +                          delegation.o idmap.o \
10653 +                          callback.o callback_xdr.o callback_proc.o
10654  nfs-$(CONFIG_NFS_DIRECTIO) += direct.o
10655  nfs-objs               := $(nfs-y)
10656 --- linux-2.6.7/fs/Kconfig.lsec 2004-06-15 23:19:36.000000000 -0600
10657 +++ linux-2.6.7/fs/Kconfig      2005-03-23 14:28:23.871420688 -0700
10658 @@ -322,7 +322,7 @@ config FS_POSIX_ACL
10659  #      Never use this symbol for ifdefs.
10660  #
10661         bool
10662 -       depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL || REISERFS_FS_POSIX_ACL
10663 +       depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL || REISERFS_FS_POSIX_ACL || NFS_V4
10664         default y
10665  
10666  config XFS_FS
10667 @@ -1443,6 +1443,7 @@ config NFSD_V3
10668  config NFSD_V4
10669         bool "Provide NFSv4 server support (EXPERIMENTAL)"
10670         depends on NFSD_V3 && EXPERIMENTAL
10671 +       select NFSD_TCP
10672         help
10673           If you would like to include the NFSv4 server as well as the NFSv2
10674           and NFSv3 servers, say Y here.  This feature is experimental, and
10675 @@ -1450,11 +1451,13 @@ config NFSD_V4
10676           If unsure, say N.
10677  
10678  config NFSD_TCP
10679 -       bool "Provide NFS server over TCP support (EXPERIMENTAL)"
10680 -       depends on NFSD && EXPERIMENTAL
10681 +       bool "Provide NFS server over TCP support"
10682 +       depends on NFSD
10683 +       default y
10684         help
10685 -         Enable NFS service over TCP connections.  This the officially
10686 -         still experimental, but seems to work well.
10687 +         If you want your NFS server to support TCP connections, say Y here.
10688 +         TCP connections usually perform better than the default UDP when
10689 +         the network is lossy or congested.  If unsure, say Y.
10690  
10691  config ROOT_NFS
10692         bool "Root file system on NFS"
10693 @@ -1505,6 +1508,22 @@ config RPCSEC_GSS_KRB5
10694  
10695           If unsure, say N.
10696  
10697 +config RPCSEC_GSS_SPKM3
10698 +       tristate "Secure RPC: SPKM3 mechanism (EXPERIMENTAL)"
10699 +       depends on SUNRPC && EXPERIMENTAL
10700 +       select SUNRPC_GSS
10701 +       select CRYPTO
10702 +       select CRYPTO_MD5
10703 +       select CRYPTO_DES
10704 +       help
10705 +         Provides for secure RPC calls by means of a gss-api
10706 +         mechanism based on the SPKM3 public-key mechanism.
10707 +
10708 +         Note: Requires an auxiliary userspace daemon which may be found on
10709 +               http://www.citi.umich.edu/projects/nfsv4/
10710 +
10711 +         If unsure, say N.
10712 +
10713  config SMB_FS
10714         tristate "SMB file system support (to mount Windows shares etc.)"
10715         depends on INET
10716 --- linux-2.6.7/include/linux/fs.h.lsec 2005-03-23 14:26:03.300790672 -0700
10717 +++ linux-2.6.7/include/linux/fs.h      2005-03-23 14:28:23.280510520 -0700
10718 @@ -632,7 +632,7 @@ struct file_lock {
10719         struct file_lock *fl_next;      /* singly linked list for this inode  */
10720         struct list_head fl_link;       /* doubly linked list of all locks */
10721         struct list_head fl_block;      /* circular list of blocked processes */
10722 -       fl_owner_t fl_owner;
10723 +       fl_owner_t fl_owner;            /* 0 if lock owned by a local process */
10724         unsigned int fl_pid;
10725         wait_queue_head_t fl_wait;
10726         struct file *fl_file;
10727 --- linux-2.6.7/include/linux/nfs4.h.lsec       2004-06-15 23:19:22.000000000 -0600
10728 +++ linux-2.6.7/include/linux/nfs4.h    2005-03-23 14:28:23.335502160 -0700
10729 @@ -13,8 +13,12 @@
10730  #ifndef _LINUX_NFS4_H
10731  #define _LINUX_NFS4_H
10732  
10733 +#include <linux/types.h>
10734 +#include <linux/list.h>
10735 +
10736  #define NFS4_VERIFIER_SIZE     8
10737  #define NFS4_FHSIZE            128
10738 +#define NFS4_MAXPATHLEN                PATH_MAX
10739  #define NFS4_MAXNAMLEN         NAME_MAX
10740  
10741  #define NFS4_ACCESS_READ        0x0001
10742 @@ -52,6 +56,60 @@
10743  #define ACL4_SUPPORT_AUDIT_ACL 0x04
10744  #define ACL4_SUPPORT_ALARM_ACL 0x08
10745  
10746 +#define NFS4_ACE_FILE_INHERIT_ACE             0x00000001
10747 +#define NFS4_ACE_DIRECTORY_INHERIT_ACE        0x00000002
10748 +#define NFS4_ACE_NO_PROPAGATE_INHERIT_ACE     0x00000004
10749 +#define NFS4_ACE_INHERIT_ONLY_ACE             0x00000008
10750 +#define NFS4_ACE_SUCCESSFUL_ACCESS_ACE_FLAG   0x00000010
10751 +#define NFS4_ACE_FAILED_ACCESS_ACE_FLAG       0x00000020
10752 +#define NFS4_ACE_IDENTIFIER_GROUP             0x00000040
10753 +#define NFS4_ACE_OWNER                        0x00000080
10754 +#define NFS4_ACE_GROUP                        0x00000100
10755 +#define NFS4_ACE_EVERYONE                     0x00000200
10756 +
10757 +#define NFS4_ACE_READ_DATA                    0x00000001
10758 +#define NFS4_ACE_LIST_DIRECTORY               0x00000001
10759 +#define NFS4_ACE_WRITE_DATA                   0x00000002
10760 +#define NFS4_ACE_ADD_FILE                     0x00000002
10761 +#define NFS4_ACE_APPEND_DATA                  0x00000004
10762 +#define NFS4_ACE_ADD_SUBDIRECTORY             0x00000004
10763 +#define NFS4_ACE_READ_NAMED_ATTRS             0x00000008
10764 +#define NFS4_ACE_WRITE_NAMED_ATTRS            0x00000010
10765 +#define NFS4_ACE_EXECUTE                      0x00000020
10766 +#define NFS4_ACE_DELETE_CHILD                 0x00000040
10767 +#define NFS4_ACE_READ_ATTRIBUTES              0x00000080
10768 +#define NFS4_ACE_WRITE_ATTRIBUTES             0x00000100
10769 +#define NFS4_ACE_DELETE                       0x00010000
10770 +#define NFS4_ACE_READ_ACL                     0x00020000
10771 +#define NFS4_ACE_WRITE_ACL                    0x00040000
10772 +#define NFS4_ACE_WRITE_OWNER                  0x00080000
10773 +#define NFS4_ACE_SYNCHRONIZE                  0x00100000
10774 +#define NFS4_ACE_GENERIC_READ                 0x00120081
10775 +#define NFS4_ACE_GENERIC_WRITE                0x00160106
10776 +#define NFS4_ACE_GENERIC_EXECUTE              0x001200A0
10777 +#define NFS4_ACE_MASK_ALL                     0x001F01FF
10778 +
10779 +enum nfs4_acl_whotype {
10780 +       NFS4_ACL_WHO_NAMED = 0,
10781 +       NFS4_ACL_WHO_OWNER,
10782 +       NFS4_ACL_WHO_GROUP,
10783 +       NFS4_ACL_WHO_EVERYONE,
10784 +};
10785 +
10786 +struct nfs4_ace {
10787 +       uint32_t        type;
10788 +       uint32_t        flag;
10789 +       uint32_t        access_mask;
10790 +       int             whotype;
10791 +       uid_t           who;
10792 +       struct list_head l_ace;
10793 +};
10794 +
10795 +struct nfs4_acl {
10796 +       uint32_t        naces;
10797 +       struct list_head ace_head;
10798 +};
10799 +
10800  typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
10801  typedef struct { char data[16]; } nfs4_stateid;
10802  
10803 @@ -297,7 +355,7 @@ enum {
10804         NFSPROC4_CLNT_COMMIT,
10805         NFSPROC4_CLNT_OPEN,
10806         NFSPROC4_CLNT_OPEN_CONFIRM,
10807 -       NFSPROC4_CLNT_OPEN_RECLAIM,
10808 +       NFSPROC4_CLNT_OPEN_NOATTR,
10809         NFSPROC4_CLNT_OPEN_DOWNGRADE,
10810         NFSPROC4_CLNT_CLOSE,
10811         NFSPROC4_CLNT_SETATTR,
10812 @@ -315,12 +373,16 @@ enum {
10813         NFSPROC4_CLNT_REMOVE,
10814         NFSPROC4_CLNT_RENAME,
10815         NFSPROC4_CLNT_LINK,
10816 +       NFSPROC4_CLNT_SYMLINK,
10817         NFSPROC4_CLNT_CREATE,
10818         NFSPROC4_CLNT_PATHCONF,
10819         NFSPROC4_CLNT_STATFS,
10820         NFSPROC4_CLNT_READLINK,
10821         NFSPROC4_CLNT_READDIR,
10822         NFSPROC4_CLNT_SERVER_CAPS,
10823 +       NFSPROC4_CLNT_DELEGRETURN,
10824 +       NFSPROC4_CLNT_GETACL,
10825 +       NFSPROC4_CLNT_SETACL,
10826  };
10827  
10828  #endif
10829 --- linux-2.6.7/include/linux/nfs_page.h.lsec   2004-06-15 23:18:57.000000000 -0600
10830 +++ linux-2.6.7/include/linux/nfs_page.h        2005-03-23 14:28:23.392493496 -0700
10831 @@ -29,14 +29,9 @@
10832  struct nfs_page {
10833         struct list_head        wb_list,        /* Defines state of page: */
10834                                 *wb_list_head;  /*      read/write/commit */
10835 -       struct file             *wb_file;
10836 -       fl_owner_t              wb_lockowner;
10837 -       struct inode            *wb_inode;
10838 -       struct rpc_cred         *wb_cred;
10839 -       struct nfs4_state       *wb_state;
10840         struct page             *wb_page;       /* page to read in/write out */
10841 +       struct nfs_open_context *wb_context;    /* File state context info */
10842         atomic_t                wb_complete;    /* i/os we're waiting for */
10843 -       wait_queue_head_t       wb_wait;        /* wait queue */
10844         unsigned long           wb_index;       /* Offset >> PAGE_CACHE_SHIFT */
10845         unsigned int            wb_offset,      /* Offset & ~PAGE_CACHE_MASK */
10846                                 wb_pgbase,      /* Start of page data */
10847 @@ -50,9 +45,11 @@ struct nfs_page {
10848  #define NFS_NEED_COMMIT(req)   (test_bit(PG_NEED_COMMIT,&(req)->wb_flags))
10849  #define NFS_NEED_RESCHED(req)  (test_bit(PG_NEED_RESCHED,&(req)->wb_flags))
10850  
10851 -extern struct nfs_page *nfs_create_request(struct file *, struct inode *,
10852 -                                           struct page *,
10853 -                                           unsigned int, unsigned int);
10854 +extern struct nfs_page *nfs_create_request(struct nfs_open_context *ctx,
10855 +                                           struct inode *inode,
10856 +                                           struct page *page,
10857 +                                           unsigned int offset,
10858 +                                           unsigned int count);
10859  extern void nfs_clear_request(struct nfs_page *req);
10860  extern void nfs_release_request(struct nfs_page *req);
10861  
10862 @@ -64,6 +61,7 @@ extern        int nfs_scan_list(struct list_hea
10863  extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
10864                                   unsigned int);
10865  extern  int nfs_wait_on_request(struct nfs_page *);
10866 +extern void nfs_unlock_request(struct nfs_page *req);
10867  
10868  extern spinlock_t nfs_wreq_lock;
10869  
10870 @@ -90,19 +88,6 @@ nfs_lock_request(struct nfs_page *req)
10871         return 1;
10872  }
10873  
10874 -static inline void
10875 -nfs_unlock_request(struct nfs_page *req)
10876 -{
10877 -       if (!NFS_WBACK_BUSY(req)) {
10878 -               printk(KERN_ERR "NFS: Invalid unlock attempted\n");
10879 -               BUG();
10880 -       }
10881 -       smp_mb__before_clear_bit();
10882 -       clear_bit(PG_BUSY, &req->wb_flags);
10883 -       smp_mb__after_clear_bit();
10884 -       wake_up_all(&req->wb_wait);
10885 -       nfs_release_request(req);
10886 -}
10887  
10888  /**
10889   * nfs_list_remove_request - Remove a request from its wb_list
10890 --- linux-2.6.7/include/linux/sunrpc/svc.h.lsec 2004-06-15 23:19:35.000000000 -0600
10891 +++ linux-2.6.7/include/linux/sunrpc/svc.h      2005-03-23 14:28:23.541470848 -0700
10892 @@ -87,6 +87,14 @@ static inline u32 svc_getu32(struct iove
10893         iov->iov_len -= sizeof(u32);
10894         return val;
10895  }
10896 +
10897 +static inline void svc_ungetu32(struct iovec *iov)
10898 +{
10899 +       u32 *vp = (u32 *)iov->iov_base;
10900 +       iov->iov_base = (void *)(vp - 1);
10901 +       iov->iov_len += sizeof(*vp);
10902 +}
10903 +
10904  static inline void svc_putu32(struct iovec *iov, u32 val)
10905  {
10906         u32 *vp = iov->iov_base + iov->iov_len;
10907 @@ -243,6 +251,8 @@ struct svc_program {
10908         char *                  pg_name;        /* service name */
10909         char *                  pg_class;       /* class name: services sharing authentication */
10910         struct svc_stat *       pg_stats;       /* rpc statistics */
10911 +       /* Override authentication. NULL means use default */
10912 +       int                     (*pg_authenticate)(struct svc_rqst *, u32 *);
10913  };
10914  
10915  /*
10916 --- linux-2.6.7/include/linux/sunrpc/gss_spkm3.h.lsec   2005-03-23 14:28:24.186372808 -0700
10917 +++ linux-2.6.7/include/linux/sunrpc/gss_spkm3.h        2005-03-23 14:28:24.185372960 -0700
10918 @@ -0,0 +1,61 @@
10919 +/*
10920 + *  linux/include/linux/sunrpc/gss_spkm3.h
10921 + *
10922 + *  Copyright (c) 2000 The Regents of the University of Michigan.
10923 + *  All rights reserved.
10924 + *
10925 + *  Andy Adamson   <andros@umich.edu>
10926 + */
10927 +
10928 +#include <linux/sunrpc/auth_gss.h>
10929 +#include <linux/sunrpc/gss_err.h>
10930 +#include <linux/sunrpc/gss_asn1.h>
10931 +
10932 +struct spkm3_ctx {
10933 +       struct xdr_netobj       ctx_id; /* per message context id */
10934 +       int                     qop;         /* negotiated qop */
10935 +       struct xdr_netobj       mech_used;
10936 +       unsigned int            ret_flags ;
10937 +       unsigned int            req_flags ;
10938 +       struct xdr_netobj       share_key;
10939 +       int                     conf_alg;
10940 +       struct crypto_tfm*      derived_conf_key;
10941 +       int                     intg_alg;
10942 +       struct crypto_tfm*      derived_integ_key;
10943 +       int                     keyestb_alg;   /* alg used to get share_key */
10944 +       int                     owf_alg;   /* one way function */
10945 +};
10946 +
10947 +/* from openssl/objects.h */
10948 +/* XXX need SEAL_ALG_NONE */
10949 +#define NID_md5                4
10950 +#define NID_dhKeyAgreement     28
10951 +#define NID_des_cbc            31
10952 +#define NID_sha1               64
10953 +#define NID_cast5_cbc          108
10954 +
10955 +/* SPKM InnerContext Token types */
10956 +
10957 +#define SPKM_ERROR_TOK 3
10958 +#define SPKM_MIC_TOK   4
10959 +#define SPKM_WRAP_TOK  5
10960 +#define SPKM_DEL_TOK   6
10961 +
10962 +u32 spkm3_make_token(struct spkm3_ctx *ctx, int qop_req, struct xdr_buf * text, struct xdr_netobj * token, int toktype);
10963 +
10964 +u32 spkm3_read_token(struct spkm3_ctx *ctx, struct xdr_netobj *read_token, struct xdr_buf *message_buffer, int *qop_state, int toktype);
10965 +
10966 +#define CKSUMTYPE_RSA_MD5            0x0007
10967 +
10968 +s32 make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
10969 +                   struct xdr_netobj *cksum);
10970 +void asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits);
10971 +int decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen,
10972 +                   int explen);
10973 +void spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen,
10974 +                   unsigned char *ctxhdr, int elen, int zbit);
10975 +void spkm3_make_mic_token(unsigned  char **tokp, int toklen,
10976 +                   struct xdr_netobj *mic_hdr,
10977 +                   struct xdr_netobj *md5cksum, int md5elen, int md5zbit);
10978 +u32 spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen,
10979 +                   unsigned char **cksum);
10980 --- linux-2.6.7/include/linux/sunrpc/sched.h.lsec       2004-06-15 23:19:42.000000000 -0600
10981 +++ linux-2.6.7/include/linux/sunrpc/sched.h    2005-03-23 14:28:23.540471000 -0700
10982 @@ -11,7 +11,9 @@
10983  
10984  #include <linux/timer.h>
10985  #include <linux/sunrpc/types.h>
10986 +#include <linux/spinlock.h>
10987  #include <linux/wait.h>
10988 +#include <linux/workqueue.h>
10989  #include <linux/sunrpc/xdr.h>
10990  
10991  /*
10992 @@ -25,11 +27,18 @@ struct rpc_message {
10993         struct rpc_cred *       rpc_cred;       /* Credentials */
10994  };
10995  
10996 +struct rpc_wait_queue;
10997 +struct rpc_wait {
10998 +       struct list_head        list;           /* wait queue links */
10999 +       struct list_head        links;          /* Links to related tasks */
11000 +       wait_queue_head_t       waitq;          /* sync: sleep on this q */
11001 +       struct rpc_wait_queue * rpc_waitq;      /* RPC wait queue we're on */
11002 +};
11003 +
11004  /*
11005   * This is the RPC task struct
11006   */
11007  struct rpc_task {
11008 -       struct list_head        tk_list;        /* wait queue links */
11009  #ifdef RPC_DEBUG
11010         unsigned long           tk_magic;       /* 0xf00baa */
11011  #endif
11012 @@ -37,7 +46,6 @@ struct rpc_task {
11013         struct rpc_clnt *       tk_client;      /* RPC client */
11014         struct rpc_rqst *       tk_rqstp;       /* RPC request */
11015         int                     tk_status;      /* result of last operation */
11016 -       struct rpc_wait_queue * tk_rpcwait;     /* RPC wait queue we're on */
11017  
11018         /*
11019          * RPC call state
11020 @@ -70,13 +78,18 @@ struct rpc_task {
11021          * you have a pathological interest in kernel oopses.
11022          */
11023         struct timer_list       tk_timer;       /* kernel timer */
11024 -       wait_queue_head_t       tk_wait;        /* sync: sleep on this q */
11025         unsigned long           tk_timeout;     /* timeout for rpc_sleep() */
11026         unsigned short          tk_flags;       /* misc flags */
11027         unsigned char           tk_active   : 1;/* Task has been activated */
11028         unsigned char           tk_priority : 2;/* Task priority */
11029         unsigned long           tk_runstate;    /* Task run status */
11030 -       struct list_head        tk_links;       /* links to related tasks */
11031 +       struct workqueue_struct *tk_workqueue;  /* Normally rpciod, but could
11032 +                                                * be any workqueue
11033 +                                                */
11034 +       union {
11035 +               struct work_struct      tk_work;        /* Async task work queue */
11036 +               struct rpc_wait         tk_wait;        /* RPC wait */
11037 +       } u;
11038  #ifdef RPC_DEBUG
11039         unsigned short          tk_pid;         /* debugging aid */
11040  #endif
11041 @@ -87,11 +100,11 @@ struct rpc_task {
11042  /* support walking a list of tasks on a wait queue */
11043  #define        task_for_each(task, pos, head) \
11044         list_for_each(pos, head) \
11045 -               if ((task=list_entry(pos, struct rpc_task, tk_list)),1)
11046 +               if ((task=list_entry(pos, struct rpc_task, u.tk_wait.list)),1)
11047  
11048  #define        task_for_first(task, head) \
11049         if (!list_empty(head) &&  \
11050 -           ((task=list_entry((head)->next, struct rpc_task, tk_list)),1))
11051 +           ((task=list_entry((head)->next, struct rpc_task, u.tk_wait.list)),1))
11052  
11053  /* .. and walking list of all tasks */
11054  #define        alltask_for_each(task, pos, head) \
11055 @@ -124,22 +137,24 @@ typedef void                      (*rpc_action)(struct rpc_
11056  #define RPC_DO_CALLBACK(t)     ((t)->tk_callback != NULL)
11057  #define RPC_IS_SOFT(t)         ((t)->tk_flags & RPC_TASK_SOFT)
11058  
11059 -#define RPC_TASK_SLEEPING      0
11060 -#define RPC_TASK_RUNNING       1
11061 -#define RPC_IS_SLEEPING(t)     (test_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
11062 -#define RPC_IS_RUNNING(t)      (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
11063 +#define RPC_TASK_RUNNING       0
11064 +#define RPC_TASK_QUEUED                1
11065  
11066 +#define RPC_IS_RUNNING(t)      (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
11067  #define rpc_set_running(t)     (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
11068 -#define rpc_clear_running(t)   (clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
11069 -
11070 -#define rpc_set_sleeping(t)    (set_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate))
11071 -
11072 -#define rpc_clear_sleeping(t) \
11073 +#define rpc_test_and_set_running(t) \
11074 +                               (test_and_set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate))
11075 +#define rpc_clear_running(t)   \
11076         do { \
11077                 smp_mb__before_clear_bit(); \
11078 -               clear_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate); \
11079 +               clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate); \
11080                 smp_mb__after_clear_bit(); \
11081 -       } while(0)
11082 +       } while (0)
11083 +
11084 +#define RPC_IS_QUEUED(t)       (test_bit(RPC_TASK_QUEUED, &(t)->tk_runstate))
11085 +#define rpc_set_queued(t)      (set_bit(RPC_TASK_QUEUED, &(t)->tk_runstate))
11086 +#define rpc_test_and_clear_queued(t) \
11087 +               (test_and_clear_bit(RPC_TASK_QUEUED, &(t)->tk_runstate))
11088  
11089  /*
11090   * Task priorities.
11091 @@ -155,6 +170,7 @@ typedef void                        (*rpc_action)(struct rpc_
11092   * RPC synchronization objects
11093   */
11094  struct rpc_wait_queue {
11095 +       spinlock_t              lock;
11096         struct list_head        tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */
11097         unsigned long           cookie;                 /* cookie of last task serviced */
11098         unsigned char           maxpriority;            /* maximum priority (0 if queue is not a priority queue) */
11099 @@ -175,6 +191,7 @@ struct rpc_wait_queue {
11100  
11101  #ifndef RPC_DEBUG
11102  # define RPC_WAITQ_INIT(var,qname) { \
11103 +               .lock = SPIN_LOCK_UNLOCKED, \
11104                 .tasks = { \
11105                         [0] = LIST_HEAD_INIT(var.tasks[0]), \
11106                         [1] = LIST_HEAD_INIT(var.tasks[1]), \
11107 @@ -183,6 +200,7 @@ struct rpc_wait_queue {
11108         }
11109  #else
11110  # define RPC_WAITQ_INIT(var,qname) { \
11111 +               .lock = SPIN_LOCK_UNLOCKED, \
11112                 .tasks = { \
11113                         [0] = LIST_HEAD_INIT(var.tasks[0]), \
11114                         [1] = LIST_HEAD_INIT(var.tasks[1]), \
11115 @@ -207,13 +225,10 @@ void              rpc_killall_tasks(struct rpc_clnt 
11116  int            rpc_execute(struct rpc_task *);
11117  void           rpc_run_child(struct rpc_task *parent, struct rpc_task *child,
11118                                         rpc_action action);
11119 -int            rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *);
11120 -void           rpc_remove_wait_queue(struct rpc_task *);
11121  void           rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *);
11122  void           rpc_init_wait_queue(struct rpc_wait_queue *, const char *);
11123  void           rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
11124                                         rpc_action action, rpc_action timer);
11125 -void           rpc_add_timer(struct rpc_task *, rpc_action);
11126  void           rpc_wake_up_task(struct rpc_task *);
11127  void           rpc_wake_up(struct rpc_wait_queue *);
11128  struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
11129 --- linux-2.6.7/include/linux/sunrpc/gss_api.h.lsec     2004-06-15 23:20:03.000000000 -0600
11130 +++ linux-2.6.7/include/linux/sunrpc/gss_api.h  2005-03-23 14:28:24.688296504 -0700
11131 @@ -47,6 +47,18 @@ u32 gss_verify_mic(
11132                 struct xdr_buf          *message,
11133                 struct xdr_netobj       *mic_token,
11134                 u32                     *qstate);
11135 +u32 gss_wrap(
11136 +               struct gss_ctx          *ctx_id,
11137 +               u32                     qop,
11138 +               int                     offset,
11139 +               struct xdr_buf          *outbuf,
11140 +               struct page             **inpages);
11141 +u32 gss_unwrap(
11142 +               struct gss_ctx          *ctx_id,
11143 +               u32                     *qop,
11144 +               int                     offset,
11145 +               struct xdr_buf          *inbuf,
11146 +               int                     *out_offset);
11147  u32 gss_delete_sec_context(
11148                 struct gss_ctx          **ctx_id);
11149  
11150 @@ -93,6 +105,18 @@ struct gss_api_ops {
11151                         struct xdr_buf          *message,
11152                         struct xdr_netobj       *mic_token,
11153                         u32                     *qstate);
11154 +       u32 (*gss_wrap)(
11155 +                       struct gss_ctx          *ctx_id,
11156 +                       u32                     qop,
11157 +                       int                     offset,
11158 +                       struct xdr_buf          *outbuf,
11159 +                       struct page             **inpages);
11160 +       u32 (*gss_unwrap)(
11161 +                       struct gss_ctx          *ctx_id,
11162 +                       u32                     *qop,
11163 +                       int                     offset,
11164 +                       struct xdr_buf          *buf,
11165 +                       int                     *out_offset);
11166         void (*gss_delete_sec_context)(
11167                         void                    *internal_ctx_id);
11168  };
11169 --- linux-2.6.7/include/linux/sunrpc/xprt.h.lsec        2004-06-15 23:19:43.000000000 -0600
11170 +++ linux-2.6.7/include/linux/sunrpc/xprt.h     2005-03-23 14:28:24.783282064 -0700
11171 @@ -95,7 +95,10 @@ struct rpc_rqst {
11172         int                     rq_cong;        /* has incremented xprt->cong */
11173         int                     rq_received;    /* receive completed */
11174         u32                     rq_seqno;       /* gss seq no. used on req. */
11175 -
11176 +       int                     rq_enc_pages_num;
11177 +       struct page             **rq_enc_pages; /* scratch pages for use by
11178 +                                                  gss privacy code */
11179 +       void (*rq_release_snd_buf)(struct rpc_rqst *); /* release rq_enc_pages */
11180         struct list_head        rq_list;
11181  
11182         struct xdr_buf          rq_private_buf;         /* The receive buffer
11183 --- linux-2.6.7/include/linux/sunrpc/gss_krb5.h.lsec    2004-06-15 23:19:29.000000000 -0600
11184 +++ linux-2.6.7/include/linux/sunrpc/gss_krb5.h 2005-03-23 14:28:24.840273400 -0700
11185 @@ -53,6 +53,8 @@ struct krb5_ctx {
11186         struct xdr_netobj       mech_used;
11187  };
11188  
11189 +extern spinlock_t krb5_seq_lock;
11190 +
11191  #define KG_TOK_MIC_MSG    0x0101
11192  #define KG_TOK_WRAP_MSG   0x0201
11193  
11194 @@ -116,18 +118,25 @@ enum seal_alg {
11195  
11196  s32
11197  make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
11198 -                  struct xdr_netobj *cksum);
11199 +               int body_offset, struct xdr_netobj *cksum);
11200  
11201  u32
11202  krb5_make_token(struct krb5_ctx *context_handle, int qop_req,
11203         struct xdr_buf *input_message_buffer,
11204 -       struct xdr_netobj *output_message_buffer, int toktype);
11205 +       struct xdr_netobj *output_message_buffer);
11206  
11207  u32
11208  krb5_read_token(struct krb5_ctx *context_handle,
11209           struct xdr_netobj *input_token_buffer,
11210 -         struct xdr_buf *message_buffer,
11211 -         int *qop_state, int toktype);
11212 +         struct xdr_buf *message_buffer, int *qop_state);
11213 +
11214 +u32
11215 +gss_wrap_kerberos(struct gss_ctx *ctx_id, u32 qop, int offset,
11216 +               struct xdr_buf *outbuf, struct page **pages);
11217 +
11218 +u32
11219 +gss_unwrap_kerberos(struct gss_ctx *ctx_id, u32 *qop, int offset,
11220 +               struct xdr_buf *buf, int *out_offset);
11221  
11222  u32
11223  krb5_encrypt(struct crypto_tfm * key,
11224 @@ -137,6 +146,13 @@ u32
11225  krb5_decrypt(struct crypto_tfm * key,
11226              void *iv, void *in, void *out, int length); 
11227  
11228 +int
11229 +gss_encrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *outbuf, int offset,
11230 +               struct page **pages);
11231 +
11232 +int
11233 +gss_decrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *inbuf, int offset);
11234 +
11235  s32
11236  krb5_make_seq_num(struct crypto_tfm * key,
11237                 int direction,
11238 --- linux-2.6.7/include/linux/sunrpc/gss_asn1.h.lsec    2004-06-15 23:20:04.000000000 -0600
11239 +++ linux-2.6.7/include/linux/sunrpc/gss_asn1.h 2005-03-23 14:28:23.706445768 -0700
11240 @@ -69,7 +69,6 @@ u32 g_verify_token_header(
11241       struct xdr_netobj *mech,
11242       int *body_size,
11243       unsigned char **buf_in,
11244 -     int tok_type,
11245       int toksize);
11246  
11247  u32 g_get_mech_oid(struct xdr_netobj *mech, struct xdr_netobj * in_buf);
11248 --- linux-2.6.7/include/linux/sunrpc/cache.h.lsec       2004-06-15 23:19:28.000000000 -0600
11249 +++ linux-2.6.7/include/linux/sunrpc/cache.h    2005-03-23 14:28:24.349348032 -0700
11250 @@ -128,20 +128,17 @@ struct cache_deferred_req {
11251   * just like a template in C++, this macro does cache lookup
11252   * for us.
11253   * The function is passed some sort of HANDLE from which a cache_detail
11254 - * structure can be determined (via SETUP, DETAIL), a template
11255 + * structure can be determined (via DETAIL), a template
11256   * cache entry (type RTN*), and a "set" flag.  Using the HASHFN and the 
11257   * TEST, the function will try to find a matching cache entry in the cache.
11258   * If "set" == 0 :
11259   *    If an entry is found, it is returned
11260   *    If no entry is found, a new non-VALID entry is created.
11261 - * If "set" == 1 and INPLACE == 0 :
11262 + * If "set" == 1:
11263   *    If no entry is found a new one is inserted with data from "template"
11264   *    If a non-CACHE_VALID entry is found, it is updated from template using UPDATE
11265   *    If a CACHE_VALID entry is found, a new entry is swapped in with data
11266   *       from "template"
11267 - * If set == 1, and INPLACE == 1 :
11268 - *    As above, except that if a CACHE_VALID entry is found, we UPDATE in place
11269 - *       instead of swapping in a new entry.
11270   *
11271   * If the passed handle has the CACHE_NEGATIVE flag set, then UPDATE is not
11272   * run but insteead CACHE_NEGATIVE is set in any new item.
11273 @@ -153,21 +150,18 @@ struct cache_deferred_req {
11274   * MEMBER is the member of the cache which is cache_head, which must be first
11275   * FNAME is the name for the function  
11276   * ARGS are arguments to function and must contain RTN *item, int set.  May
11277 - *   also contain something to be usedby SETUP or DETAIL to find cache_detail.
11278 - * SETUP  locates the cache detail and makes it available as...
11279 - * DETAIL identifies the cache detail, possibly set up by SETUP
11280 + *   also contain something to be used by DETAIL to find cache_detail.
11281 + * DETAIL identifies the cache detail
11282   * HASHFN returns a hash value of the cache entry "item"
11283   * TEST  tests if "tmp" matches "item"
11284   * INIT copies key information from "item" to "new"
11285   * UPDATE copies content information from "item" to "tmp"
11286 - * INPLACE is true if updates can happen inplace rather than allocating a new structure
11287   */
11288 -#define DefineCacheLookup(RTN,MEMBER,FNAME,ARGS,SETUP,DETAIL,HASHFN,TEST,INIT,UPDATE,INPLACE)  \
11289 +#define DefineCacheLookup(RTN,MEMBER,FNAME,ARGS,DETAIL,HASHFN,TEST,INIT,UPDATE)        \
11290  RTN *FNAME ARGS                                                                                \
11291  {                                                                                      \
11292         RTN *tmp, *new=NULL;                                                            \
11293         struct cache_head **hp, **head;                                                 \
11294 -       SETUP;                                                                          \
11295         head = &(DETAIL)->hash_table[HASHFN];                                           \
11296   retry:                                                                                        \
11297         if (set||new) write_lock(&(DETAIL)->hash_lock);                                 \
11298 @@ -176,14 +170,14 @@ RTN *FNAME ARGS                                                                           \
11299                 tmp = container_of(*hp, RTN, MEMBER);                                   \
11300                 if (TEST) { /* found a match */                                         \
11301                                                                                         \
11302 -                       if (set && !INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \
11303 +                       if (set && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \
11304                                 break;                                                  \
11305                                                                                         \
11306                         if (new)                                                        \
11307                                 {INIT;}                                                 \
11308                         cache_get(&tmp->MEMBER);                                        \
11309                         if (set) {                                                      \
11310 -                               if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\
11311 +                               if (test_bit(CACHE_VALID, &tmp->MEMBER.flags))\
11312                                 { /* need to swap in new */                             \
11313                                         RTN *t2;                                        \
11314                                                                                         \
11315 @@ -205,7 +199,7 @@ RTN *FNAME ARGS                                                                             \
11316                         else read_unlock(&(DETAIL)->hash_lock);                         \
11317                         if (set)                                                        \
11318                                 cache_fresh(DETAIL, &tmp->MEMBER, item->MEMBER.expiry_time); \
11319 -                       if (set && !INPLACE && new) cache_fresh(DETAIL, &new->MEMBER, 0);       \
11320 +                       if (set && new) cache_fresh(DETAIL, &new->MEMBER, 0);   \
11321                         if (new) (DETAIL)->cache_put(&new->MEMBER, DETAIL);             \
11322                         return tmp;                                                     \
11323                 }                                                                       \
11324 @@ -233,16 +227,15 @@ RTN *FNAME ARGS                                                                           \
11325         new = kmalloc(sizeof(*new), GFP_KERNEL);                                        \
11326         if (new) {                                                                      \
11327                 cache_init(&new->MEMBER);                                               \
11328 -               cache_get(&new->MEMBER);                                                \
11329                 goto retry;                                                             \
11330         }                                                                               \
11331         return NULL;                                                                    \
11332  }
11333  
11334 -#define DefineSimpleCacheLookup(STRUCT,INPLACE)        \
11335 -       DefineCacheLookup(struct STRUCT, h, STRUCT##_lookup, (struct STRUCT *item, int set), /*no setup */,     \
11336 +#define DefineSimpleCacheLookup(STRUCT)        \
11337 +       DefineCacheLookup(struct STRUCT, h, STRUCT##_lookup, (struct STRUCT *item, int set),    \
11338                           & STRUCT##_cache, STRUCT##_hash(item), STRUCT##_match(item, tmp),\
11339 -                         STRUCT##_init(new, item), STRUCT##_update(tmp, item),INPLACE)
11340 +                         STRUCT##_init(new, item), STRUCT##_update(tmp, item))
11341  
11342  #define cache_for_each(pos, detail, index, member)                                             \
11343         for (({read_lock(&(detail)->hash_lock); index = (detail)->hash_size;}) ;                \
11344 --- linux-2.6.7/include/linux/sunrpc/xdr.h.lsec 2004-06-15 23:20:26.000000000 -0600
11345 +++ linux-2.6.7/include/linux/sunrpc/xdr.h      2005-03-23 14:28:24.783282064 -0700
11346 @@ -192,6 +192,7 @@ extern void xdr_write_pages(struct xdr_s
11347  extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
11348  extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
11349  extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
11350 +extern void truncate_xdr_buf(struct xdr_buf *xdr, int len);
11351  
11352  #endif /* __KERNEL__ */
11353  
11354 --- linux-2.6.7/include/linux/nfsd/state.h.lsec 2004-06-15 23:18:56.000000000 -0600
11355 +++ linux-2.6.7/include/linux/nfsd/state.h      2005-03-23 14:28:24.081388768 -0700
11356 @@ -38,6 +38,7 @@
11357  #define _NFSD4_STATE_H
11358  
11359  #include <linux/list.h>
11360 +#include <linux/sunrpc/clnt.h>
11361  
11362  #define NFS4_OPAQUE_LIMIT 1024
11363  typedef struct {
11364 @@ -65,6 +66,22 @@ extern stateid_t onestateid;
11365  #define ZERO_STATEID(stateid)       (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
11366  #define ONE_STATEID(stateid)        (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
11367  
11368 +/* client delegation callback info */
11369 +struct nfs4_callback {
11370 +       /* SETCLIENTID info */
11371 +       u32                     cb_parsed;  /* addr parsed */
11372 +       u32                     cb_addr;
11373 +       unsigned short          cb_port;
11374 +       u32                     cb_prog;
11375 +       u32                     cb_ident;
11376 +       struct xdr_netobj       cb_netid;
11377 +       /* RPC client info */
11378 +       u32                     cb_set;     /* successful CB_NULL call */
11379 +       struct rpc_program      cb_program;
11380 +       struct rpc_stat         cb_stat;
11381 +       struct rpc_clnt *       cb_client;
11382 +};
11383 +
11384  /*
11385   * struct nfs4_client - one per client.  Clientids live here.
11386   *     o Each nfs4_client is hashed by clientid.
11387 @@ -87,6 +104,21 @@ struct nfs4_client {
11388         struct svc_cred         cl_cred;        /* setclientid principal */
11389         clientid_t              cl_clientid;    /* generated by server */
11390         nfs4_verifier           cl_confirm;     /* generated by server */
11391 +       struct nfs4_callback    cl_callback;    /* callback info */
11392 +       time_t                  cl_first_state; /* first state aquisition*/
11393 +       atomic_t                cl_count;       /* ref count */
11394 +};
11395 +
11396 +/* struct nfs4_client_reset
11397 + * one per old client. Populates reset_str_hashtbl. Filled from conf_id_hashtbl
11398 + * upon lease reset, or from upcall to state_daemon (to read in state
11399 + * from non-volitile storage) upon reboot.
11400 + */
11401 +struct nfs4_client_reclaim {
11402 +       struct list_head        cr_strhash;     /* hash by cr_name */
11403 +       struct xdr_netobj       cr_name;        /* id generated by client */
11404 +       time_t                  cr_first_state; /* first state aquisition */
11405 +       u32                     cr_expired;     /* boolean: lease expired? */
11406  };
11407  
11408  static inline void
11409 @@ -216,5 +248,8 @@ extern int nfs4_share_conflict(struct sv
11410  extern void nfs4_lock_state(void);
11411  extern void nfs4_unlock_state(void);
11412  extern int nfs4_in_grace(void);
11413 -extern int nfs4_in_no_grace(void);
11414 +extern int nfs4_check_open_reclaim(clientid_t *clid);
11415 +extern void nfsd4_probe_callback(struct nfs4_client *clp);
11416 +extern void expire_client(struct nfs4_client *clp);
11417 +extern void put_nfs4_client(struct nfs4_client *clp);
11418  #endif   /* NFSD4_STATE_H */
11419 --- linux-2.6.7/include/linux/nfsd/nfsd.h.lsec  2004-06-15 23:20:04.000000000 -0600
11420 +++ linux-2.6.7/include/linux/nfsd/nfsd.h       2005-03-23 14:28:24.133380864 -0700
11421 @@ -76,6 +76,11 @@ int          nfsd_lookup(struct svc_rqst *, stru
11422                                 const char *, int, struct svc_fh *);
11423  int            nfsd_setattr(struct svc_rqst *, struct svc_fh *,
11424                                 struct iattr *, int, time_t);
11425 +#ifdef CONFIG_NFSD_V4
11426 +int             nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
11427 +                    struct nfs4_acl *);
11428 +int             nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
11429 +#endif /* CONFIG_NFSD_V4 */
11430  int            nfsd_create(struct svc_rqst *, struct svc_fh *,
11431                                 char *name, int len, struct iattr *attrs,
11432                                 int type, dev_t rdev, struct svc_fh *res);
11433 @@ -126,9 +131,13 @@ int                nfsd_permission(struct svc_export *
11434  #ifdef CONFIG_NFSD_V4
11435  void nfs4_state_init(void);
11436  void nfs4_state_shutdown(void);
11437 +time_t nfs4_lease_time(void);
11438 +void nfs4_reset_lease(time_t leasetime);
11439  #else
11440  void static inline nfs4_state_init(void){}
11441  void static inline nfs4_state_shutdown(void){}
11442 +time_t static inline nfs4_lease_time(void){return 0;}
11443 +void static inline nfs4_reset_lease(time_t leasetime){}
11444  #endif
11445  
11446  /*
11447 @@ -249,12 +258,11 @@ static inline int is_fsid(struct svc_fh 
11448  #define        COMPOUND_SLACK_SPACE            140    /* OP_GETFH */
11449  #define COMPOUND_ERR_SLACK_SPACE       12     /* OP_SETATTR */
11450  
11451 -#define NFSD_LEASE_TIME                        60  /* seconds */
11452 +#define NFSD_LEASE_TIME                 (nfs4_lease_time())
11453  #define NFSD_LAUNDROMAT_MINTIMEOUT      10   /* seconds */
11454  
11455  /*
11456   * The following attributes are currently not supported by the NFSv4 server:
11457 - *    ACL           (will be supported in a forthcoming patch)
11458   *    ARCHIVE       (deprecated anyway)
11459   *    FS_LOCATIONS  (will be supported eventually)
11460   *    HIDDEN        (unlikely to be supported any time soon)
11461 @@ -274,7 +282,7 @@ static inline int is_fsid(struct svc_fh 
11462   | FATTR4_WORD0_FILEHANDLE      | FATTR4_WORD0_FILEID       | FATTR4_WORD0_FILES_AVAIL      \
11463   | FATTR4_WORD0_FILES_FREE      | FATTR4_WORD0_FILES_TOTAL  | FATTR4_WORD0_HOMOGENEOUS      \
11464   | FATTR4_WORD0_MAXFILESIZE     | FATTR4_WORD0_MAXLINK      | FATTR4_WORD0_MAXNAME          \
11465 - | FATTR4_WORD0_MAXREAD         | FATTR4_WORD0_MAXWRITE)
11466 + | FATTR4_WORD0_MAXREAD         | FATTR4_WORD0_MAXWRITE     | FATTR4_WORD0_ACL)
11467  
11468  #define NFSD_SUPPORTED_ATTRS_WORD1                                                          \
11469  (FATTR4_WORD1_MODE              | FATTR4_WORD1_NO_TRUNC     | FATTR4_WORD1_NUMLINKS         \
11470 @@ -289,7 +297,8 @@ static inline int is_fsid(struct svc_fh 
11471  (FATTR4_WORD1_TIME_ACCESS_SET   | FATTR4_WORD1_TIME_MODIFY_SET)
11472  
11473  /* These are the only attrs allowed in CREATE/OPEN/SETATTR. */
11474 -#define NFSD_WRITEABLE_ATTRS_WORD0                            FATTR4_WORD0_SIZE
11475 +#define NFSD_WRITEABLE_ATTRS_WORD0                                                          \
11476 +(FATTR4_WORD0_SIZE              | FATTR4_WORD0_ACL                                         )
11477  #define NFSD_WRITEABLE_ATTRS_WORD1                                                          \
11478  (FATTR4_WORD1_MODE              | FATTR4_WORD1_OWNER         | FATTR4_WORD1_OWNER_GROUP     \
11479   | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET)
11480 --- linux-2.6.7/include/linux/nfsd/xdr4.h.lsec  2004-06-15 23:18:59.000000000 -0600
11481 +++ linux-2.6.7/include/linux/nfsd/xdr4.h       2005-03-23 14:28:24.082388616 -0700
11482 @@ -39,6 +39,8 @@
11483  #ifndef _LINUX_NFSD_XDR4_H
11484  #define _LINUX_NFSD_XDR4_H
11485  
11486 +#include <linux/nfs4.h>
11487 +
11488  #define NFSD4_MAX_TAGLEN       128
11489  #define XDR_LEN(n)                     (((n) + 3) & ~3)
11490  
11491 @@ -95,6 +97,7 @@ struct nfsd4_create {
11492         u32             cr_bmval[2];        /* request */
11493         struct iattr    cr_iattr;           /* request */
11494         struct nfsd4_change_info  cr_cinfo; /* response */
11495 +       struct nfs4_acl *cr_acl;
11496  };
11497  #define cr_linklen     u.link.namelen
11498  #define cr_linkname    u.link.name
11499 @@ -216,7 +219,7 @@ struct nfsd4_open {
11500         u32             op_rflags;          /* response */
11501         int             op_truncate;        /* used during processing */
11502         struct nfs4_stateowner *op_stateowner; /* used during processing */
11503 -
11504 +       struct nfs4_acl *op_acl;
11505  };
11506  #define op_iattr       u.iattr
11507  #define op_verf                u.verf
11508 @@ -291,6 +294,7 @@ struct nfsd4_setattr {
11509         stateid_t       sa_stateid;         /* request */
11510         u32             sa_bmval[2];        /* request */
11511         struct iattr    sa_iattr;           /* request */
11512 +       struct nfs4_acl *sa_acl;
11513  };
11514  
11515  struct nfsd4_setclientid {
11516 @@ -378,6 +382,7 @@ struct nfsd4_compoundargs {
11517         u32 *                           tmpp;
11518         struct tmpbuf {
11519                 struct tmpbuf *next;
11520 +               void (*release)(const void *);
11521                 void *buf;
11522         }                               *to_free;
11523  
11524 @@ -449,6 +454,7 @@ extern int nfsd4_locku(struct svc_rqst *
11525  extern int
11526  nfsd4_release_lockowner(struct svc_rqst *rqstp,
11527                 struct nfsd4_release_lockowner *rlockowner);
11528 +extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *);
11529  #endif
11530  
11531  /*
11532 --- linux-2.6.7/include/linux/nfs_fs.h.lsec     2004-06-15 23:19:13.000000000 -0600
11533 +++ linux-2.6.7/include/linux/nfs_fs.h  2005-03-23 14:28:23.338501704 -0700
11534 @@ -28,6 +28,7 @@
11535  #include <linux/nfs3.h>
11536  #include <linux/nfs4.h>
11537  #include <linux/nfs_xdr.h>
11538 +#include <linux/rwsem.h>
11539  #include <linux/workqueue.h>
11540  
11541  /*
11542 @@ -75,15 +76,33 @@
11543  #ifdef __KERNEL__
11544  
11545  /*
11546 - * NFSv3 Access mode cache
11547 + * NFSv3/v4 Access mode cache entry
11548   */
11549 -struct nfs_access_cache {
11550 +struct nfs_access_entry {
11551         unsigned long           jiffies;
11552         struct rpc_cred *       cred;
11553         int                     mask;
11554 -       int                     err;
11555  };
11556  
11557 +struct nfs4_state;
11558 +struct nfs_open_context {
11559 +       atomic_t count;
11560 +       struct dentry *dentry;
11561 +       struct rpc_cred *cred;
11562 +       struct nfs4_state *state;
11563 +       unsigned int pid;
11564 +       int mode;
11565 +       int error;
11566 +
11567 +       struct list_head list;
11568 +       wait_queue_head_t waitq;
11569 +};
11570 +
11571 +/*
11572 + * NFSv4 delegation
11573 + */
11574 +struct nfs_delegation;
11575 +
11576  /*
11577   * nfs fs inode data in memory
11578   */
11579 @@ -137,7 +156,7 @@ struct nfs_inode {
11580          */
11581         atomic_t                data_updates;
11582  
11583 -       struct nfs_access_cache cache_access;
11584 +       struct nfs_access_entry cache_access;
11585  
11586         /*
11587          * This is the cookie verifier used for NFSv3 readdir
11588 @@ -156,16 +175,20 @@ struct nfs_inode {
11589                                 ncommit,
11590                                 npages;
11591  
11592 -       /* Credentials for shared mmap */
11593 -       struct rpc_cred         *mm_cred;
11594 +       /* Open contexts for shared mmap writes */
11595 +       struct list_head        open_files;
11596  
11597         wait_queue_head_t       nfs_i_wait;
11598  
11599  #ifdef CONFIG_NFS_V4
11600          /* NFSv4 state */
11601         struct list_head        open_states;
11602 +       struct nfs_delegation   *delegation;
11603 +       int                      delegation_state;
11604 +       struct rw_semaphore     rwsem;
11605  #endif /* CONFIG_NFS_V4*/
11606 -
11607 +       void                    *acl;
11608 +       ssize_t                 acl_len;
11609         struct inode            vfs_inode;
11610  };
11611  
11612 @@ -259,6 +282,18 @@ static inline int nfs_verify_change_attr
11613                 && chattr == NFS_I(inode)->cache_change_attribute;
11614  }
11615  
11616 +/**
11617 + * nfs_compare_fh - compare two filehandles for equality
11618 + * @fh1 - pointer to first filehandle
11619 + * @fh2 - pointer to second filehandle
11620 + */
11621 +static inline int nfs_compare_fh(const struct nfs_fh *fh1, const struct nfs_fh *fh2)
11622 +{
11623 +       if (fh1->size == fh2->size)
11624 +               return memcmp(fh1->data, fh2->data, fh1->size);
11625 +       return (fh1->size > fh2->size) ? 1 : -1;
11626 +}
11627 +
11628  /*
11629   * linux/fs/nfs/inode.c
11630   */
11631 @@ -268,9 +303,12 @@ extern struct inode *nfs_fhget(struct su
11632  extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
11633  extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
11634  extern int nfs_permission(struct inode *, int, struct nameidata *);
11635 -extern void nfs_set_mmcred(struct inode *, struct rpc_cred *);
11636 +extern int nfs_access_get_cached(struct inode *, struct rpc_cred *, struct nfs_access_entry *);
11637 +extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *);
11638  extern int nfs_open(struct inode *, struct file *);
11639  extern int nfs_release(struct inode *, struct file *);
11640 +extern int nfs_attribute_timeout(struct inode *inode);
11641 +extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode);
11642  extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
11643  extern int nfs_setattr(struct dentry *, struct iattr *);
11644  extern void nfs_begin_attr_update(struct inode *);
11645 @@ -278,6 +316,12 @@ extern void nfs_end_attr_update(struct i
11646  extern void nfs_begin_data_update(struct inode *);
11647  extern void nfs_end_data_update(struct inode *);
11648  extern void nfs_end_data_update_defer(struct inode *);
11649 +extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, struct rpc_cred *cred);
11650 +extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
11651 +extern void put_nfs_open_context(struct nfs_open_context *ctx);
11652 +extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx);
11653 +extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, int mode);
11654 +extern void nfs_file_clear_open_context(struct file *filp);
11655  
11656  /* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
11657  extern u32 root_nfs_parse_addr(char *name); /*__init*/
11658 @@ -289,16 +333,15 @@ extern struct inode_operations nfs_file_
11659  extern struct file_operations nfs_file_operations;
11660  extern struct address_space_operations nfs_file_aops;
11661  
11662 -static __inline__ struct rpc_cred *
11663 -nfs_file_cred(struct file *file)
11664 +static inline struct rpc_cred *nfs_file_cred(struct file *file)
11665  {
11666 -       struct rpc_cred *cred = NULL;
11667 -       if (file)
11668 -               cred = (struct rpc_cred *)file->private_data;
11669 -#ifdef RPC_DEBUG
11670 -       BUG_ON(cred && cred->cr_magic != RPCAUTH_CRED_MAGIC);
11671 -#endif
11672 -       return cred;
11673 +       if (file != NULL) {
11674 +               struct nfs_open_context *ctx;
11675 +
11676 +               ctx = (struct nfs_open_context*)file->private_data;
11677 +               return ctx->cred;
11678 +       }
11679 +       return NULL;
11680  }
11681  
11682  /*
11683 @@ -418,28 +461,6 @@ extern int  nfsroot_mount(struct sockadd
11684   * inline functions
11685   */
11686  
11687 -static inline int nfs_attribute_timeout(struct inode *inode)
11688 -{
11689 -       struct nfs_inode *nfsi = NFS_I(inode);
11690 -
11691 -       return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
11692 -}
11693 -
11694 -/**
11695 - * nfs_revalidate_inode - Revalidate the inode attributes
11696 - * @server - pointer to nfs_server struct
11697 - * @inode - pointer to inode struct
11698 - *
11699 - * Updates inode attribute information by retrieving the data from the server.
11700 - */
11701 -static inline int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
11702 -{
11703 -       if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
11704 -                       && !nfs_attribute_timeout(inode))
11705 -               return NFS_STALE(inode) ? -ESTALE : 0;
11706 -       return __nfs_revalidate_inode(server, inode);
11707 -}
11708 -
11709  static inline loff_t
11710  nfs_size_to_loff_t(__u64 size)
11711  {
11712 @@ -507,8 +528,6 @@ struct idmap;
11713  
11714  enum nfs4_client_state {
11715         NFS4CLNT_OK  = 0,
11716 -       NFS4CLNT_NEW,
11717 -       NFS4CLNT_SETUP_STATE,
11718  };
11719  
11720  /*
11721 @@ -520,7 +539,6 @@ struct nfs4_client {
11722         u64                     cl_clientid;    /* constant */
11723         nfs4_verifier           cl_confirm;
11724         unsigned long           cl_state;
11725 -       long                    cl_generation;
11726  
11727         u32                     cl_lockowner_id;
11728  
11729 @@ -530,6 +548,7 @@ struct nfs4_client {
11730          */
11731         struct rw_semaphore     cl_sem;
11732  
11733 +       struct list_head        cl_delegations;
11734         struct list_head        cl_state_owners;
11735         struct list_head        cl_unused;
11736         int                     cl_nunused;
11737 @@ -573,12 +592,11 @@ struct nfs4_state_owner {
11738         u32                  so_id;      /* 32-bit identifier, unique */
11739         struct semaphore     so_sema;
11740         u32                  so_seqid;   /* protected by so_sema */
11741 -       unsigned int         so_flags;   /* protected by so_sema */
11742         atomic_t             so_count;
11743 -       long                 so_generation;
11744  
11745         struct rpc_cred      *so_cred;   /* Associated cred */
11746         struct list_head     so_states;
11747 +       struct list_head     so_delegations;
11748  };
11749  
11750  /*
11751 @@ -593,10 +611,13 @@ struct nfs4_state_owner {
11752   * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN)
11753   */
11754  
11755 +/* bits for nfs4_lock_state->flags */
11756 +
11757  struct nfs4_lock_state {
11758         struct list_head        ls_locks;       /* Other lock stateids */
11759 -       fl_owner_t              ls_owner;       /* POSIX lock owner */
11760 -       struct nfs4_state *     ls_parent;      /* Parent nfs4_state */
11761 +       unsigned int            ls_pid;         /* pid of owner process */
11762 +#define NFS_LOCK_INITIALIZED 1
11763 +       int                     flags;
11764         u32                     ls_seqid;
11765         u32                     ls_id;
11766         nfs4_stateid            ls_stateid;
11767 @@ -606,6 +627,7 @@ struct nfs4_lock_state {
11768  /* bits for nfs4_state->flags */
11769  enum {
11770         LK_STATE_IN_USE,
11771 +       NFS_DELEGATED_STATE,
11772  };
11773  
11774  struct nfs4_state {
11775 @@ -629,8 +651,19 @@ struct nfs4_state {
11776  };
11777  
11778  
11779 +struct nfs4_exception {
11780 +       long timeout;
11781 +       int retry;
11782 +};
11783 +
11784  extern struct dentry_operations nfs4_dentry_operations;
11785  extern struct inode_operations nfs4_dir_inode_operations;
11786 +extern struct inode_operations nfs4_file_inode_operations;
11787 +
11788 +/* inode.c */
11789 +extern ssize_t nfs_getxattr(struct dentry *, const char *, void *, size_t);
11790 +extern int nfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
11791 +extern ssize_t nfs_listxattr(struct dentry *, char *, size_t);
11792  
11793  /* nfs4proc.c */
11794  extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
11795 @@ -639,10 +672,15 @@ extern int nfs4_open_reclaim(struct nfs4
11796  extern int nfs4_proc_async_renew(struct nfs4_client *);
11797  extern int nfs4_proc_renew(struct nfs4_client *);
11798  extern int nfs4_do_close(struct inode *, struct nfs4_state *);
11799 -int nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode);
11800 +extern int nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode);
11801  extern int nfs4_wait_clnt_recover(struct rpc_clnt *, struct nfs4_client *);
11802  extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
11803  extern int nfs4_open_revalidate(struct inode *, struct dentry *, int);
11804 +extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *);
11805 +extern int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request);
11806 +extern ssize_t nfs4_proc_get_acl(struct inode *, void *buf, ssize_t buflen);
11807 +extern int nfs4_proc_set_acl(struct inode *, const void *buf, ssize_t buflen);
11808 +extern void nfs4_zap_acl_attr(struct inode *inode);
11809  
11810  /* nfs4renewd.c */
11811  extern void nfs4_schedule_state_renewal(struct nfs4_client *);
11812 @@ -654,6 +692,8 @@ extern void init_nfsv4_state(struct nfs_
11813  extern void destroy_nfsv4_state(struct nfs_server *);
11814  extern struct nfs4_client *nfs4_get_client(struct in_addr *);
11815  extern void nfs4_put_client(struct nfs4_client *clp);
11816 +extern int nfs4_init_client(struct nfs4_client *clp);
11817 +extern struct nfs4_client *nfs4_find_client(struct in_addr *);
11818  extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);
11819  
11820  extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
11821 @@ -663,15 +703,14 @@ extern void nfs4_put_open_state(struct n
11822  extern void nfs4_close_state(struct nfs4_state *, mode_t);
11823  extern struct nfs4_state *nfs4_find_state(struct inode *, struct rpc_cred *, mode_t mode);
11824  extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp);
11825 -extern int nfs4_handle_error(struct nfs_server *, int);
11826  extern void nfs4_schedule_state_recovery(struct nfs4_client *);
11827 -extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t);
11828 -extern struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t);
11829 +extern struct nfs4_lock_state *nfs4_find_lock_state(struct nfs4_state *state, unsigned int pid);
11830 +extern struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, unsigned int pid);
11831  extern void nfs4_put_lock_state(struct nfs4_lock_state *state);
11832  extern void nfs4_increment_lock_seqid(int status, struct nfs4_lock_state *ls);
11833 -extern void nfs4_notify_setlk(struct inode *, struct file_lock *, struct nfs4_lock_state *);
11834 -extern void nfs4_notify_unlck(struct inode *, struct file_lock *, struct nfs4_lock_state *);
11835 -extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t);
11836 +extern void nfs4_notify_setlk(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *);
11837 +extern void nfs4_notify_unlck(struct nfs4_state *, struct file_lock *, struct nfs4_lock_state *);
11838 +extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, unsigned int pid);
11839  
11840  
11841  
11842 @@ -681,6 +720,7 @@ struct nfs4_mount_data;
11843  #define destroy_nfsv4_state(server)       do { } while (0)
11844  #define nfs4_put_state_owner(inode, owner) do { } while (0)
11845  #define nfs4_put_open_state(state) do { } while (0)
11846 +#define nfs4_close_state(a, b) do { } while (0)
11847  #define nfs4_renewd_prepare_shutdown(server) do { } while (0)
11848  #endif
11849  
11850 @@ -697,6 +737,7 @@ struct nfs4_mount_data;
11851  #define NFSDBG_XDR             0x0020
11852  #define NFSDBG_FILE            0x0040
11853  #define NFSDBG_ROOT            0x0080
11854 +#define NFSDBG_CALLBACK                0x0100
11855  #define NFSDBG_ALL             0xFFFF
11856  
11857  #ifdef __KERNEL__
11858 --- linux-2.6.7/include/linux/nfs4_acl.h.lsec   2005-03-23 14:28:24.519322192 -0700
11859 +++ linux-2.6.7/include/linux/nfs4_acl.h        2005-03-23 14:28:24.518322344 -0700
11860 @@ -0,0 +1,59 @@
11861 +/*
11862 + *  include/linux/nfs4_acl.c
11863 + *
11864 + *  Common NFSv4 ACL handling definitions.
11865 + *
11866 + *  Copyright (c) 2002 The Regents of the University of Michigan.
11867 + *  All rights reserved.
11868 + *
11869 + *  Marius Aamodt Eriksen <marius@umich.edu>
11870 + *
11871 + *  Redistribution and use in source and binary forms, with or without
11872 + *  modification, are permitted provided that the following conditions
11873 + *  are met:
11874 + *
11875 + *  1. Redistributions of source code must retain the above copyright
11876 + *     notice, this list of conditions and the following disclaimer.
11877 + *  2. Redistributions in binary form must reproduce the above copyright
11878 + *     notice, this list of conditions and the following disclaimer in the
11879 + *     documentation and/or other materials provided with the distribution.
11880 + *  3. Neither the name of the University nor the names of its
11881 + *     contributors may be used to endorse or promote products derived
11882 + *     from this software without specific prior written permission.
11883 + *
11884 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
11885 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
11886 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
11887 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
11888 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
11889 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
11890 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
11891 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
11892 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
11893 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
11894 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
11895 + */
11896 +
11897 +#ifndef LINUX_NFS4_ACL_H
11898 +#define LINUX_NFS4_ACL_H
11899 +
11900 +#include <linux/posix_acl.h>
11901 +
11902 +struct nfs4_acl *nfs4_acl_new(void);
11903 +void nfs4_acl_free(struct nfs4_acl *);
11904 +int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
11905 +int nfs4_acl_get_whotype(char *, u32);
11906 +int nfs4_acl_write_who(int who, char *p);
11907 +int nfs4_acl_permission(struct nfs4_acl *acl, uid_t owner, gid_t group,
11908 +                                       uid_t who, u32 mask);
11909 +
11910 +#define NFS4_ACL_TYPE_DEFAULT  0x01
11911 +#define NFS4_ACL_DIR           0x02
11912 +#define NFS4_ACL_OWNER         0x04
11913 +
11914 +struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *,
11915 +                               struct posix_acl *, unsigned int flags);
11916 +int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *, struct posix_acl **,
11917 +                               struct posix_acl **, unsigned int flags);
11918 +
11919 +#endif /* LINUX_NFS4_ACL_H */
11920 --- linux-2.6.7/include/linux/nfs_xdr.h.lsec    2004-06-15 23:19:52.000000000 -0600
11921 +++ linux-2.6.7/include/linux/nfs_xdr.h 2005-03-23 14:28:23.539471152 -0700
11922 @@ -99,20 +99,21 @@ struct nfs4_change_info {
11923   * Arguments to the open call.
11924   */
11925  struct nfs_openargs {
11926 -       struct nfs_fh *         fh;
11927 +       const struct nfs_fh *   fh;
11928         __u32                   seqid;
11929 -       __u32                   share_access;
11930 +       int                     open_flags;
11931         __u64                   clientid;
11932         __u32                   id;
11933 -       __u32                   opentype;
11934 -       __u32                   createmode;
11935         union {
11936                 struct iattr *  attrs;    /* UNCHECKED, GUARDED */
11937                 nfs4_verifier   verifier; /* EXCLUSIVE */
11938 +               nfs4_stateid    delegation;             /* CLAIM_DELEGATE_CUR */
11939 +               int             delegation_type;        /* CLAIM_PREVIOUS */
11940         } u;
11941         const struct qstr *     name;
11942         const struct nfs_server *server;         /* Needed for ID mapping */
11943         const u32 *             bitmask;
11944 +       __u32                   claim;
11945  };
11946  
11947  struct nfs_openres {
11948 @@ -122,13 +123,17 @@ struct nfs_openres {
11949         __u32                   rflags;
11950         struct nfs_fattr *      f_attr;
11951         const struct nfs_server *server;
11952 +       int                     delegation_type;
11953 +       nfs4_stateid            delegation;
11954 +       __u32                   do_recall;
11955 +       __u64                   maxsize;
11956  };
11957  
11958  /*
11959   * Arguments to the open_confirm call.
11960   */
11961  struct nfs_open_confirmargs {
11962 -       struct nfs_fh *         fh;
11963 +       const struct nfs_fh *   fh;
11964         nfs4_stateid            stateid;
11965         __u32                   seqid;
11966  };
11967 @@ -138,26 +143,13 @@ struct nfs_open_confirmres {
11968  };
11969  
11970  /*
11971 - * Arguments to the open_reclaim call.
11972 - */
11973 -struct nfs_open_reclaimargs {
11974 -       struct nfs_fh *         fh;
11975 -       __u64                   clientid;
11976 -       __u32                   seqid;
11977 -       __u32                   id;
11978 -       __u32                   share_access;
11979 -       __u32                   claim;
11980 -       const __u32 *           bitmask;
11981 -};
11982 -
11983 -/*
11984   * Arguments to the close call.
11985   */
11986  struct nfs_closeargs {
11987         struct nfs_fh *         fh;
11988         nfs4_stateid            stateid;
11989         __u32                   seqid;
11990 -       __u32                   share_access;
11991 +       int                     open_flags;
11992  };
11993  
11994  struct nfs_closeres {
11995 @@ -224,6 +216,11 @@ struct nfs_lockres {
11996         const struct nfs_server *       server;
11997  };
11998  
11999 +struct nfs4_delegreturnargs {
12000 +       const struct nfs_fh *fhandle;
12001 +       const nfs4_stateid *stateid;
12002 +};
12003 +
12004  /*
12005   * Arguments to the read call.
12006   */
12007 @@ -235,8 +232,7 @@ struct nfs_lockres {
12008  
12009  struct nfs_readargs {
12010         struct nfs_fh *         fh;
12011 -       fl_owner_t              lockowner;
12012 -       struct nfs4_state *     state;
12013 +       struct nfs_open_context *context;
12014         __u64                   offset;
12015         __u32                   count;
12016         unsigned int            pgbase;
12017 @@ -259,8 +255,7 @@ struct nfs_readres {
12018  
12019  struct nfs_writeargs {
12020         struct nfs_fh *         fh;
12021 -       fl_owner_t              lockowner;
12022 -       struct nfs4_state *     state;
12023 +       struct nfs_open_context *context;
12024         __u64                   offset;
12025         __u32                   count;
12026         enum nfs3_stable_how    stable;
12027 @@ -331,6 +326,19 @@ struct nfs_setattrargs {
12028         const u32 *                     bitmask;
12029  };
12030  
12031 +struct nfs_setaclargs {
12032 +       struct nfs_fh *                 fh;
12033 +       const char *                    acl;
12034 +       ssize_t                         acl_len;
12035 +       const struct nfs_server *       server; /* Needed for name mapping */
12036 +};
12037 +
12038 +struct nfs_getaclres {
12039 +       char *                          acl;
12040 +       ssize_t                         acl_len;
12041 +       const struct nfs_server  *      server; /* Needed for name mapping */
12042 +};
12043 +
12044  struct nfs_setattrres {
12045         struct nfs_fattr *              fattr;
12046         const struct nfs_server *       server;
12047 @@ -597,13 +605,15 @@ struct nfs4_rename_res {
12048  };
12049  
12050  struct nfs4_setclientid {
12051 -       nfs4_verifier                   sc_verifier;      /* request */
12052 -       char *                          sc_name;          /* request */
12053 +       const nfs4_verifier *           sc_verifier;      /* request */
12054 +       unsigned int                    sc_name_len;
12055 +       char                            sc_name[32];      /* request */
12056         u32                             sc_prog;          /* request */
12057 +       unsigned int                    sc_netid_len;
12058         char                            sc_netid[4];      /* request */
12059 +       unsigned int                    sc_uaddr_len;
12060         char                            sc_uaddr[24];     /* request */
12061         u32                             sc_cb_ident;      /* request */
12062 -       struct nfs4_client *            sc_state;         /* response */
12063  };
12064  
12065  struct nfs4_statfs_arg {
12066 @@ -657,6 +667,8 @@ struct nfs_write_data {
12067         void (*complete) (struct nfs_write_data *, int);
12068  };
12069  
12070 +struct nfs_access_entry;
12071 +
12072  /*
12073   * RPC procedure vector for NFSv2/NFSv3 demuxing
12074   */
12075 @@ -664,6 +676,7 @@ struct nfs_rpc_ops {
12076         int     version;                /* Protocol version */
12077         struct dentry_operations *dentry_ops;
12078         struct inode_operations *dir_inode_ops;
12079 +       struct inode_operations *file_inode_ops;
12080  
12081         int     (*getroot) (struct nfs_server *, struct nfs_fh *,
12082                             struct nfs_fsinfo *);
12083 @@ -672,11 +685,11 @@ struct nfs_rpc_ops {
12084                             struct iattr *);
12085         int     (*lookup)  (struct inode *, struct qstr *,
12086                             struct nfs_fh *, struct nfs_fattr *);
12087 -       int     (*access)  (struct inode *, struct rpc_cred *, int);
12088 +       int     (*access)  (struct inode *, struct nfs_access_entry *);
12089         int     (*readlink)(struct inode *, struct page *);
12090 -       int     (*read)    (struct nfs_read_data *, struct file *);
12091 -       int     (*write)   (struct nfs_write_data *, struct file *);
12092 -       int     (*commit)  (struct nfs_write_data *, struct file *);
12093 +       int     (*read)    (struct nfs_read_data *);
12094 +       int     (*write)   (struct nfs_write_data *);
12095 +       int     (*commit)  (struct nfs_write_data *);
12096         struct inode *  (*create)  (struct inode *, struct qstr *,
12097                             struct iattr *, int);
12098         int     (*remove)  (struct inode *, struct qstr *);
12099 @@ -708,8 +721,6 @@ struct nfs_rpc_ops {
12100         void    (*commit_setup) (struct nfs_write_data *, int how);
12101         int     (*file_open)   (struct inode *, struct file *);
12102         int     (*file_release) (struct inode *, struct file *);
12103 -       void    (*request_init)(struct nfs_page *, struct file *);
12104 -       int     (*request_compatible)(struct nfs_page *, struct file *, struct page *);
12105         int     (*lock)(struct file *, int, struct file_lock *);
12106  };
12107  
12108 --- linux-2.6.7/arch/s390/defconfig.lsec        2004-06-15 23:19:52.000000000 -0600
12109 +++ linux-2.6.7/arch/s390/defconfig     2005-03-23 14:28:23.869420992 -0700
12110 @@ -422,7 +422,7 @@ CONFIG_NFS_V3=y
12111  CONFIG_NFSD=y
12112  CONFIG_NFSD_V3=y
12113  # CONFIG_NFSD_V4 is not set
12114 -# CONFIG_NFSD_TCP is not set
12115 +CONFIG_NFSD_TCP=y
12116  CONFIG_LOCKD=y
12117  CONFIG_LOCKD_V4=y
12118  CONFIG_EXPORTFS=y
12119 --- linux-2.6.7/arch/ia64/defconfig.lsec        2004-06-15 23:18:57.000000000 -0600
12120 +++ linux-2.6.7/arch/ia64/defconfig     2005-03-23 14:28:23.816429048 -0700
12121 @@ -987,7 +987,7 @@ CONFIG_NFS_DIRECTIO=y
12122  CONFIG_NFSD=y
12123  CONFIG_NFSD_V3=y
12124  # CONFIG_NFSD_V4 is not set
12125 -# CONFIG_NFSD_TCP is not set
12126 +CONFIG_NFSD_TCP=y
12127  CONFIG_LOCKD=y
12128  CONFIG_LOCKD_V4=y
12129  CONFIG_EXPORTFS=y
12130 --- linux-2.6.7/arch/ppc/defconfig.lsec 2004-06-15 23:19:52.000000000 -0600
12131 +++ linux-2.6.7/arch/ppc/defconfig      2005-03-23 14:28:23.817428896 -0700
12132 @@ -1230,7 +1230,7 @@ CONFIG_NFS_V3=y
12133  CONFIG_NFSD=y
12134  CONFIG_NFSD_V3=y
12135  # CONFIG_NFSD_V4 is not set
12136 -# CONFIG_NFSD_TCP is not set
12137 +CONFIG_NFSD_TCP=y
12138  CONFIG_LOCKD=y
12139  CONFIG_LOCKD_V4=y
12140  CONFIG_EXPORTFS=y
12141 --- linux-2.6.7/arch/i386/defconfig.lsec        2004-06-15 23:19:42.000000000 -0600
12142 +++ linux-2.6.7/arch/i386/defconfig     2005-03-23 14:28:23.763437104 -0700
12143 @@ -1148,7 +1148,7 @@ CONFIG_NFS_FS=y
12144  # CONFIG_NFS_DIRECTIO is not set
12145  CONFIG_NFSD=y
12146  # CONFIG_NFSD_V3 is not set
12147 -# CONFIG_NFSD_TCP is not set
12148 +CONFIG_NFSD_TCP=y
12149  CONFIG_LOCKD=y
12150  CONFIG_EXPORTFS=y
12151  CONFIG_SUNRPC=y
12152 --- linux-2.6.7/arch/alpha/defconfig.lsec       2004-06-15 23:19:23.000000000 -0600
12153 +++ linux-2.6.7/arch/alpha/defconfig    2005-03-23 14:28:23.762437256 -0700
12154 @@ -791,7 +791,7 @@ CONFIG_NFS_V3=y
12155  CONFIG_NFSD=m
12156  CONFIG_NFSD_V3=y
12157  # CONFIG_NFSD_V4 is not set
12158 -# CONFIG_NFSD_TCP is not set
12159 +CONFIG_NFSD_TCP=y
12160  CONFIG_LOCKD=m
12161  CONFIG_LOCKD_V4=y
12162  CONFIG_EXPORTFS=m
12163 --- linux-2.6.7/net/sunrpc/svcauth_unix.c.lsec  2004-06-15 23:19:37.000000000 -0600
12164 +++ linux-2.6.7/net/sunrpc/svcauth_unix.c       2005-03-23 14:28:24.295356240 -0700
12165 @@ -55,12 +55,10 @@ struct auth_domain *unix_domain_find(cha
12166         if (new == NULL)
12167                 return NULL;
12168         cache_init(&new->h.h);
12169 -       atomic_inc(&new->h.h.refcnt);
12170         new->h.name = strdup(name);
12171         new->h.flavour = RPC_AUTH_UNIX;
12172         new->addr_changes = 0;
12173         new->h.h.expiry_time = NEVER;
12174 -       new->h.h.flags = 0;
12175  
12176         rv = auth_domain_lookup(&new->h, 2);
12177         if (rv == &new->h) {
12178 @@ -262,7 +260,7 @@ struct cache_detail ip_map_cache = {
12179         .cache_show     = ip_map_show,
12180  };
12181  
12182 -static DefineSimpleCacheLookup(ip_map, 0)
12183 +static DefineSimpleCacheLookup(ip_map)
12184  
12185  
12186  int auth_unix_add_addr(struct in_addr addr, struct auth_domain *dom)
12187 @@ -318,7 +316,8 @@ struct auth_domain *auth_unix_lookup(str
12188                 return NULL;
12189  
12190         if ((ipm->m_client->addr_changes - ipm->m_add_change) >0) {
12191 -               set_bit(CACHE_NEGATIVE, &ipm->h.flags);
12192 +               if (test_and_set_bit(CACHE_NEGATIVE, &ipm->h.flags) == 0)
12193 +                       auth_domain_put(&ipm->m_client->h);
12194                 rv = NULL;
12195         } else {
12196                 rv = &ipm->m_client->h;
12197 @@ -405,6 +404,9 @@ svcauth_null_release(struct svc_rqst *rq
12198         if (rqstp->rq_client)
12199                 auth_domain_put(rqstp->rq_client);
12200         rqstp->rq_client = NULL;
12201 +       if (rqstp->rq_cred.cr_group_info)
12202 +               put_group_info(rqstp->rq_cred.cr_group_info);
12203 +       rqstp->rq_cred.cr_group_info = NULL;
12204  
12205         return 0; /* don't drop */
12206  }
12207 --- linux-2.6.7/net/sunrpc/xprt.c.lsec  2004-06-15 23:19:42.000000000 -0600
12208 +++ linux-2.6.7/net/sunrpc/xprt.c       2005-03-23 14:28:23.706445768 -0700
12209 @@ -1099,7 +1099,7 @@ xprt_write_space(struct sock *sk)
12210                 goto out;
12211  
12212         spin_lock_bh(&xprt->sock_lock);
12213 -       if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
12214 +       if (xprt->snd_task)
12215                 rpc_wake_up_task(xprt->snd_task);
12216         spin_unlock_bh(&xprt->sock_lock);
12217  out:
12218 @@ -1357,6 +1357,7 @@ xprt_request_init(struct rpc_task *task,
12219         req->rq_task    = task;
12220         req->rq_xprt    = xprt;
12221         req->rq_xid     = xprt_alloc_xid(xprt);
12222 +       req->rq_release_snd_buf = NULL;
12223         dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid,
12224                         req, req->rq_xid);
12225  }
12226 @@ -1382,6 +1383,8 @@ xprt_release(struct rpc_task *task)
12227                 mod_timer(&xprt->timer, xprt->last_used + XPRT_IDLE_TIMEOUT);
12228         spin_unlock_bh(&xprt->sock_lock);
12229         task->tk_rqstp = NULL;
12230 +       if (req->rq_release_snd_buf)
12231 +               req->rq_release_snd_buf(req);
12232         memset(req, 0, sizeof(*req));   /* mark unused */
12233  
12234         dprintk("RPC: %4d release request %p\n", task->tk_pid, req);
12235 --- linux-2.6.7/net/sunrpc/sched.c.lsec 2004-06-15 23:19:35.000000000 -0600
12236 +++ linux-2.6.7/net/sunrpc/sched.c      2005-03-23 14:28:23.651454128 -0700
12237 @@ -41,13 +41,7 @@ static mempool_t     *rpc_buffer_mempool;
12238  
12239  static void                    __rpc_default_timer(struct rpc_task *task);
12240  static void                    rpciod_killall(void);
12241 -
12242 -/*
12243 - * When an asynchronous RPC task is activated within a bottom half
12244 - * handler, or while executing another RPC task, it is put on
12245 - * schedq, and rpciod is woken up.
12246 - */
12247 -static RPC_WAITQ(schedq, "schedq");
12248 +static void                    rpc_async_schedule(void *);
12249  
12250  /*
12251   * RPC tasks that create another task (e.g. for contacting the portmapper)
12252 @@ -68,26 +62,18 @@ static LIST_HEAD(all_tasks);
12253  /*
12254   * rpciod-related stuff
12255   */
12256 -static DECLARE_WAIT_QUEUE_HEAD(rpciod_idle);
12257 -static DECLARE_COMPLETION(rpciod_killer);
12258  static DECLARE_MUTEX(rpciod_sema);
12259  static unsigned int            rpciod_users;
12260 -static pid_t                   rpciod_pid;
12261 -static int                     rpc_inhibit;
12262 +static struct workqueue_struct *rpciod_workqueue;
12263  
12264  /*
12265 - * Spinlock for wait queues. Access to the latter also has to be
12266 - * interrupt-safe in order to allow timers to wake up sleeping tasks.
12267 - */
12268 -static spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
12269 -/*
12270   * Spinlock for other critical sections of code.
12271   */
12272  static spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED;
12273  
12274  /*
12275   * Disable the timer for a given RPC task. Should be called with
12276 - * rpc_queue_lock and bh_disabled in order to avoid races within
12277 + * queue->lock and bh_disabled in order to avoid races within
12278   * rpc_run_timer().
12279   */
12280  static inline void
12281 @@ -105,16 +91,13 @@ __rpc_disable_timer(struct rpc_task *tas
12282   * without calling del_timer_sync(). The latter could cause a
12283   * deadlock if called while we're holding spinlocks...
12284   */
12285 -static void
12286 -rpc_run_timer(struct rpc_task *task)
12287 +static void rpc_run_timer(struct rpc_task *task)
12288  {
12289         void (*callback)(struct rpc_task *);
12290  
12291 -       spin_lock_bh(&rpc_queue_lock);
12292         callback = task->tk_timeout_fn;
12293         task->tk_timeout_fn = NULL;
12294 -       spin_unlock_bh(&rpc_queue_lock);
12295 -       if (callback) {
12296 +       if (callback && RPC_IS_QUEUED(task)) {
12297                 dprintk("RPC: %4d running timer\n", task->tk_pid);
12298                 callback(task);
12299         }
12300 @@ -140,19 +123,8 @@ __rpc_add_timer(struct rpc_task *task, r
12301  }
12302  
12303  /*
12304 - * Set up a timer for an already sleeping task.
12305 - */
12306 -void rpc_add_timer(struct rpc_task *task, rpc_action timer)
12307 -{
12308 -       spin_lock_bh(&rpc_queue_lock);
12309 -       if (!RPC_IS_RUNNING(task))
12310 -               __rpc_add_timer(task, timer);
12311 -       spin_unlock_bh(&rpc_queue_lock);
12312 -}
12313 -
12314 -/*
12315   * Delete any timer for the current task. Because we use del_timer_sync(),
12316 - * this function should never be called while holding rpc_queue_lock.
12317 + * this function should never be called while holding queue->lock.
12318   */
12319  static inline void
12320  rpc_delete_timer(struct rpc_task *task)
12321 @@ -169,16 +141,17 @@ static void __rpc_add_wait_queue_priorit
12322         struct list_head *q;
12323         struct rpc_task *t;
12324  
12325 +       INIT_LIST_HEAD(&task->u.tk_wait.links);
12326         q = &queue->tasks[task->tk_priority];
12327         if (unlikely(task->tk_priority > queue->maxpriority))
12328                 q = &queue->tasks[queue->maxpriority];
12329 -       list_for_each_entry(t, q, tk_list) {
12330 +       list_for_each_entry(t, q, u.tk_wait.list) {
12331                 if (t->tk_cookie == task->tk_cookie) {
12332 -                       list_add_tail(&task->tk_list, &t->tk_links);
12333 +                       list_add_tail(&task->u.tk_wait.list, &t->u.tk_wait.links);
12334                         return;
12335                 }
12336         }
12337 -       list_add_tail(&task->tk_list, q);
12338 +       list_add_tail(&task->u.tk_wait.list, q);
12339  }
12340  
12341  /*
12342 @@ -189,37 +162,21 @@ static void __rpc_add_wait_queue_priorit
12343   * improve overall performance.
12344   * Everyone else gets appended to the queue to ensure proper FIFO behavior.
12345   */
12346 -static int __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
12347 +static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
12348  {
12349 -       if (task->tk_rpcwait == queue)
12350 -               return 0;
12351 +       BUG_ON (RPC_IS_QUEUED(task));
12352  
12353 -       if (task->tk_rpcwait) {
12354 -               printk(KERN_WARNING "RPC: doubly enqueued task!\n");
12355 -               return -EWOULDBLOCK;
12356 -       }
12357         if (RPC_IS_PRIORITY(queue))
12358                 __rpc_add_wait_queue_priority(queue, task);
12359         else if (RPC_IS_SWAPPER(task))
12360 -               list_add(&task->tk_list, &queue->tasks[0]);
12361 +               list_add(&task->u.tk_wait.list, &queue->tasks[0]);
12362         else
12363 -               list_add_tail(&task->tk_list, &queue->tasks[0]);
12364 -       task->tk_rpcwait = queue;
12365 +               list_add_tail(&task->u.tk_wait.list, &queue->tasks[0]);
12366 +       task->u.tk_wait.rpc_waitq = queue;
12367 +       rpc_set_queued(task);
12368  
12369         dprintk("RPC: %4d added to queue %p \"%s\"\n",
12370                                 task->tk_pid, queue, rpc_qname(queue));
12371 -
12372 -       return 0;
12373 -}
12374 -
12375 -int rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task)
12376 -{
12377 -       int             result;
12378 -
12379 -       spin_lock_bh(&rpc_queue_lock);
12380 -       result = __rpc_add_wait_queue(q, task);
12381 -       spin_unlock_bh(&rpc_queue_lock);
12382 -       return result;
12383  }
12384  
12385  /*
12386 @@ -229,12 +186,12 @@ static void __rpc_remove_wait_queue_prio
12387  {
12388         struct rpc_task *t;
12389  
12390 -       if (!list_empty(&task->tk_links)) {
12391 -               t = list_entry(task->tk_links.next, struct rpc_task, tk_list);
12392 -               list_move(&t->tk_list, &task->tk_list);
12393 -               list_splice_init(&task->tk_links, &t->tk_links);
12394 +       if (!list_empty(&task->u.tk_wait.links)) {
12395 +               t = list_entry(task->u.tk_wait.links.next, struct rpc_task, u.tk_wait.list);
12396 +               list_move(&t->u.tk_wait.list, &task->u.tk_wait.list);
12397 +               list_splice_init(&task->u.tk_wait.links, &t->u.tk_wait.links);
12398         }
12399 -       list_del(&task->tk_list);
12400 +       list_del(&task->u.tk_wait.list);
12401  }
12402  
12403  /*
12404 @@ -243,31 +200,17 @@ static void __rpc_remove_wait_queue_prio
12405   */
12406  static void __rpc_remove_wait_queue(struct rpc_task *task)
12407  {
12408 -       struct rpc_wait_queue *queue = task->tk_rpcwait;
12409 -
12410 -       if (!queue)
12411 -               return;
12412 +       struct rpc_wait_queue *queue;
12413 +       queue = task->u.tk_wait.rpc_waitq;
12414  
12415         if (RPC_IS_PRIORITY(queue))
12416                 __rpc_remove_wait_queue_priority(task);
12417         else
12418 -               list_del(&task->tk_list);
12419 -       task->tk_rpcwait = NULL;
12420 -
12421 +               list_del(&task->u.tk_wait.list);
12422         dprintk("RPC: %4d removed from queue %p \"%s\"\n",
12423                                 task->tk_pid, queue, rpc_qname(queue));
12424  }
12425  
12426 -void
12427 -rpc_remove_wait_queue(struct rpc_task *task)
12428 -{
12429 -       if (!task->tk_rpcwait)
12430 -               return;
12431 -       spin_lock_bh(&rpc_queue_lock);
12432 -       __rpc_remove_wait_queue(task);
12433 -       spin_unlock_bh(&rpc_queue_lock);
12434 -}
12435 -
12436  static inline void rpc_set_waitqueue_priority(struct rpc_wait_queue *queue, int priority)
12437  {
12438         queue->priority = priority;
12439 @@ -290,6 +233,7 @@ static void __rpc_init_priority_wait_que
12440  {
12441         int i;
12442  
12443 +       spin_lock_init(&queue->lock);
12444         for (i = 0; i < ARRAY_SIZE(queue->tasks); i++)
12445                 INIT_LIST_HEAD(&queue->tasks[i]);
12446         queue->maxpriority = maxprio;
12447 @@ -316,34 +260,27 @@ EXPORT_SYMBOL(rpc_init_wait_queue);
12448   * Note: If the task is ASYNC, this must be called with 
12449   * the spinlock held to protect the wait queue operation.
12450   */
12451 -static inline void
12452 -rpc_make_runnable(struct rpc_task *task)
12453 +static void rpc_make_runnable(struct rpc_task *task)
12454  {
12455 -       if (task->tk_timeout_fn) {
12456 -               printk(KERN_ERR "RPC: task w/ running timer in rpc_make_runnable!!\n");
12457 +       if (rpc_test_and_set_running(task))
12458                 return;
12459 -       }
12460 -       rpc_set_running(task);
12461 +       BUG_ON(task->tk_timeout_fn);
12462         if (RPC_IS_ASYNC(task)) {
12463 -               if (RPC_IS_SLEEPING(task)) {
12464 -                       int status;
12465 -                       status = __rpc_add_wait_queue(&schedq, task);
12466 -                       if (status < 0) {
12467 -                               printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
12468 -                               task->tk_status = status;
12469 -                               return;
12470 -                       }
12471 -                       rpc_clear_sleeping(task);
12472 -                       wake_up(&rpciod_idle);
12473 +               int status;
12474 +
12475 +               INIT_WORK(&task->u.tk_work, rpc_async_schedule, (void *)task);
12476 +               status = queue_work(task->tk_workqueue, &task->u.tk_work);
12477 +               if (status < 0) {
12478 +                       printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
12479 +                       task->tk_status = status;
12480 +                       return;
12481                 }
12482 -       } else {
12483 -               rpc_clear_sleeping(task);
12484 -               wake_up(&task->tk_wait);
12485 -       }
12486 +       } else
12487 +               wake_up(&task->u.tk_wait.waitq);
12488  }
12489  
12490  /*
12491 - * Place a newly initialized task on the schedq.
12492 + * Place a newly initialized task on the workqueue.
12493   */
12494  static inline void
12495  rpc_schedule_run(struct rpc_task *task)
12496 @@ -352,33 +289,18 @@ rpc_schedule_run(struct rpc_task *task)
12497         if (RPC_IS_ACTIVATED(task))
12498                 return;
12499         task->tk_active = 1;
12500 -       rpc_set_sleeping(task);
12501         rpc_make_runnable(task);
12502  }
12503  
12504  /*
12505 - *     For other people who may need to wake the I/O daemon
12506 - *     but should (for now) know nothing about its innards
12507 - */
12508 -void rpciod_wake_up(void)
12509 -{
12510 -       if(rpciod_pid==0)
12511 -               printk(KERN_ERR "rpciod: wot no daemon?\n");
12512 -       wake_up(&rpciod_idle);
12513 -}
12514 -
12515 -/*
12516   * Prepare for sleeping on a wait queue.
12517   * By always appending tasks to the list we ensure FIFO behavior.
12518   * NB: An RPC task will only receive interrupt-driven events as long
12519   * as it's on a wait queue.
12520   */
12521 -static void
12522 -__rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
12523 +static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
12524                         rpc_action action, rpc_action timer)
12525  {
12526 -       int status;
12527 -
12528         dprintk("RPC: %4d sleep_on(queue \"%s\" time %ld)\n", task->tk_pid,
12529                                 rpc_qname(q), jiffies);
12530  
12531 @@ -388,49 +310,36 @@ __rpc_sleep_on(struct rpc_wait_queue *q,
12532         }
12533  
12534         /* Mark the task as being activated if so needed */
12535 -       if (!RPC_IS_ACTIVATED(task)) {
12536 +       if (!RPC_IS_ACTIVATED(task))
12537                 task->tk_active = 1;
12538 -               rpc_set_sleeping(task);
12539 -       }
12540  
12541 -       status = __rpc_add_wait_queue(q, task);
12542 -       if (status) {
12543 -               printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
12544 -               task->tk_status = status;
12545 -       } else {
12546 -               rpc_clear_running(task);
12547 -               if (task->tk_callback) {
12548 -                       dprintk(KERN_ERR "RPC: %4d overwrites an active callback\n", task->tk_pid);
12549 -                       BUG();
12550 -               }
12551 -               task->tk_callback = action;
12552 -               __rpc_add_timer(task, timer);
12553 -       }
12554 +       __rpc_add_wait_queue(q, task);
12555 +
12556 +       BUG_ON(task->tk_callback != NULL);
12557 +       task->tk_callback = action;
12558 +       __rpc_add_timer(task, timer);
12559  }
12560  
12561 -void
12562 -rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
12563 +void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
12564                                 rpc_action action, rpc_action timer)
12565  {
12566         /*
12567          * Protect the queue operations.
12568          */
12569 -       spin_lock_bh(&rpc_queue_lock);
12570 +       spin_lock_bh(&q->lock);
12571         __rpc_sleep_on(q, task, action, timer);
12572 -       spin_unlock_bh(&rpc_queue_lock);
12573 +       spin_unlock_bh(&q->lock);
12574  }
12575  
12576  /**
12577 - * __rpc_wake_up_task - wake up a single rpc_task
12578 + * __rpc_do_wake_up_task - wake up a single rpc_task
12579   * @task: task to be woken up
12580   *
12581 - * Caller must hold rpc_queue_lock
12582 + * Caller must hold queue->lock, and have cleared the task queued flag.
12583   */
12584 -static void
12585 -__rpc_wake_up_task(struct rpc_task *task)
12586 +static void __rpc_do_wake_up_task(struct rpc_task *task)
12587  {
12588 -       dprintk("RPC: %4d __rpc_wake_up_task (now %ld inh %d)\n",
12589 -                                       task->tk_pid, jiffies, rpc_inhibit);
12590 +       dprintk("RPC: %4d __rpc_wake_up_task (now %ld)\n", task->tk_pid, jiffies);
12591  
12592  #ifdef RPC_DEBUG
12593         if (task->tk_magic != 0xf00baa) {
12594 @@ -445,12 +354,9 @@ __rpc_wake_up_task(struct rpc_task *task
12595                 printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task);
12596                 return;
12597         }
12598 -       if (RPC_IS_RUNNING(task))
12599 -               return;
12600  
12601         __rpc_disable_timer(task);
12602 -       if (task->tk_rpcwait != &schedq)
12603 -               __rpc_remove_wait_queue(task);
12604 +       __rpc_remove_wait_queue(task);
12605  
12606         rpc_make_runnable(task);
12607  
12608 @@ -458,6 +364,15 @@ __rpc_wake_up_task(struct rpc_task *task
12609  }
12610  
12611  /*
12612 + * Wake up the specified task
12613 + */
12614 +static void __rpc_wake_up_task(struct rpc_task *task)
12615 +{
12616 +       if (rpc_test_and_clear_queued(task))
12617 +               __rpc_do_wake_up_task(task);
12618 +}
12619 +
12620 +/*
12621   * Default timeout handler if none specified by user
12622   */
12623  static void
12624 @@ -471,14 +386,15 @@ __rpc_default_timer(struct rpc_task *tas
12625  /*
12626   * Wake up the specified task
12627   */
12628 -void
12629 -rpc_wake_up_task(struct rpc_task *task)
12630 +void rpc_wake_up_task(struct rpc_task *task)
12631  {
12632 -       if (RPC_IS_RUNNING(task))
12633 -               return;
12634 -       spin_lock_bh(&rpc_queue_lock);
12635 -       __rpc_wake_up_task(task);
12636 -       spin_unlock_bh(&rpc_queue_lock);
12637 +       if (rpc_test_and_clear_queued(task)) {
12638 +               struct rpc_wait_queue *queue = task->u.tk_wait.rpc_waitq;
12639 +
12640 +               spin_lock_bh(&queue->lock);
12641 +               __rpc_do_wake_up_task(task);
12642 +               spin_unlock_bh(&queue->lock);
12643 +       }
12644  }
12645  
12646  /*
12647 @@ -494,11 +410,11 @@ static struct rpc_task * __rpc_wake_up_n
12648          */
12649         q = &queue->tasks[queue->priority];
12650         if (!list_empty(q)) {
12651 -               task = list_entry(q->next, struct rpc_task, tk_list);
12652 +               task = list_entry(q->next, struct rpc_task, u.tk_wait.list);
12653                 if (queue->cookie == task->tk_cookie) {
12654                         if (--queue->nr)
12655                                 goto out;
12656 -                       list_move_tail(&task->tk_list, q);
12657 +                       list_move_tail(&task->u.tk_wait.list, q);
12658                 }
12659                 /*
12660                  * Check if we need to switch queues.
12661 @@ -516,7 +432,7 @@ static struct rpc_task * __rpc_wake_up_n
12662                 else
12663                         q = q - 1;
12664                 if (!list_empty(q)) {
12665 -                       task = list_entry(q->next, struct rpc_task, tk_list);
12666 +                       task = list_entry(q->next, struct rpc_task, u.tk_wait.list);
12667                         goto new_queue;
12668                 }
12669         } while (q != &queue->tasks[queue->priority]);
12670 @@ -541,14 +457,14 @@ struct rpc_task * rpc_wake_up_next(struc
12671         struct rpc_task *task = NULL;
12672  
12673         dprintk("RPC:      wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue));
12674 -       spin_lock_bh(&rpc_queue_lock);
12675 +       spin_lock_bh(&queue->lock);
12676         if (RPC_IS_PRIORITY(queue))
12677                 task = __rpc_wake_up_next_priority(queue);
12678         else {
12679                 task_for_first(task, &queue->tasks[0])
12680                         __rpc_wake_up_task(task);
12681         }
12682 -       spin_unlock_bh(&rpc_queue_lock);
12683 +       spin_unlock_bh(&queue->lock);
12684  
12685         return task;
12686  }
12687 @@ -557,25 +473,25 @@ struct rpc_task * rpc_wake_up_next(struc
12688   * rpc_wake_up - wake up all rpc_tasks
12689   * @queue: rpc_wait_queue on which the tasks are sleeping
12690   *
12691 - * Grabs rpc_queue_lock
12692 + * Grabs queue->lock
12693   */
12694  void rpc_wake_up(struct rpc_wait_queue *queue)
12695  {
12696         struct rpc_task *task;
12697  
12698         struct list_head *head;
12699 -       spin_lock_bh(&rpc_queue_lock);
12700 +       spin_lock_bh(&queue->lock);
12701         head = &queue->tasks[queue->maxpriority];
12702         for (;;) {
12703                 while (!list_empty(head)) {
12704 -                       task = list_entry(head->next, struct rpc_task, tk_list);
12705 +                       task = list_entry(head->next, struct rpc_task, u.tk_wait.list);
12706                         __rpc_wake_up_task(task);
12707                 }
12708                 if (head == &queue->tasks[0])
12709                         break;
12710                 head--;
12711         }
12712 -       spin_unlock_bh(&rpc_queue_lock);
12713 +       spin_unlock_bh(&queue->lock);
12714  }
12715  
12716  /**
12717 @@ -583,18 +499,18 @@ void rpc_wake_up(struct rpc_wait_queue *
12718   * @queue: rpc_wait_queue on which the tasks are sleeping
12719   * @status: status value to set
12720   *
12721 - * Grabs rpc_queue_lock
12722 + * Grabs queue->lock
12723   */
12724  void rpc_wake_up_status(struct rpc_wait_queue *queue, int status)
12725  {
12726         struct list_head *head;
12727         struct rpc_task *task;
12728  
12729 -       spin_lock_bh(&rpc_queue_lock);
12730 +       spin_lock_bh(&queue->lock);
12731         head = &queue->tasks[queue->maxpriority];
12732         for (;;) {
12733                 while (!list_empty(head)) {
12734 -                       task = list_entry(head->next, struct rpc_task, tk_list);
12735 +                       task = list_entry(head->next, struct rpc_task, u.tk_wait.list);
12736                         task->tk_status = status;
12737                         __rpc_wake_up_task(task);
12738                 }
12739 @@ -602,7 +518,7 @@ void rpc_wake_up_status(struct rpc_wait_
12740                         break;
12741                 head--;
12742         }
12743 -       spin_unlock_bh(&rpc_queue_lock);
12744 +       spin_unlock_bh(&queue->lock);
12745  }
12746  
12747  /*
12748 @@ -626,18 +542,14 @@ __rpc_atrun(struct rpc_task *task)
12749  /*
12750   * This is the RPC `scheduler' (or rather, the finite state machine).
12751   */
12752 -static int
12753 -__rpc_execute(struct rpc_task *task)
12754 +static int __rpc_execute(struct rpc_task *task)
12755  {
12756         int             status = 0;
12757  
12758         dprintk("RPC: %4d rpc_execute flgs %x\n",
12759                                 task->tk_pid, task->tk_flags);
12760  
12761 -       if (!RPC_IS_RUNNING(task)) {
12762 -               printk(KERN_WARNING "RPC: rpc_execute called for sleeping task!!\n");
12763 -               return 0;
12764 -       }
12765 +       BUG_ON(RPC_IS_QUEUED(task));
12766  
12767   restarted:
12768         while (1) {
12769 @@ -657,7 +569,9 @@ __rpc_execute(struct rpc_task *task)
12770                          */
12771                         save_callback=task->tk_callback;
12772                         task->tk_callback=NULL;
12773 +                       lock_kernel();
12774                         save_callback(task);
12775 +                       unlock_kernel();
12776                 }
12777  
12778                 /*
12779 @@ -665,43 +579,41 @@ __rpc_execute(struct rpc_task *task)
12780                  * tk_action may be NULL when the task has been killed
12781                  * by someone else.
12782                  */
12783 -               if (RPC_IS_RUNNING(task)) {
12784 +               if (!RPC_IS_QUEUED(task)) {
12785                         /*
12786                          * Garbage collection of pending timers...
12787                          */
12788                         rpc_delete_timer(task);
12789                         if (!task->tk_action)
12790                                 break;
12791 +                       lock_kernel();
12792                         task->tk_action(task);
12793 -                       /* micro-optimization to avoid spinlock */
12794 -                       if (RPC_IS_RUNNING(task))
12795 -                               continue;
12796 +                       unlock_kernel();
12797                 }
12798  
12799                 /*
12800 -                * Check whether task is sleeping.
12801 +                * Lockless check for whether task is sleeping or not.
12802                  */
12803 -               spin_lock_bh(&rpc_queue_lock);
12804 -               if (!RPC_IS_RUNNING(task)) {
12805 -                       rpc_set_sleeping(task);
12806 -                       if (RPC_IS_ASYNC(task)) {
12807 -                               spin_unlock_bh(&rpc_queue_lock);
12808 +               if (!RPC_IS_QUEUED(task))
12809 +                       continue;
12810 +               if (RPC_IS_ASYNC(task)) {
12811 +                       rpc_clear_running(task);
12812 +                       /* Careful! we may have raced... */
12813 +                       if (RPC_IS_QUEUED(task))
12814                                 return 0;
12815 -                       }
12816 +                       if (rpc_test_and_set_running(task))
12817 +                               return 0;
12818 +                       continue;
12819                 }
12820 -               spin_unlock_bh(&rpc_queue_lock);
12821  
12822 -               if (!RPC_IS_SLEEPING(task))
12823 -                       continue;
12824 +               init_waitqueue_head(&task->u.tk_wait.waitq);
12825 +               rpc_clear_running(task);
12826                 /* sync task: sleep here */
12827                 dprintk("RPC: %4d sync task going to sleep\n", task->tk_pid);
12828 -               if (current->pid == rpciod_pid)
12829 -                       printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
12830 -
12831                 if (!task->tk_client->cl_intr) {
12832 -                       __wait_event(task->tk_wait, !RPC_IS_SLEEPING(task));
12833 +                       __wait_event(task->u.tk_wait.waitq, RPC_IS_RUNNING(task));
12834                 } else {
12835 -                       __wait_event_interruptible(task->tk_wait, !RPC_IS_SLEEPING(task), status);
12836 +                       __wait_event_interruptible(task->u.tk_wait.waitq, RPC_IS_RUNNING(task), status);
12837                         /*
12838                          * When a sync task receives a signal, it exits with
12839                          * -ERESTARTSYS. In order to catch any callbacks that
12840 @@ -719,7 +631,9 @@ __rpc_execute(struct rpc_task *task)
12841         }
12842  
12843         if (task->tk_exit) {
12844 +               lock_kernel();
12845                 task->tk_exit(task);
12846 +               unlock_kernel();
12847                 /* If tk_action is non-null, the user wants us to restart */
12848                 if (task->tk_action) {
12849                         if (!RPC_ASSASSINATED(task)) {
12850 @@ -738,7 +652,6 @@ __rpc_execute(struct rpc_task *task)
12851  
12852         /* Release all resources associated with the task */
12853         rpc_release_task(task);
12854 -
12855         return status;
12856  }
12857  
12858 @@ -754,57 +667,16 @@ __rpc_execute(struct rpc_task *task)
12859  int
12860  rpc_execute(struct rpc_task *task)
12861  {
12862 -       int status = -EIO;
12863 -       if (rpc_inhibit) {
12864 -               printk(KERN_INFO "RPC: execution inhibited!\n");
12865 -               goto out_release;
12866 -       }
12867 -
12868 -       status = -EWOULDBLOCK;
12869 -       if (task->tk_active) {
12870 -               printk(KERN_ERR "RPC: active task was run twice!\n");
12871 -               goto out_err;
12872 -       }
12873 +       BUG_ON(task->tk_active);
12874  
12875         task->tk_active = 1;
12876         rpc_set_running(task);
12877         return __rpc_execute(task);
12878 - out_release:
12879 -       rpc_release_task(task);
12880 - out_err:
12881 -       return status;
12882  }
12883  
12884 -/*
12885 - * This is our own little scheduler for async RPC tasks.
12886 - */
12887 -static void
12888 -__rpc_schedule(void)
12889 +static void rpc_async_schedule(void *arg)
12890  {
12891 -       struct rpc_task *task;
12892 -       int             count = 0;
12893 -
12894 -       dprintk("RPC:      rpc_schedule enter\n");
12895 -       while (1) {
12896 -
12897 -               task_for_first(task, &schedq.tasks[0]) {
12898 -                       __rpc_remove_wait_queue(task);
12899 -                       spin_unlock_bh(&rpc_queue_lock);
12900 -
12901 -                       __rpc_execute(task);
12902 -                       spin_lock_bh(&rpc_queue_lock);
12903 -               } else {
12904 -                       break;
12905 -               }
12906 -
12907 -               if (++count >= 200 || need_resched()) {
12908 -                       count = 0;
12909 -                       spin_unlock_bh(&rpc_queue_lock);
12910 -                       schedule();
12911 -                       spin_lock_bh(&rpc_queue_lock);
12912 -               }
12913 -       }
12914 -       dprintk("RPC:      rpc_schedule leave\n");
12915 +       __rpc_execute((struct rpc_task *)arg);
12916  }
12917  
12918  /*
12919 @@ -862,7 +734,6 @@ void rpc_init_task(struct rpc_task *task
12920         task->tk_client = clnt;
12921         task->tk_flags  = flags;
12922         task->tk_exit   = callback;
12923 -       init_waitqueue_head(&task->tk_wait);
12924         if (current->uid != current->fsuid || current->gid != current->fsgid)
12925                 task->tk_flags |= RPC_TASK_SETUID;
12926  
12927 @@ -873,7 +744,9 @@ void rpc_init_task(struct rpc_task *task
12928  
12929         task->tk_priority = RPC_PRIORITY_NORMAL;
12930         task->tk_cookie = (unsigned long)current;
12931 -       INIT_LIST_HEAD(&task->tk_links);
12932 +
12933 +       /* Initialize workqueue for async tasks */
12934 +       task->tk_workqueue = rpciod_workqueue;
12935  
12936         /* Add to global list of all tasks */
12937         spin_lock(&rpc_sched_lock);
12938 @@ -942,8 +815,7 @@ cleanup:
12939         goto out;
12940  }
12941  
12942 -void
12943 -rpc_release_task(struct rpc_task *task)
12944 +void rpc_release_task(struct rpc_task *task)
12945  {
12946         dprintk("RPC: %4d release task\n", task->tk_pid);
12947  
12948 @@ -961,19 +833,9 @@ rpc_release_task(struct rpc_task *task)
12949         list_del(&task->tk_task);
12950         spin_unlock(&rpc_sched_lock);
12951  
12952 -       /* Protect the execution below. */
12953 -       spin_lock_bh(&rpc_queue_lock);
12954 -
12955 -       /* Disable timer to prevent zombie wakeup */
12956 -       __rpc_disable_timer(task);
12957 -
12958 -       /* Remove from any wait queue we're still on */
12959 -       __rpc_remove_wait_queue(task);
12960 -
12961 +       BUG_ON (rpc_test_and_clear_queued(task));
12962         task->tk_active = 0;
12963  
12964 -       spin_unlock_bh(&rpc_queue_lock);
12965 -
12966         /* Synchronously delete any running timer */
12967         rpc_delete_timer(task);
12968  
12969 @@ -1003,10 +865,9 @@ rpc_release_task(struct rpc_task *task)
12970   * queue 'childq'. If so returns a pointer to the parent.
12971   * Upon failure returns NULL.
12972   *
12973 - * Caller must hold rpc_queue_lock
12974 + * Caller must hold childq.lock
12975   */
12976 -static inline struct rpc_task *
12977 -rpc_find_parent(struct rpc_task *child)
12978 +static inline struct rpc_task *rpc_find_parent(struct rpc_task *child)
12979  {
12980         struct rpc_task *task, *parent;
12981         struct list_head *le;
12982 @@ -1019,17 +880,16 @@ rpc_find_parent(struct rpc_task *child)
12983         return NULL;
12984  }
12985  
12986 -static void
12987 -rpc_child_exit(struct rpc_task *child)
12988 +static void rpc_child_exit(struct rpc_task *child)
12989  {
12990         struct rpc_task *parent;
12991  
12992 -       spin_lock_bh(&rpc_queue_lock);
12993 +       spin_lock_bh(&childq.lock);
12994         if ((parent = rpc_find_parent(child)) != NULL) {
12995                 parent->tk_status = child->tk_status;
12996                 __rpc_wake_up_task(parent);
12997         }
12998 -       spin_unlock_bh(&rpc_queue_lock);
12999 +       spin_unlock_bh(&childq.lock);
13000  }
13001  
13002  /*
13003 @@ -1052,22 +912,20 @@ fail:
13004         return NULL;
13005  }
13006  
13007 -void
13008 -rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func)
13009 +void rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func)
13010  {
13011 -       spin_lock_bh(&rpc_queue_lock);
13012 +       spin_lock_bh(&childq.lock);
13013         /* N.B. Is it possible for the child to have already finished? */
13014         __rpc_sleep_on(&childq, task, func, NULL);
13015         rpc_schedule_run(child);
13016 -       spin_unlock_bh(&rpc_queue_lock);
13017 +       spin_unlock_bh(&childq.lock);
13018  }
13019  
13020  /*
13021   * Kill all tasks for the given client.
13022   * XXX: kill their descendants as well?
13023   */
13024 -void
13025 -rpc_killall_tasks(struct rpc_clnt *clnt)
13026 +void rpc_killall_tasks(struct rpc_clnt *clnt)
13027  {
13028         struct rpc_task *rovr;
13029         struct list_head *le;
13030 @@ -1089,93 +947,14 @@ rpc_killall_tasks(struct rpc_clnt *clnt)
13031  
13032  static DECLARE_MUTEX_LOCKED(rpciod_running);
13033  
13034 -static inline int
13035 -rpciod_task_pending(void)
13036 -{
13037 -       return !list_empty(&schedq.tasks[0]);
13038 -}
13039 -
13040 -
13041 -/*
13042 - * This is the rpciod kernel thread
13043 - */
13044 -static int
13045 -rpciod(void *ptr)
13046 -{
13047 -       int             rounds = 0;
13048 -
13049 -       lock_kernel();
13050 -       /*
13051 -        * Let our maker know we're running ...
13052 -        */
13053 -       rpciod_pid = current->pid;
13054 -       up(&rpciod_running);
13055 -
13056 -       daemonize("rpciod");
13057 -       allow_signal(SIGKILL);
13058 -
13059 -       dprintk("RPC: rpciod starting (pid %d)\n", rpciod_pid);
13060 -       spin_lock_bh(&rpc_queue_lock);
13061 -       while (rpciod_users) {
13062 -               DEFINE_WAIT(wait);
13063 -               if (signalled()) {
13064 -                       spin_unlock_bh(&rpc_queue_lock);
13065 -                       rpciod_killall();
13066 -                       flush_signals(current);
13067 -                       spin_lock_bh(&rpc_queue_lock);
13068 -               }
13069 -               __rpc_schedule();
13070 -               if (current->flags & PF_FREEZE) {
13071 -                       spin_unlock_bh(&rpc_queue_lock);
13072 -                       refrigerator(PF_FREEZE);
13073 -                       spin_lock_bh(&rpc_queue_lock);
13074 -               }
13075 -
13076 -               if (++rounds >= 64) {   /* safeguard */
13077 -                       spin_unlock_bh(&rpc_queue_lock);
13078 -                       schedule();
13079 -                       rounds = 0;
13080 -                       spin_lock_bh(&rpc_queue_lock);
13081 -               }
13082 -
13083 -               dprintk("RPC: rpciod back to sleep\n");
13084 -               prepare_to_wait(&rpciod_idle, &wait, TASK_INTERRUPTIBLE);
13085 -               if (!rpciod_task_pending() && !signalled()) {
13086 -                       spin_unlock_bh(&rpc_queue_lock);
13087 -                       schedule();
13088 -                       rounds = 0;
13089 -                       spin_lock_bh(&rpc_queue_lock);
13090 -               }
13091 -               finish_wait(&rpciod_idle, &wait);
13092 -               dprintk("RPC: switch to rpciod\n");
13093 -       }
13094 -       spin_unlock_bh(&rpc_queue_lock);
13095 -
13096 -       dprintk("RPC: rpciod shutdown commences\n");
13097 -       if (!list_empty(&all_tasks)) {
13098 -               printk(KERN_ERR "rpciod: active tasks at shutdown?!\n");
13099 -               rpciod_killall();
13100 -       }
13101 -
13102 -       dprintk("RPC: rpciod exiting\n");
13103 -       unlock_kernel();
13104 -
13105 -       rpciod_pid = 0;
13106 -       complete_and_exit(&rpciod_killer, 0);
13107 -       return 0;
13108 -}
13109 -
13110 -static void
13111 -rpciod_killall(void)
13112 +static void rpciod_killall(void)
13113  {
13114         unsigned long flags;
13115  
13116         while (!list_empty(&all_tasks)) {
13117                 clear_thread_flag(TIF_SIGPENDING);
13118                 rpc_killall_tasks(NULL);
13119 -               spin_lock_bh(&rpc_queue_lock);
13120 -               __rpc_schedule();
13121 -               spin_unlock_bh(&rpc_queue_lock);
13122 +               flush_workqueue(rpciod_workqueue);
13123                 if (!list_empty(&all_tasks)) {
13124                         dprintk("rpciod_killall: waiting for tasks to exit\n");
13125                         yield();
13126 @@ -1193,28 +972,30 @@ rpciod_killall(void)
13127  int
13128  rpciod_up(void)
13129  {
13130 +       struct workqueue_struct *wq;
13131         int error = 0;
13132  
13133         down(&rpciod_sema);
13134 -       dprintk("rpciod_up: pid %d, users %d\n", rpciod_pid, rpciod_users);
13135 +       dprintk("rpciod_up: users %d\n", rpciod_users);
13136         rpciod_users++;
13137 -       if (rpciod_pid)
13138 +       if (rpciod_workqueue)
13139                 goto out;
13140         /*
13141          * If there's no pid, we should be the first user.
13142          */
13143         if (rpciod_users > 1)
13144 -               printk(KERN_WARNING "rpciod_up: no pid, %d users??\n", rpciod_users);
13145 +               printk(KERN_WARNING "rpciod_up: no workqueue, %d users??\n", rpciod_users);
13146         /*
13147          * Create the rpciod thread and wait for it to start.
13148          */
13149 -       error = kernel_thread(rpciod, NULL, 0);
13150 -       if (error < 0) {
13151 -               printk(KERN_WARNING "rpciod_up: create thread failed, error=%d\n", error);
13152 +       error = -ENOMEM;
13153 +       wq = create_workqueue("rpciod");
13154 +       if (wq == NULL) {
13155 +               printk(KERN_WARNING "rpciod_up: create workqueue failed, error=%d\n", error);
13156                 rpciod_users--;
13157                 goto out;
13158         }
13159 -       down(&rpciod_running);
13160 +       rpciod_workqueue = wq;
13161         error = 0;
13162  out:
13163         up(&rpciod_sema);
13164 @@ -1225,20 +1006,21 @@ void
13165  rpciod_down(void)
13166  {
13167         down(&rpciod_sema);
13168 -       dprintk("rpciod_down pid %d sema %d\n", rpciod_pid, rpciod_users);
13169 +       dprintk("rpciod_down sema %d\n", rpciod_users);
13170         if (rpciod_users) {
13171                 if (--rpciod_users)
13172                         goto out;
13173         } else
13174 -               printk(KERN_WARNING "rpciod_down: pid=%d, no users??\n", rpciod_pid);
13175 +               printk(KERN_WARNING "rpciod_down: no users??\n");
13176  
13177 -       if (!rpciod_pid) {
13178 +       if (!rpciod_workqueue) {
13179                 dprintk("rpciod_down: Nothing to do!\n");
13180                 goto out;
13181         }
13182 +       rpciod_killall();
13183  
13184 -       kill_proc(rpciod_pid, SIGKILL, 1);
13185 -       wait_for_completion(&rpciod_killer);
13186 +       destroy_workqueue(rpciod_workqueue);
13187 +       rpciod_workqueue = NULL;
13188   out:
13189         up(&rpciod_sema);
13190  }
13191 @@ -1256,7 +1038,12 @@ void rpc_show_tasks(void)
13192         }
13193         printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
13194                 "-rpcwait -action- --exit--\n");
13195 -       alltask_for_each(t, le, &all_tasks)
13196 +       alltask_for_each(t, le, &all_tasks) {
13197 +               const char *rpc_waitq = "none";
13198 +
13199 +               if (RPC_IS_QUEUED(t))
13200 +                       rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq);
13201 +
13202                 printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n",
13203                         t->tk_pid,
13204                         (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1),
13205 @@ -1264,8 +1051,9 @@ void rpc_show_tasks(void)
13206                         t->tk_client,
13207                         (t->tk_client ? t->tk_client->cl_prog : 0),
13208                         t->tk_rqstp, t->tk_timeout,
13209 -                       rpc_qname(t->tk_rpcwait),
13210 +                       rpc_waitq,
13211                         t->tk_action, t->tk_exit);
13212 +       }
13213         spin_unlock(&rpc_sched_lock);
13214  }
13215  #endif
13216 --- linux-2.6.7/net/sunrpc/svcsock.c.lsec       2004-06-15 23:18:57.000000000 -0600
13217 +++ linux-2.6.7/net/sunrpc/svcsock.c    2005-03-23 14:28:24.029396672 -0700
13218 @@ -414,7 +414,6 @@ svc_sendto(struct svc_rqst *rqstp, struc
13219         }
13220         /* send tail */
13221         if (xdr->tail[0].iov_len) {
13222 -               /* The tail *will* be in respages[0]; */
13223                 result = sock->ops->sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage], 
13224                                              ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1),
13225                                              xdr->tail[0].iov_len, 0);
13226 --- linux-2.6.7/net/sunrpc/clnt.c.lsec  2004-06-15 23:19:13.000000000 -0600
13227 +++ linux-2.6.7/net/sunrpc/clnt.c       2005-03-23 14:28:23.595462640 -0700
13228 @@ -351,7 +351,9 @@ int rpc_call_sync(struct rpc_clnt *clnt,
13229         rpc_clnt_sigmask(clnt, &oldset);                
13230  
13231         /* Create/initialize a new RPC task */
13232 -       rpc_init_task(task, clnt, NULL, flags);
13233 +       task = rpc_new_task(clnt, NULL, flags);
13234 +       if (task == NULL)
13235 +               return -ENOMEM;
13236         rpc_call_setup(task, msg, 0);
13237  
13238         /* Set up the call info struct and execute the task */
13239 @@ -620,8 +622,14 @@ call_encode(struct rpc_task *task)
13240                 rpc_exit(task, -EIO);
13241                 return;
13242         }
13243 -       if (encode && (status = rpcauth_wrap_req(task, encode, req, p,
13244 -                                                task->tk_msg.rpc_argp)) < 0) {
13245 +       if (encode == NULL)
13246 +               return;
13247 +
13248 +       status = rpcauth_wrap_req(task, encode, req, p, task->tk_msg.rpc_argp);
13249 +       if (status == -EAGAIN) {
13250 +               printk("XXXJBF: out of memeory?  Should retry here!!!\n");
13251 +       }
13252 +       if (status < 0) {
13253                 printk(KERN_WARNING "%s: can't encode arguments: %d\n",
13254                                 clnt->cl_protname, -status);
13255                 rpc_exit(task, status);
13256 --- linux-2.6.7/net/sunrpc/sunrpc_syms.c.lsec   2004-06-15 23:19:52.000000000 -0600
13257 +++ linux-2.6.7/net/sunrpc/sunrpc_syms.c        2005-03-23 14:32:35.589153776 -0700
13258 @@ -58,6 +58,8 @@ EXPORT_SYMBOL(rpc_unlink);
13259  EXPORT_SYMBOL(rpc_wake_up);
13260  EXPORT_SYMBOL(rpc_queue_upcall);
13261  EXPORT_SYMBOL(rpc_mkpipe);
13262 +EXPORT_SYMBOL(rpc_mkdir);
13263 +EXPORT_SYMBOL(rpc_rmdir);
13264  
13265  /* Client transport */
13266  EXPORT_SYMBOL(xprt_create_proto);
13267 @@ -89,6 +91,7 @@ EXPORT_SYMBOL(svc_makesock);
13268  EXPORT_SYMBOL(svc_reserve);
13269  EXPORT_SYMBOL(svc_auth_register);
13270  EXPORT_SYMBOL(auth_domain_lookup);
13271 +EXPORT_SYMBOL(svc_authenticate);
13272  
13273  /* RPC statistics */
13274  #ifdef CONFIG_PROC_FS
13275 --- linux-2.6.7/net/sunrpc/pmap_clnt.c.lsec     2004-06-15 23:19:23.000000000 -0600
13276 +++ linux-2.6.7/net/sunrpc/pmap_clnt.c  2005-03-23 14:28:24.134380712 -0700
13277 @@ -183,8 +183,10 @@ rpc_register(u32 prog, u32 vers, int pro
13278         map.pm_prot = prot;
13279         map.pm_port = port;
13280  
13281 +       rpciod_up();
13282         error = rpc_call(pmap_clnt, port? PMAP_SET : PMAP_UNSET,
13283                                         &map, okay, 0);
13284 +       rpciod_down();
13285  
13286         if (error < 0) {
13287                 printk(KERN_WARNING
13288 --- linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_unseal.c.lsec      2004-06-15 23:19:44.000000000 -0600
13289 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_unseal.c   2005-03-23 14:28:23.761437408 -0700
13290 @@ -68,20 +68,13 @@
13291  #endif
13292  
13293  
13294 -/* message_buffer is an input if toktype is MIC and an output if it is WRAP:
13295 - * If toktype is MIC: read_token is a mic token, and message_buffer is the
13296 - *   data that the mic was supposedly taken over.
13297 - * If toktype is WRAP: read_token is a wrap token, and message_buffer is used
13298 - *   to return the decrypted data.
13299 - */
13300 +/* read_token is a mic token, and message_buffer is the data that the mic was
13301 + * supposedly taken over. */
13302  
13303 -/* XXX will need to change prototype and/or just split into a separate function
13304 - * when we add privacy (because read_token will be in pages too). */
13305  u32
13306  krb5_read_token(struct krb5_ctx *ctx,
13307                 struct xdr_netobj *read_token,
13308 -               struct xdr_buf *message_buffer,
13309 -               int *qop_state, int toktype)
13310 +               struct xdr_buf *message_buffer, int *qop_state)
13311  {
13312         int                     signalg;
13313         int                     sealalg;
13314 @@ -96,20 +89,16 @@ krb5_read_token(struct krb5_ctx *ctx,
13315  
13316         dprintk("RPC:      krb5_read_token\n");
13317  
13318 -       if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr, toktype,
13319 +       if (g_verify_token_header(&ctx->mech_used, &bodysize, &ptr,
13320                                         read_token->len))
13321                 goto out;
13322  
13323 -       if ((*ptr++ != ((toktype>>8)&0xff)) || (*ptr++ != (toktype&0xff)))
13324 +       if ((*ptr++ != ((KG_TOK_MIC_MSG>>8)&0xff)) ||
13325 +           (*ptr++ != ( KG_TOK_MIC_MSG    &0xff))   )
13326                 goto out;
13327  
13328         /* XXX sanity-check bodysize?? */
13329  
13330 -       if (toktype == KG_TOK_WRAP_MSG) {
13331 -               /* XXX gone */
13332 -               goto out;
13333 -       }
13334 -
13335         /* get the sign and seal algorithms */
13336  
13337         signalg = ptr[0] + (ptr[1] << 8);
13338 @@ -120,14 +109,7 @@ krb5_read_token(struct krb5_ctx *ctx,
13339         if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
13340                 goto out;
13341  
13342 -       if (((toktype != KG_TOK_WRAP_MSG) && (sealalg != 0xffff)) ||
13343 -           ((toktype == KG_TOK_WRAP_MSG) && (sealalg == 0xffff)))
13344 -               goto out;
13345 -
13346 -       /* in the current spec, there is only one valid seal algorithm per
13347 -          key type, so a simple comparison is ok */
13348 -
13349 -       if ((toktype == KG_TOK_WRAP_MSG) && !(sealalg == ctx->sealalg))
13350 +       if (sealalg != 0xffff)
13351                 goto out;
13352  
13353         /* there are several mappings of seal algorithms to sign algorithms,
13354 @@ -154,7 +136,7 @@ krb5_read_token(struct krb5_ctx *ctx,
13355         switch (signalg) {
13356         case SGN_ALG_DES_MAC_MD5:
13357                 ret = make_checksum(checksum_type, ptr - 2, 8,
13358 -                                        message_buffer, &md5cksum);
13359 +                                        message_buffer, 0, &md5cksum);
13360                 if (ret)
13361                         goto out;
13362  
13363 --- linux-2.6.7/net/sunrpc/auth_gss/auth_gss.c.lsec     2004-06-15 23:19:22.000000000 -0600
13364 +++ linux-2.6.7/net/sunrpc/auth_gss/auth_gss.c  2005-03-23 14:28:24.185372960 -0700
13365 @@ -45,6 +45,7 @@
13366  #include <linux/socket.h>
13367  #include <linux/in.h>
13368  #include <linux/sched.h>
13369 +#include <linux/pagemap.h>
13370  #include <linux/sunrpc/clnt.h>
13371  #include <linux/sunrpc/auth.h>
13372  #include <linux/sunrpc/auth_gss.h>
13373 @@ -397,7 +398,7 @@ retry:
13374                 spin_unlock(&gss_auth->lock);
13375         }
13376         gss_release_msg(gss_msg);
13377 -       dprintk("RPC: %4u gss_upcall for uid %u result %d", task->tk_pid,
13378 +       dprintk("RPC: %4u gss_upcall for uid %u result %d\n", task->tk_pid,
13379                         uid, res);
13380         return res;
13381  out_sleep:
13382 @@ -740,6 +741,8 @@ gss_marshal(struct rpc_task *task, u32 *
13383         maj_stat = gss_get_mic(ctx->gc_gss_ctx,
13384                                GSS_C_QOP_DEFAULT, 
13385                                &verf_buf, &mic);
13386 +       if (maj_stat == GSS_S_CONTEXT_EXPIRED)
13387 +               cred->cr_flags |= RPCAUTH_CRED_DEAD;
13388         if(maj_stat != 0){
13389                 printk("gss_marshal: gss_get_mic FAILED (%d)\n", maj_stat);
13390                 goto out_put_ctx;
13391 @@ -779,6 +782,7 @@ gss_validate(struct rpc_task *task, u32 
13392         struct xdr_netobj mic;
13393         u32             flav,len;
13394         u32             service;
13395 +       u32             maj_stat;
13396  
13397         dprintk("RPC: %4u gss_validate\n", task->tk_pid);
13398  
13399 @@ -794,8 +798,11 @@ gss_validate(struct rpc_task *task, u32 
13400         mic.data = (u8 *)p;
13401         mic.len = len;
13402  
13403 -       if (gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic, &qop_state))
13404 -               goto out_bad;
13405 +       maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic, &qop_state);
13406 +       if (maj_stat == GSS_S_CONTEXT_EXPIRED)
13407 +               cred->cr_flags |= RPCAUTH_CRED_DEAD;
13408 +       if (maj_stat)
13409 +               goto out_bad;
13410         service = gss_pseudoflavor_to_service(ctx->gc_gss_ctx->mech_type,
13411                                         gss_cred->gc_flavor);
13412         switch (service) {
13413 @@ -807,6 +814,11 @@ gss_validate(struct rpc_task *task, u32 
13414                /* verifier data, flavor, length, length, sequence number: */
13415                task->tk_auth->au_rslack = XDR_QUADLEN(len) + 4;
13416                break;
13417 +       case RPC_GSS_SVC_PRIVACY:
13418 +              /* XXXJBF: Ugh. Going for a wild overestimate.
13419 +               * Need some info from krb5 layer? */
13420 +              task->tk_auth->au_rslack = XDR_QUADLEN(len) + 32;
13421 +              break;
13422         default:
13423                goto out_bad;
13424         }
13425 @@ -821,11 +833,11 @@ out_bad:
13426  }
13427  
13428  static inline int
13429 -gss_wrap_req_integ(struct gss_cl_ctx *ctx,
13430 -                       kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
13431 +gss_wrap_req_integ(struct rpc_cred *cred, kxdrproc_t encode,
13432 +                       struct rpc_rqst *rqstp, u32 *p, void *obj)
13433  {
13434 -       struct rpc_rqst *req = (struct rpc_rqst *)rqstp;
13435 -       struct xdr_buf  *snd_buf = &req->rq_snd_buf;
13436 +       struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
13437 +       struct xdr_buf  *snd_buf = &rqstp->rq_snd_buf;
13438         struct xdr_buf  integ_buf;
13439         u32             *integ_len = NULL;
13440         struct xdr_netobj mic;
13441 @@ -836,7 +848,7 @@ gss_wrap_req_integ(struct gss_cl_ctx *ct
13442  
13443         integ_len = p++;
13444         offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
13445 -       *p++ = htonl(req->rq_seqno);
13446 +       *p++ = htonl(rqstp->rq_seqno);
13447  
13448         status = encode(rqstp, p, obj);
13449         if (status)
13450 @@ -848,7 +860,7 @@ gss_wrap_req_integ(struct gss_cl_ctx *ct
13451         *integ_len = htonl(integ_buf.len);
13452  
13453         /* guess whether we're in the head or the tail: */
13454 -       if (snd_buf->page_len || snd_buf->tail[0].iov_len) 
13455 +       if (snd_buf->page_len || snd_buf->tail[0].iov_len)
13456                 iov = snd_buf->tail;
13457         else
13458                 iov = snd_buf->head;
13459 @@ -857,6 +869,8 @@ gss_wrap_req_integ(struct gss_cl_ctx *ct
13460  
13461         maj_stat = gss_get_mic(ctx->gc_gss_ctx,
13462                         GSS_C_QOP_DEFAULT, &integ_buf, &mic);
13463 +       if (maj_stat == GSS_S_CONTEXT_EXPIRED)
13464 +               cred->cr_flags |= RPCAUTH_CRED_DEAD;
13465         status = -EIO; /* XXX? */
13466         if (maj_stat)
13467                 return status;
13468 @@ -868,6 +882,113 @@ gss_wrap_req_integ(struct gss_cl_ctx *ct
13469         return 0;
13470  }
13471  
13472 +static void
13473 +priv_release_snd_buf(struct rpc_rqst *rqstp)
13474 +{
13475 +       int i;
13476 +
13477 +       for (i=0; i < rqstp->rq_enc_pages_num; i++)
13478 +               __free_page(rqstp->rq_enc_pages[i]);
13479 +       kfree(rqstp->rq_enc_pages);
13480 +}
13481 +
13482 +static int
13483 +alloc_enc_pages(struct rpc_rqst *rqstp)
13484 +{
13485 +       struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
13486 +       int first, last, i;
13487 +
13488 +       if (snd_buf->page_len == 0) {
13489 +               rqstp->rq_enc_pages_num = 0;
13490 +               return 0;
13491 +       }
13492 +
13493 +       first = snd_buf->page_base >> PAGE_CACHE_SHIFT;
13494 +       last = (snd_buf->page_base + snd_buf->page_len - 1) >> PAGE_CACHE_SHIFT;
13495 +       rqstp->rq_enc_pages_num = last - first + 1 + 1;
13496 +       rqstp->rq_enc_pages
13497 +               = kmalloc(rqstp->rq_enc_pages_num * sizeof(struct page *),
13498 +                               GFP_NOFS);
13499 +       if (!rqstp->rq_enc_pages)
13500 +               goto out;
13501 +       for (i=0; i < rqstp->rq_enc_pages_num; i++) {
13502 +               rqstp->rq_enc_pages[i] = alloc_page(GFP_NOFS);
13503 +               if (rqstp->rq_enc_pages[i] == NULL)
13504 +                       goto out_free;
13505 +       }
13506 +       rqstp->rq_release_snd_buf = priv_release_snd_buf;
13507 +       return 0;
13508 +out_free:
13509 +       for (i--; i >= 0; i--) {
13510 +               __free_page(rqstp->rq_enc_pages[i]);
13511 +       }
13512 +out:
13513 +       return -EAGAIN;
13514 +}
13515 +
13516 +static inline int
13517 +gss_wrap_req_priv(struct rpc_cred *cred, kxdrproc_t encode,
13518 +               struct rpc_rqst *rqstp, u32 *p, void *obj)
13519 +{
13520 +       struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
13521 +       struct xdr_buf  *snd_buf = &rqstp->rq_snd_buf;
13522 +       u32             offset;
13523 +       u32             maj_stat;
13524 +       int             status;
13525 +       u32             *opaque_len;
13526 +       struct page     **inpages;
13527 +       int             first;
13528 +       int             pad;
13529 +       struct iovec    *iov;
13530 +       char            *tmp;
13531 +
13532 +       opaque_len = p++;
13533 +       offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
13534 +       *p++ = htonl(rqstp->rq_seqno);
13535 +
13536 +       status = encode(rqstp, p, obj);
13537 +       if (status)
13538 +               return status;
13539 +
13540 +       status = alloc_enc_pages(rqstp);
13541 +       if (status)
13542 +               return status;
13543 +       /* XXXJBF: Oops!  Do we need rq_enc_pages really any more?? */
13544 +       first = snd_buf->page_base >> PAGE_CACHE_SHIFT;
13545 +       inpages = snd_buf->pages + first;
13546 +       snd_buf->pages = rqstp->rq_enc_pages;
13547 +       snd_buf->page_base -= first << PAGE_CACHE_SHIFT;
13548 +       /* XXX?: tail needs to be separate if we want to be able to expand
13549 +        * the head (since it's often put right after the head).  But is
13550 +        * expanding the head safe in any case? */
13551 +       if (snd_buf->page_len || snd_buf->tail[0].iov_len) {
13552 +               tmp = page_address(rqstp->rq_enc_pages[rqstp->rq_enc_pages_num - 1]);
13553 +               memcpy(tmp, snd_buf->tail[0].iov_base, snd_buf->tail[0].iov_len);
13554 +               snd_buf->tail[0].iov_base = tmp;
13555 +       }
13556 +       maj_stat = gss_wrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT, offset,
13557 +                               snd_buf, inpages);
13558 +       if (maj_stat == GSS_S_CONTEXT_EXPIRED)
13559 +               cred->cr_flags |= RPCAUTH_CRED_DEAD;
13560 +        status = -EIO; /* XXX? */
13561 +       if (maj_stat)
13562 +               return status;
13563 +
13564 +       *opaque_len = htonl(snd_buf->len - offset);
13565 +       /* guess whether we're in the head or the tail: */
13566 +       if (snd_buf->page_len || snd_buf->tail[0].iov_len)
13567 +               iov = snd_buf->tail;
13568 +       else
13569 +               iov = snd_buf->head;
13570 +       p = iov->iov_base + iov->iov_len;
13571 +       pad = 3 - ((snd_buf->len - offset - 1) & 3);
13572 +       memset(p, 0, pad);
13573 +       iov->iov_len += pad;
13574 +       snd_buf->len += pad;
13575 +
13576 +       return 0;
13577 +}
13578 +
13579  static int
13580  gss_wrap_req(struct rpc_task *task,
13581              kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
13582 @@ -894,9 +1015,11 @@ gss_wrap_req(struct rpc_task *task,
13583                         status = encode(rqstp, p, obj);
13584                         goto out;
13585                 case RPC_GSS_SVC_INTEGRITY:
13586 -                       status = gss_wrap_req_integ(ctx, encode, rqstp, p, obj);
13587 +                       status = gss_wrap_req_integ(cred, encode, rqstp, p, obj);
13588                         goto out;
13589                 case RPC_GSS_SVC_PRIVACY:
13590 +                       status = gss_wrap_req_priv(cred, encode, rqstp, p, obj);
13591 +                       goto out;
13592                 default:
13593                         goto out;
13594         }
13595 @@ -907,11 +1030,10 @@ out:
13596  }
13597  
13598  static inline int
13599 -gss_unwrap_resp_integ(struct gss_cl_ctx *ctx,
13600 -               kxdrproc_t decode, void *rqstp, u32 **p, void *obj)
13601 +gss_unwrap_resp_integ(struct rpc_cred *cred, struct rpc_rqst *rqstp, u32 **p)
13602  {
13603 -       struct rpc_rqst *req = (struct rpc_rqst *)rqstp;
13604 -       struct xdr_buf  *rcv_buf = &req->rq_rcv_buf;
13605 +       struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
13606 +       struct xdr_buf  *rcv_buf = &rqstp->rq_rcv_buf;
13607         struct xdr_buf integ_buf;
13608         struct xdr_netobj mic;
13609         u32 data_offset, mic_offset;
13610 @@ -926,7 +1048,7 @@ gss_unwrap_resp_integ(struct gss_cl_ctx 
13611         mic_offset = integ_len + data_offset;
13612         if (mic_offset > rcv_buf->len)
13613                 return status;
13614 -       if (ntohl(*(*p)++) != req->rq_seqno)
13615 +       if (ntohl(*(*p)++) != rqstp->rq_seqno)
13616                 return status;
13617  
13618         if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset,
13619 @@ -938,11 +1060,44 @@ gss_unwrap_resp_integ(struct gss_cl_ctx 
13620  
13621         maj_stat = gss_verify_mic(ctx->gc_gss_ctx, &integ_buf,
13622                         &mic, NULL);
13623 +       if (maj_stat == GSS_S_CONTEXT_EXPIRED)
13624 +               cred->cr_flags |= RPCAUTH_CRED_DEAD;
13625         if (maj_stat != GSS_S_COMPLETE)
13626                 return status;
13627         return 0;
13628  }
13629  
13630 +static inline int
13631 +gss_unwrap_resp_priv(struct rpc_cred *cred, struct rpc_rqst *rqstp, u32 **p)
13632 +{
13633 +       struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
13634 +       struct xdr_buf  *rcv_buf = &rqstp->rq_rcv_buf;
13635 +       u32 offset, out_offset;
13636 +       u32 opaque_len;
13637 +       u32 maj_stat;
13638 +       int status = -EIO;
13639 +
13640 +       opaque_len = ntohl(*(*p)++);
13641 +       offset = (u8 *)(*p) - (u8 *)rcv_buf->head[0].iov_base;
13642 +       if (offset + opaque_len > rcv_buf->len)
13643 +               return status;
13644 +       /* remove padding: */
13645 +       rcv_buf->len = offset + opaque_len;
13646 +
13647 +       maj_stat = gss_unwrap(ctx->gc_gss_ctx, GSS_C_QOP_DEFAULT,
13648 +                       offset, rcv_buf, &out_offset);
13649 +       if (maj_stat == GSS_S_CONTEXT_EXPIRED)
13650 +               cred->cr_flags |= RPCAUTH_CRED_DEAD;
13651 +       if (maj_stat != GSS_S_COMPLETE)
13652 +               return status;
13653 +       *p = (u32 *)(rcv_buf->head[0].iov_base + out_offset);
13654 +       if (ntohl(*(*p)++) != rqstp->rq_seqno)
13655 +               return status;
13656 +
13657 +       return 0;
13658 +}
13659 +
13660 +
13661  static int
13662  gss_unwrap_resp(struct rpc_task *task,
13663                 kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
13664 @@ -962,12 +1117,16 @@ gss_unwrap_resp(struct rpc_task *task,
13665                 case RPC_GSS_SVC_NONE:
13666                         goto out_decode;
13667                 case RPC_GSS_SVC_INTEGRITY:
13668 -                       status = gss_unwrap_resp_integ(ctx, decode, 
13669 -                                                       rqstp, &p, obj);
13670 +                       status = gss_unwrap_resp_integ(cred, rqstp, &p);
13671                         if (status)
13672                                 goto out;
13673                         break;
13674                 case RPC_GSS_SVC_PRIVACY:
13675 +                       status = gss_unwrap_resp_priv(cred, rqstp, &p);
13676 +                       if (status)
13677 +                               goto out;
13678 +                       break;
13679 +
13680                 default:
13681                         goto out;
13682         }
13683 --- linux-2.6.7/net/sunrpc/auth_gss/gss_spkm3_mech.c.lsec       2005-03-23 14:28:24.187372656 -0700
13684 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_spkm3_mech.c    2005-03-23 14:28:24.186372808 -0700
13685 @@ -0,0 +1,296 @@
13686 +/*
13687 + *  linux/net/sunrpc/gss_spkm3_mech.c
13688 + *
13689 + *  Copyright (c) 2003 The Regents of the University of Michigan.
13690 + *  All rights reserved.
13691 + *
13692 + *  Andy Adamson <andros@umich.edu>
13693 + *  J. Bruce Fields <bfields@umich.edu>
13694 + *
13695 + *  Redistribution and use in source and binary forms, with or without
13696 + *  modification, are permitted provided that the following conditions
13697 + *  are met:
13698 + *
13699 + *  1. Redistributions of source code must retain the above copyright
13700 + *     notice, this list of conditions and the following disclaimer.
13701 + *  2. Redistributions in binary form must reproduce the above copyright
13702 + *     notice, this list of conditions and the following disclaimer in the
13703 + *     documentation and/or other materials provided with the distribution.
13704 + *  3. Neither the name of the University nor the names of its
13705 + *     contributors may be used to endorse or promote products derived
13706 + *     from this software without specific prior written permission.
13707 + *
13708 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
13709 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
13710 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
13711 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
13712 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
13713 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
13714 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
13715 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
13716 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
13717 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
13718 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13719 + *
13720 + */
13721 +
13722 +#include <linux/module.h>
13723 +#include <linux/init.h>
13724 +#include <linux/types.h>
13725 +#include <linux/slab.h>
13726 +#include <linux/sunrpc/auth.h>
13727 +#include <linux/in.h>
13728 +#include <linux/sunrpc/svcauth_gss.h>
13729 +#include <linux/sunrpc/gss_spkm3.h>
13730 +#include <linux/sunrpc/xdr.h>
13731 +#include <linux/crypto.h>
13732 +
13733 +#ifdef RPC_DEBUG
13734 +# define RPCDBG_FACILITY       RPCDBG_AUTH
13735 +#endif
13736 +
13737 +struct xdr_netobj gss_mech_spkm3_oid =
13738 +   {7, "\053\006\001\005\005\001\003"};
13739 +
13740 +static inline int
13741 +get_bytes(char **ptr, const char *end, void *res, int len)
13742 +{
13743 +       char *p, *q;
13744 +       p = *ptr;
13745 +       q = p + len;
13746 +       if (q > end || q < p)
13747 +               return -1;
13748 +       memcpy(res, p, len);
13749 +       *ptr = q;
13750 +       return 0;
13751 +}
13752 +
13753 +static inline int
13754 +get_netobj(char **ptr, const char *end, struct xdr_netobj *res)
13755 +{
13756 +       char *p, *q;
13757 +       p = *ptr;
13758 +       if (get_bytes(&p, end, &res->len, sizeof(res->len)))
13759 +               return -1;
13760 +       q = p + res->len;
13761 +       if(res->len == 0)
13762 +               goto out_nocopy;
13763 +       if (q > end || q < p)
13764 +               return -1;
13765 +       if (!(res->data = kmalloc(res->len, GFP_KERNEL)))
13766 +               return -1;
13767 +       memcpy(res->data, p, res->len);
13768 +out_nocopy:
13769 +       *ptr = q;
13770 +       return 0;
13771 +}
13772 +
13773 +static inline int
13774 +get_key(char **p, char *end, struct crypto_tfm **res, int *resalg)
13775 +{
13776 +       struct xdr_netobj       key = {
13777 +               .len = 0,
13778 +               .data = NULL,
13779 +       };
13780 +       int                     alg_mode,setkey = 0;
13781 +       char                    *alg_name;
13782 +
13783 +       if (get_bytes(p, end, resalg, sizeof(int)))
13784 +               goto out_err;
13785 +       if ((get_netobj(p, end, &key)))
13786 +               goto out_err;
13787 +
13788 +       switch (*resalg) {
13789 +               case NID_des_cbc:
13790 +                       alg_name = "des";
13791 +                       alg_mode = CRYPTO_TFM_MODE_CBC;
13792 +                       setkey = 1;
13793 +                       break;
13794 +               case NID_md5:
13795 +                       if (key.len == 0) {
13796 +                               dprintk("RPC: SPKM3 get_key: NID_md5 zero Key length\n");
13797 +                       }
13798 +                       alg_name = "md5";
13799 +                       alg_mode = 0;
13800 +                       setkey = 0;
13801 +                       break;
13802 +               case NID_cast5_cbc:
13803 +                       dprintk("RPC: SPKM3 get_key: case cast5_cbc, UNSUPPORTED \n");
13804 +                       goto out_err;
13805 +                       break;
13806 +               default:
13807 +                       dprintk("RPC: SPKM3 get_key: unsupported algorithm %d", *resalg);
13808 +                       goto out_err_free_key;
13809 +       }
13810 +       if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
13811 +               goto out_err_free_key;
13812 +       if (setkey) {
13813 +               if (crypto_cipher_setkey(*res, key.data, key.len))
13814 +                       goto out_err_free_tfm;
13815 +       }
13816 +
13817 +       if(key.len > 0)
13818 +               kfree(key.data);
13819 +       return 0;
13820 +
13821 +out_err_free_tfm:
13822 +       crypto_free_tfm(*res);
13823 +out_err_free_key:
13824 +       if(key.len > 0)
13825 +               kfree(key.data);
13826 +out_err:
13827 +       return -1;
13828 +}
13829 +
13830 +static u32
13831 +gss_import_sec_context_spkm3(struct xdr_netobj *inbuf,
13832 +                               struct gss_ctx *ctx_id)
13833 +{
13834 +       char    *p = inbuf->data;
13835 +       char    *end = inbuf->data + inbuf->len;
13836 +       struct  spkm3_ctx *ctx;
13837 +
13838 +       if (!(ctx = kmalloc(sizeof(*ctx), GFP_KERNEL)))
13839 +               goto out_err;
13840 +       memset(ctx, 0, sizeof(*ctx));
13841 +
13842 +       if (get_netobj(&p, end, &ctx->ctx_id))
13843 +               goto out_err_free_ctx;
13844 +
13845 +       if (get_bytes(&p, end, &ctx->qop, sizeof(ctx->qop)))
13846 +               goto out_err_free_ctx_id;
13847 +
13848 +       if (get_netobj(&p, end, &ctx->mech_used))
13849 +               goto out_err_free_mech;
13850 +
13851 +       if (get_bytes(&p, end, &ctx->ret_flags, sizeof(ctx->ret_flags)))
13852 +               goto out_err_free_mech;
13853 +
13854 +       if (get_bytes(&p, end, &ctx->req_flags, sizeof(ctx->req_flags)))
13855 +               goto out_err_free_mech;
13856 +
13857 +       if (get_netobj(&p, end, &ctx->share_key))
13858 +               goto out_err_free_s_key;
13859 +
13860 +       if (get_key(&p, end, &ctx->derived_conf_key, &ctx->conf_alg)) {
13861 +               dprintk("RPC: SPKM3 confidentiality key will be NULL\n");
13862 +       }
13863 +
13864 +       if (get_key(&p, end, &ctx->derived_integ_key, &ctx->intg_alg)) {
13865 +               dprintk("RPC: SPKM3 integrity key will be NULL\n");
13866 +       }
13867 +
13868 +       if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
13869 +               goto out_err_free_s_key;
13870 +
13871 +       if (get_bytes(&p, end, &ctx->owf_alg, sizeof(ctx->owf_alg)))
13872 +               goto out_err_free_s_key;
13873 +
13874 +       if (p != end)
13875 +               goto out_err_free_s_key;
13876 +
13877 +       ctx_id->internal_ctx_id = ctx;
13878 +
13879 +       dprintk("Succesfully imported new spkm context.\n");
13880 +       return 0;
13881 +
13882 +out_err_free_s_key:
13883 +       kfree(ctx->share_key.data);
13884 +out_err_free_mech:
13885 +       kfree(ctx->mech_used.data);
13886 +out_err_free_ctx_id:
13887 +       kfree(ctx->ctx_id.data);
13888 +out_err_free_ctx:
13889 +       kfree(ctx);
13890 +out_err:
13891 +       return GSS_S_FAILURE;
13892 +}
13893 +
13894 +void
13895 +gss_delete_sec_context_spkm3(void *internal_ctx) {
13896 +       struct spkm3_ctx *sctx = internal_ctx;
13897 +
13898 +       if(sctx->derived_integ_key)
13899 +               crypto_free_tfm(sctx->derived_integ_key);
13900 +       if(sctx->derived_conf_key)
13901 +               crypto_free_tfm(sctx->derived_conf_key);
13902 +       if(sctx->share_key.data)
13903 +               kfree(sctx->share_key.data);
13904 +       if(sctx->mech_used.data)
13905 +               kfree(sctx->mech_used.data);
13906 +       kfree(sctx);
13907 +}
13908 +
13909 +u32
13910 +gss_verify_mic_spkm3(struct gss_ctx            *ctx,
13911 +                       struct xdr_buf          *signbuf,
13912 +                       struct xdr_netobj       *checksum,
13913 +                       u32             *qstate) {
13914 +       u32 maj_stat = 0;
13915 +       int qop_state = 0;
13916 +       struct spkm3_ctx *sctx = ctx->internal_ctx_id;
13917 +
13918 +       dprintk("RPC: gss_verify_mic_spkm3 calling spkm3_read_token\n");
13919 +       maj_stat = spkm3_read_token(sctx, checksum, signbuf, &qop_state,
13920 +                                  SPKM_MIC_TOK);
13921 +
13922 +       if (!maj_stat && qop_state)
13923 +           *qstate = qop_state;
13924 +
13925 +       dprintk("RPC: gss_verify_mic_spkm3 returning %d\n", maj_stat);
13926 +       return maj_stat;
13927 +}
13928 +
13929 +u32
13930 +gss_get_mic_spkm3(struct gss_ctx       *ctx,
13931 +                    u32                qop,
13932 +                    struct xdr_buf     *message_buffer,
13933 +                    struct xdr_netobj  *message_token) {
13934 +       u32 err = 0;
13935 +       struct spkm3_ctx *sctx = ctx->internal_ctx_id;
13936 +
13937 +       dprintk("RPC: gss_get_mic_spkm3\n");
13938 +
13939 +       err = spkm3_make_token(sctx, qop, message_buffer,
13940 +                             message_token, SPKM_MIC_TOK);
13941 +       return err;
13942 +}
13943 +
13944 +static struct gss_api_ops gss_spkm3_ops = {
13945 +       .gss_import_sec_context = gss_import_sec_context_spkm3,
13946 +       .gss_get_mic            = gss_get_mic_spkm3,
13947 +       .gss_verify_mic         = gss_verify_mic_spkm3,
13948 +       .gss_delete_sec_context = gss_delete_sec_context_spkm3,
13949 +};
13950 +
13951 +static struct pf_desc gss_spkm3_pfs[] = {
13952 +       {RPC_AUTH_GSS_SPKM, 0, RPC_GSS_SVC_NONE, "spkm3"},
13953 +       {RPC_AUTH_GSS_SPKMI, 0, RPC_GSS_SVC_INTEGRITY, "spkm3i"},
13954 +};
13955 +
13956 +static struct gss_api_mech gss_spkm3_mech = {
13957 +       .gm_name        = "spkm3",
13958 +       .gm_owner       = THIS_MODULE,
13959 +       .gm_ops         = &gss_spkm3_ops,
13960 +       .gm_pf_num      = ARRAY_SIZE(gss_spkm3_pfs),
13961 +       .gm_pfs         = gss_spkm3_pfs,
13962 +};
13963 +
13964 +static int __init init_spkm3_module(void)
13965 +{
13966 +       int status;
13967 +
13968 +       status = gss_mech_register(&gss_spkm3_mech);
13969 +       if (status)
13970 +               printk("Failed to register spkm3 gss mechanism!\n");
13971 +       return 0;
13972 +}
13973 +
13974 +static void __exit cleanup_spkm3_module(void)
13975 +{
13976 +       gss_mech_unregister(&gss_spkm3_mech);
13977 +}
13978 +
13979 +MODULE_LICENSE("GPL");
13980 +module_init(init_spkm3_module);
13981 +module_exit(cleanup_spkm3_module);
13982 --- linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_crypto.c.lsec      2004-06-15 23:18:55.000000000 -0600
13983 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_crypto.c   2005-03-23 14:28:24.840273400 -0700
13984 @@ -139,17 +139,91 @@ buf_to_sg(struct scatterlist *sg, char *
13985         sg->length = len;
13986  }
13987  
13988 +static int
13989 +process_xdr_buf(struct xdr_buf *buf, int offset, int len,
13990 +               int (*actor)(struct scatterlist *, void *), void *data)
13991 +{
13992 +       int i, page_len, thislen, page_offset, ret = 0;
13993 +       struct scatterlist      sg[1];
13994 +
13995 +       if (offset >= buf->head[0].iov_len) {
13996 +               offset -= buf->head[0].iov_len;
13997 +       } else {
13998 +               thislen = buf->head[0].iov_len - offset;
13999 +               if (thislen > len)
14000 +                       thislen = len;
14001 +               buf_to_sg(sg, buf->head[0].iov_base + offset, thislen);
14002 +               ret = actor(sg, data);
14003 +               if (ret)
14004 +                       goto out;
14005 +               offset = 0;
14006 +               len -= thislen;
14007 +       }
14008 +       if (len == 0)
14009 +               goto out;
14010 +
14011 +       if (offset >= buf->page_len) {
14012 +               offset -= buf->page_len;
14013 +       } else {
14014 +               page_len = buf->page_len - offset;
14015 +               if (page_len > len)
14016 +                       page_len = len;
14017 +               len -= page_len;
14018 +               page_offset = (offset + buf->page_base) & (PAGE_CACHE_SIZE - 1);
14019 +               i = (offset + buf->page_base) >> PAGE_CACHE_SHIFT;
14020 +               thislen = PAGE_CACHE_SIZE - page_offset;
14021 +               do {
14022 +                       if (thislen > page_len)
14023 +                               thislen = page_len;
14024 +                       sg->page = buf->pages[i];
14025 +                       sg->offset = page_offset;
14026 +                       sg->length = thislen;
14027 +                       ret = actor(sg, data);
14028 +                       if (ret)
14029 +                               goto out;
14030 +                       page_len -= thislen;
14031 +                       i++;
14032 +                       page_offset = 0;
14033 +                       thislen = PAGE_CACHE_SIZE;
14034 +               } while (page_len != 0);
14035 +               offset = 0;
14036 +       }
14037 +       if (len == 0)
14038 +               goto out;
14039 +
14040 +       if (offset < buf->tail[0].iov_len) {
14041 +               thislen = buf->tail[0].iov_len - offset;
14042 +               if (thislen > len)
14043 +                       thislen = len;
14044 +               buf_to_sg(sg, buf->tail[0].iov_base + offset, thislen);
14045 +               ret = actor(sg, data);
14046 +               len -= thislen;
14047 +       }
14048 +       if (len != 0)
14049 +               ret = -EINVAL;
14050 +out:
14051 +       return ret;
14052 +}
14053 +
14054 +static int
14055 +checksummer(struct scatterlist *sg, void *data)
14056 +{
14057 +       struct crypto_tfm *tfm = (struct crypto_tfm *)data;
14058 +
14059 +       crypto_digest_update(tfm, sg, 1);
14060 +
14061 +       return 0;
14062 +}
14063 +
14064  /* checksum the plaintext data and hdrlen bytes of the token header */
14065  s32
14066  make_checksum(s32 cksumtype, char *header, int hdrlen, struct xdr_buf *body,
14067 -                  struct xdr_netobj *cksum)
14068 +                  int body_offset, struct xdr_netobj *cksum)
14069  {
14070         char                            *cksumname;
14071         struct crypto_tfm               *tfm = NULL; /* XXX add to ctx? */
14072         struct scatterlist              sg[1];
14073         u32                             code = GSS_S_FAILURE;
14074 -       int                             len, thislen, offset;
14075 -       int                             i;
14076  
14077         switch (cksumtype) {
14078                 case CKSUMTYPE_RSA_MD5:
14079 @@ -169,35 +243,8 @@ make_checksum(s32 cksumtype, char *heade
14080         crypto_digest_init(tfm);
14081         buf_to_sg(sg, header, hdrlen);
14082         crypto_digest_update(tfm, sg, 1);
14083 -       if (body->head[0].iov_len) {
14084 -               buf_to_sg(sg, body->head[0].iov_base, body->head[0].iov_len);
14085 -               crypto_digest_update(tfm, sg, 1);
14086 -       }
14087 -
14088 -       len = body->page_len;
14089 -       if (len != 0) {
14090 -               offset = body->page_base & (PAGE_CACHE_SIZE - 1);
14091 -               i = body->page_base >> PAGE_CACHE_SHIFT;
14092 -               thislen = PAGE_CACHE_SIZE - offset;
14093 -               do {
14094 -                       if (thislen > len)
14095 -                               thislen = len;
14096 -                       sg->page = body->pages[i];
14097 -                       sg->offset = offset;
14098 -                       sg->length = thislen;
14099 -                       kmap(sg->page); /* XXX kmap_atomic? */
14100 -                       crypto_digest_update(tfm, sg, 1);
14101 -                       kunmap(sg->page);
14102 -                       len -= thislen;
14103 -                       i++;
14104 -                       offset = 0;
14105 -                       thislen = PAGE_CACHE_SIZE;
14106 -               } while(len != 0);
14107 -       }
14108 -       if (body->tail[0].iov_len) {
14109 -               buf_to_sg(sg, body->tail[0].iov_base, body->tail[0].iov_len);
14110 -               crypto_digest_update(tfm, sg, 1);
14111 -       }
14112 +       process_xdr_buf(body, body_offset, body->len - body_offset,
14113 +                       checksummer, tfm);
14114         crypto_digest_final(tfm, cksum->data);
14115         code = 0;
14116  out:
14117 @@ -207,3 +254,154 @@ out:
14118  }
14119  
14120  EXPORT_SYMBOL(make_checksum);
14121 +
14122 +struct encryptor_desc {
14123 +       u8 iv[8]; /* XXX hard-coded blocksize */
14124 +       struct crypto_tfm *tfm;
14125 +       int pos;
14126 +       struct xdr_buf *outbuf;
14127 +       struct page **pages;
14128 +       struct scatterlist infrags[4];
14129 +       struct scatterlist outfrags[4];
14130 +       int fragno;
14131 +       int fraglen;
14132 +};
14133 +
14134 +static int
14135 +encryptor(struct scatterlist *sg, void *data)
14136 +{
14137 +       struct encryptor_desc *desc = data;
14138 +       struct xdr_buf *outbuf = desc->outbuf;
14139 +       struct page *in_page;
14140 +       int thislen = desc->fraglen + sg->length;
14141 +       int fraglen, ret;
14142 +       int page_pos;
14143 +
14144 +       /* Worst case is 4 fragments: head, end of page 1, start
14145 +        * of page 2, tail.  Anything more is a bug. */
14146 +       BUG_ON(desc->fragno > 3);
14147 +       desc->infrags[desc->fragno] = *sg;
14148 +       desc->outfrags[desc->fragno] = *sg;
14149 +
14150 +       page_pos = desc->pos - outbuf->head[0].iov_len;
14151 +       if (page_pos >= 0 && page_pos < outbuf->page_len) {
14152 +               /* pages are not in place: */
14153 +               int i = (page_pos + outbuf->page_base) >> PAGE_CACHE_SHIFT;
14154 +               in_page = desc->pages[i];
14155 +       } else {
14156 +               in_page = sg->page;
14157 +       }
14158 +       desc->infrags[desc->fragno].page = in_page;
14159 +       desc->fragno++;
14160 +       desc->fraglen += sg->length;
14161 +       desc->pos += sg->length;
14162 +
14163 +       fraglen = thislen & 7; /* XXX hardcoded blocksize */
14164 +       thislen -= fraglen;
14165 +
14166 +       if (thislen == 0)
14167 +               return 0;
14168 +
14169 +       ret = crypto_cipher_encrypt_iv(desc->tfm, desc->outfrags, desc->infrags,
14170 +                                       thislen, desc->iv);
14171 +       if (ret)
14172 +               return ret;
14173 +       if (fraglen) {
14174 +               desc->outfrags[0].page = sg->page;
14175 +               desc->outfrags[0].offset = sg->offset + sg->length - fraglen;
14176 +               desc->outfrags[0].length = fraglen;
14177 +               desc->infrags[0] = desc->outfrags[0];
14178 +               desc->infrags[0].page = in_page;
14179 +               desc->fragno = 1;
14180 +               desc->fraglen = fraglen;
14181 +       } else {
14182 +               desc->fragno = 0;
14183 +               desc->fraglen = 0;
14184 +       }
14185 +       return 0;
14186 +}
14187 +
14188 +int
14189 +gss_encrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset,
14190 +               struct page **pages)
14191 +{
14192 +       int ret;
14193 +       struct encryptor_desc desc;
14194 +
14195 +       BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0);
14196 +
14197 +       memset(desc.iv, 0, sizeof(desc.iv));
14198 +       desc.tfm = tfm;
14199 +       desc.pos = offset;
14200 +       desc.outbuf = buf;
14201 +       desc.pages = pages;
14202 +       desc.fragno = 0;
14203 +       desc.fraglen = 0;
14204 +
14205 +       ret = process_xdr_buf(buf, offset, buf->len - offset, encryptor, &desc);
14206 +       return ret;
14207 +}
14208 +
14209 +EXPORT_SYMBOL(gss_encrypt_xdr_buf);
14210 +
14211 +struct decryptor_desc {
14212 +       u8 iv[8]; /* XXX hard-coded blocksize */
14213 +       struct crypto_tfm *tfm;
14214 +       struct scatterlist frags[4];
14215 +       int fragno;
14216 +       int fraglen;
14217 +};
14218 +
14219 +static int
14220 +decryptor(struct scatterlist *sg, void *data)
14221 +{
14222 +       struct decryptor_desc *desc = data;
14223 +       int thislen = desc->fraglen + sg->length;
14224 +       int fraglen, ret;
14225 +
14226 +       /* Worst case is 4 fragments: head, end of page 1, start
14227 +        * of page 2, tail.  Anything more is a bug. */
14228 +       BUG_ON(desc->fragno > 3);
14229 +       desc->frags[desc->fragno] = *sg;
14230 +       desc->fragno++;
14231 +       desc->fraglen += sg->length;
14232 +
14233 +       fraglen = thislen & 7; /* XXX hardcoded blocksize */
14234 +       thislen -= fraglen;
14235 +
14236 +       if (thislen == 0)
14237 +               return 0;
14238 +
14239 +       ret = crypto_cipher_decrypt_iv(desc->tfm, desc->frags, desc->frags,
14240 +                                       thislen, desc->iv);
14241 +       if (ret)
14242 +               return ret;
14243 +       if (fraglen) {
14244 +               desc->frags[0].page = sg->page;
14245 +               desc->frags[0].offset = sg->offset + sg->length - fraglen;
14246 +               desc->frags[0].length = fraglen;
14247 +               desc->fragno = 1;
14248 +               desc->fraglen = fraglen;
14249 +       } else {
14250 +               desc->fragno = 0;
14251 +               desc->fraglen = 0;
14252 +       }
14253 +       return 0;
14254 +}
14255 +
14256 +int
14257 +gss_decrypt_xdr_buf(struct crypto_tfm *tfm, struct xdr_buf *buf, int offset)
14258 +{
14259 +       struct decryptor_desc desc;
14260 +
14261 +       /* XXXJBF: */
14262 +       BUG_ON((buf->len - offset) % crypto_tfm_alg_blocksize(tfm) != 0);
14263 +
14264 +       memset(desc.iv, 0, sizeof(desc.iv));
14265 +       desc.tfm = tfm;
14266 +       desc.fragno = 0;
14267 +       desc.fraglen = 0;
14268 +       return process_xdr_buf(buf, offset, buf->len - offset, decryptor, &desc);
14269 +}
14270 +
14271 +EXPORT_SYMBOL(gss_decrypt_xdr_buf);
14272 --- linux-2.6.7/net/sunrpc/auth_gss/gss_spkm3_seal.c.lsec       2005-03-23 14:28:24.239364752 -0700
14273 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_spkm3_seal.c    2005-03-23 14:28:24.238364904 -0700
14274 @@ -0,0 +1,132 @@
14275 +/*
14276 + *  linux/net/sunrpc/gss_spkm3_seal.c
14277 + *
14278 + *  Copyright (c) 2003 The Regents of the University of Michigan.
14279 + *  All rights reserved.
14280 + *
14281 + *  Andy Adamson <andros@umich.edu>
14282 + *
14283 + *  Redistribution and use in source and binary forms, with or without
14284 + *  modification, are permitted provided that the following conditions
14285 + *  are met:
14286 + *
14287 + *  1. Redistributions of source code must retain the above copyright
14288 + *     notice, this list of conditions and the following disclaimer.
14289 + *  2. Redistributions in binary form must reproduce the above copyright
14290 + *     notice, this list of conditions and the following disclaimer in the
14291 + *     documentation and/or other materials provided with the distribution.
14292 + *  3. Neither the name of the University nor the names of its
14293 + *     contributors may be used to endorse or promote products derived
14294 + *     from this software without specific prior written permission.
14295 + *
14296 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
14297 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
14298 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
14299 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
14300 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
14301 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
14302 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
14303 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
14304 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
14305 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
14306 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14307 + *
14308 + */
14309 +
14310 +#include <linux/types.h>
14311 +#include <linux/slab.h>
14312 +#include <linux/jiffies.h>
14313 +#include <linux/sunrpc/gss_spkm3.h>
14314 +#include <linux/random.h>
14315 +#include <linux/crypto.h>
14316 +
14317 +#ifdef RPC_DEBUG
14318 +# define RPCDBG_FACILITY        RPCDBG_AUTH
14319 +#endif
14320 +
14321 +/*
14322 + * spkm3_make_token()
14323 + *
14324 + * Only SPKM_MIC_TOK with md5 intg-alg is supported
14325 + */
14326 +
14327 +u32
14328 +spkm3_make_token(struct spkm3_ctx *ctx, int qop_req,
14329 +                  struct xdr_buf * text, struct xdr_netobj * token,
14330 +                  int toktype)
14331 +{
14332 +       s32                     checksum_type;
14333 +       char                    tokhdrbuf[25];
14334 +       struct xdr_netobj       md5cksum = {.len = 0, .data = NULL};
14335 +       struct xdr_netobj       mic_hdr = {.len = 0, .data = tokhdrbuf};
14336 +       int                     tmsglen, tokenlen = 0;
14337 +       unsigned char           *ptr;
14338 +       s32                     now;
14339 +       int                     ctxelen = 0, ctxzbit = 0;
14340 +       int                     md5elen = 0, md5zbit = 0;
14341 +
14342 +       dprintk("RPC: spkm3_make_token\n");
14343 +
14344 +       now = jiffies;
14345 +       if (qop_req != 0)
14346 +               goto out_err;
14347 +
14348 +       if (ctx->ctx_id.len != 16) {
14349 +               dprintk("RPC: spkm3_make_token BAD ctx_id.len %d\n",
14350 +                       ctx->ctx_id.len);
14351 +               goto out_err;
14352 +       }
14353 +
14354 +       switch (ctx->intg_alg) {
14355 +               case NID_md5:
14356 +                       checksum_type = CKSUMTYPE_RSA_MD5;
14357 +                       break;
14358 +               default:
14359 +                       dprintk("RPC: gss_spkm3_seal: ctx->signalg %d not"
14360 +                               " supported\n", ctx->intg_alg);
14361 +                       goto out_err;
14362 +       }
14363 +       /* XXX since we don't support WRAP, perhaps we don't care... */
14364 +       if (ctx->conf_alg != NID_cast5_cbc) {
14365 +               dprintk("RPC: gss_spkm3_seal: ctx->sealalg %d not supported\n",
14366 +                       ctx->conf_alg);
14367 +               goto out_err;
14368 +       }
14369 +
14370 +       if (toktype == SPKM_MIC_TOK) {
14371 +               tmsglen = 0;
14372 +               /* Calculate checksum over the mic-header */
14373 +               asn1_bitstring_len(&ctx->ctx_id, &ctxelen, &ctxzbit);
14374 +               spkm3_mic_header(&mic_hdr.data, &mic_hdr.len, ctx->ctx_id.data,
14375 +                                        ctxelen, ctxzbit);
14376 +
14377 +               if (make_checksum(checksum_type, mic_hdr.data, mic_hdr.len,
14378 +                                            text, &md5cksum))
14379 +                       goto out_err;
14380 +
14381 +               asn1_bitstring_len(&md5cksum, &md5elen, &md5zbit);
14382 +               tokenlen = 10 + ctxelen + 1 + 2 + md5elen + 1;
14383 +
14384 +               /* Create token header using generic routines */
14385 +               token->len = g_token_size(&ctx->mech_used, tokenlen + tmsglen);
14386 +
14387 +               ptr = token->data;
14388 +               g_make_token_header(&ctx->mech_used, tokenlen + tmsglen, &ptr);
14389 +
14390 +               spkm3_make_mic_token(&ptr, tokenlen, &mic_hdr, &md5cksum, md5elen, md5zbit);
14391 +       } else if (toktype == SPKM_WRAP_TOK) { /* Not Supported */
14392 +               dprintk("RPC: gss_spkm3_seal: SPKM_WRAP_TOK not supported\n");
14393 +               goto out_err;
14394 +       }
14395 +       kfree(md5cksum.data);
14396 +
14397 +       /* XXX need to implement sequence numbers, and ctx->expired */
14398 +
14399 +       return  GSS_S_COMPLETE;
14400 +out_err:
14401 +       if (md5cksum.data)
14402 +               kfree(md5cksum.data);
14403 +       token->data = 0;
14404 +       token->len = 0;
14405 +       return GSS_S_FAILURE;
14406 +}
14407 --- linux-2.6.7/net/sunrpc/auth_gss/svcauth_gss.c.lsec  2004-06-15 23:19:22.000000000 -0600
14408 +++ linux-2.6.7/net/sunrpc/auth_gss/svcauth_gss.c       2005-03-23 14:28:24.405339520 -0700
14409 @@ -37,6 +37,7 @@
14410   *
14411   */
14412  
14413 +#include <asm/bitops.h>
14414  #include <linux/types.h>
14415  #include <linux/module.h>
14416  #include <linux/pagemap.h>
14417 @@ -78,7 +79,6 @@ struct rsi {
14418  
14419  static struct cache_head *rsi_table[RSI_HASHMAX];
14420  static struct cache_detail rsi_cache;
14421 -static struct rsi *rsi_lookup(struct rsi *item, int set);
14422  
14423  static void rsi_free(struct rsi *rsii)
14424  {
14425 @@ -125,38 +125,6 @@ static inline int dup_netobj(struct xdr_
14426         return dup_to_netobj(dst, src->data, src->len);
14427  }
14428  
14429 -static inline void rsi_init(struct rsi *new, struct rsi *item)
14430 -{
14431 -       new->out_handle.data = NULL;
14432 -       new->out_handle.len = 0;
14433 -       new->out_token.data = NULL;
14434 -       new->out_token.len = 0;
14435 -       new->in_handle.len = item->in_handle.len;
14436 -       item->in_handle.len = 0;
14437 -       new->in_token.len = item->in_token.len;
14438 -       item->in_token.len = 0;
14439 -       new->in_handle.data = item->in_handle.data;
14440 -       item->in_handle.data = NULL;
14441 -       new->in_token.data = item->in_token.data;
14442 -       item->in_token.data = NULL;
14443 -}
14444 -
14445 -static inline void rsi_update(struct rsi *new, struct rsi *item)
14446 -{
14447 -       BUG_ON(new->out_handle.data || new->out_token.data);
14448 -       new->out_handle.len = item->out_handle.len;
14449 -       item->out_handle.len = 0;
14450 -       new->out_token.len = item->out_token.len;
14451 -       item->out_token.len = 0;
14452 -       new->out_handle.data = item->out_handle.data;
14453 -       item->out_handle.data = NULL;
14454 -       new->out_token.data = item->out_token.data;
14455 -       item->out_token.data = NULL;
14456 -
14457 -       new->major_status = item->major_status;
14458 -       new->minor_status = item->minor_status;
14459 -}
14460 -
14461  static void rsi_request(struct cache_detail *cd,
14462                         struct cache_head *h,
14463                         char **bpp, int *blen)
14464 @@ -168,6 +136,75 @@ static void rsi_request(struct cache_det
14465         (*bpp)[-1] = '\n';
14466  }
14467  
14468 +static inline int
14469 +gssd_reply(struct rsi *item)
14470 +{
14471 +       struct rsi *tmp;
14472 +       struct cache_head **hp, **head;
14473 +
14474 +       head = &rsi_cache.hash_table[rsi_hash(item)];
14475 +       write_lock(&rsi_cache.hash_lock);
14476 +       for (hp = head; *hp != NULL; hp = &tmp->h.next) {
14477 +               tmp = container_of(*hp, struct rsi, h);
14478 +               if (rsi_match(tmp, item)) {
14479 +                       cache_get(&tmp->h);
14480 +                       clear_bit(CACHE_HASHED, &tmp->h.flags);
14481 +                       *hp = tmp->h.next;
14482 +                       tmp->h.next = NULL;
14483 +                       rsi_cache.entries--;
14484 +                       if (test_bit(CACHE_VALID, &tmp->h.flags)) {
14485 +                               write_unlock(&rsi_cache.hash_lock);
14486 +                               rsi_put(&tmp->h, &rsi_cache);
14487 +                               return -EINVAL;
14488 +                       }
14489 +                       set_bit(CACHE_HASHED, &item->h.flags);
14490 +                       item->h.next = *hp;
14491 +                       *hp = &item->h;
14492 +                       rsi_cache.entries++;
14493 +                       set_bit(CACHE_VALID, &item->h.flags);
14494 +                       item->h.last_refresh = get_seconds();
14495 +                       write_unlock(&rsi_cache.hash_lock);
14496 +                       cache_fresh(&rsi_cache, &tmp->h, 0);
14497 +                       rsi_put(&tmp->h, &rsi_cache);
14498 +                       return 0;
14499 +               }
14500 +       }
14501 +       write_unlock(&rsi_cache.hash_lock);
14502 +       return -EINVAL;
14503 +}
14504 +
14505 +static inline struct rsi *
14506 +gssd_upcall(struct rsi *item, struct svc_rqst *rqstp)
14507 +{
14508 +       struct rsi *tmp;
14509 +       struct cache_head **hp, **head;
14510 +
14511 +       head = &rsi_cache.hash_table[rsi_hash(item)];
14512 +       read_lock(&rsi_cache.hash_lock);
14513 +       for (hp = head; *hp != NULL; hp = &tmp->h.next) {
14514 +               tmp = container_of(*hp, struct rsi, h);
14515 +               if (rsi_match(tmp, item)) {
14516 +                       if (!test_bit(CACHE_VALID, &tmp->h.flags)) {
14517 +                               read_unlock(&rsi_cache.hash_lock);
14518 +                               return NULL;
14519 +                       }
14520 +                       *hp = tmp->h.next;
14521 +                       tmp->h.next = NULL;
14522 +                       rsi_cache.entries--;
14523 +                       read_unlock(&rsi_cache.hash_lock);
14524 +                       return tmp;
14525 +               }
14526 +       }
14527 +       cache_get(&item->h);
14528 +       item->h.next = *head;
14529 +       *head = &item->h;
14530 +       rsi_cache.entries++;
14531 +       read_unlock(&rsi_cache.hash_lock);
14532 +       cache_get(&item->h);
14533 +       if (cache_check(&rsi_cache, &item->h, &rqstp->rq_chandle))
14534 +               return NULL;
14535 +       return item;
14536 +}
14537  
14538  static int rsi_parse(struct cache_detail *cd,
14539                      char *mesg, int mlen)
14540 @@ -176,17 +213,22 @@ static int rsi_parse(struct cache_detail
14541         char *buf = mesg;
14542         char *ep;
14543         int len;
14544 -       struct rsi rsii, *rsip = NULL;
14545 +       struct rsi *rsii;
14546         time_t expiry;
14547         int status = -EINVAL;
14548  
14549 -       memset(&rsii, 0, sizeof(rsii));
14550 +       rsii = kmalloc(sizeof(*rsii), GFP_KERNEL);
14551 +       if (!rsii)
14552 +               return -ENOMEM;
14553 +       memset(rsii, 0, sizeof(*rsii));
14554 +       cache_init(&rsii->h);
14555 +
14556         /* handle */
14557         len = qword_get(&mesg, buf, mlen);
14558         if (len < 0)
14559                 goto out;
14560         status = -ENOMEM;
14561 -       if (dup_to_netobj(&rsii.in_handle, buf, len))
14562 +       if (dup_to_netobj(&rsii->in_handle, buf, len))
14563                 goto out;
14564  
14565         /* token */
14566 @@ -195,10 +237,9 @@ static int rsi_parse(struct cache_detail
14567         if (len < 0)
14568                 goto out;
14569         status = -ENOMEM;
14570 -       if (dup_to_netobj(&rsii.in_token, buf, len))
14571 +       if (dup_to_netobj(&rsii->in_token, buf, len))
14572                 goto out;
14573  
14574 -       rsii.h.flags = 0;
14575         /* expiry */
14576         expiry = get_expiry(&mesg);
14577         status = -EINVAL;
14578 @@ -212,13 +253,13 @@ static int rsi_parse(struct cache_detail
14579         if (len == 0) {
14580                 goto out;
14581         } else {
14582 -               rsii.major_status = simple_strtoul(buf, &ep, 10);
14583 +               rsii->major_status = simple_strtoul(buf, &ep, 10);
14584                 if (*ep)
14585                         goto out;
14586                 len = qword_get(&mesg, buf, mlen);
14587                 if (len <= 0)
14588                         goto out;
14589 -               rsii.minor_status = simple_strtoul(buf, &ep, 10);
14590 +               rsii->minor_status = simple_strtoul(buf, &ep, 10);
14591                 if (*ep)
14592                         goto out;
14593  
14594 @@ -227,7 +268,7 @@ static int rsi_parse(struct cache_detail
14595                 if (len < 0)
14596                         goto out;
14597                 status = -ENOMEM;
14598 -               if (dup_to_netobj(&rsii.out_handle, buf, len))
14599 +               if (dup_to_netobj(&rsii->out_handle, buf, len))
14600                         goto out;
14601  
14602                 /* out_token */
14603 @@ -236,16 +277,14 @@ static int rsi_parse(struct cache_detail
14604                 if (len < 0)
14605                         goto out;
14606                 status = -ENOMEM;
14607 -               if (dup_to_netobj(&rsii.out_token, buf, len))
14608 +               if (dup_to_netobj(&rsii->out_token, buf, len))
14609                         goto out;
14610         }
14611 -       rsii.h.expiry_time = expiry;
14612 -       rsip = rsi_lookup(&rsii, 1);
14613 -       status = 0;
14614 +       rsii->h.expiry_time = expiry;
14615 +       status = gssd_reply(rsii);
14616  out:
14617 -       rsi_free(&rsii);
14618 -       if (rsip)
14619 -               rsi_put(&rsip->h, &rsi_cache);
14620 +       if (rsii)
14621 +               rsi_put(&rsii->h, &rsi_cache);
14622         return status;
14623  }
14624  
14625 @@ -258,8 +297,6 @@ static struct cache_detail rsi_cache = {
14626         .cache_parse    = rsi_parse,
14627  };
14628  
14629 -static DefineSimpleCacheLookup(rsi, 0)
14630 -
14631  /*
14632   * The rpcsec_context cache is used to store a context that is
14633   * used in data exchange.
14634 @@ -292,7 +329,6 @@ struct rsc {
14635  
14636  static struct cache_head *rsc_table[RSC_HASHMAX];
14637  static struct cache_detail rsc_cache;
14638 -static struct rsc *rsc_lookup(struct rsc *item, int set);
14639  
14640  static void rsc_free(struct rsc *rsci)
14641  {
14642 @@ -325,26 +361,44 @@ rsc_match(struct rsc *new, struct rsc *t
14643         return netobj_equal(&new->handle, &tmp->handle);
14644  }
14645  
14646 -static inline void
14647 -rsc_init(struct rsc *new, struct rsc *tmp)
14648 +static struct rsc *rsc_lookup(struct rsc *item, int set)
14649  {
14650 -       new->handle.len = tmp->handle.len;
14651 -       tmp->handle.len = 0;
14652 -       new->handle.data = tmp->handle.data;
14653 -       tmp->handle.data = NULL;
14654 -       new->mechctx = NULL;
14655 -       new->cred.cr_group_info = NULL;
14656 -}
14657 -
14658 -static inline void
14659 -rsc_update(struct rsc *new, struct rsc *tmp)
14660 -{
14661 -       new->mechctx = tmp->mechctx;
14662 -       tmp->mechctx = NULL;
14663 -       memset(&new->seqdata, 0, sizeof(new->seqdata));
14664 -       spin_lock_init(&new->seqdata.sd_lock);
14665 -       new->cred = tmp->cred;
14666 -       tmp->cred.cr_group_info = NULL;
14667 +       struct rsc *tmp = NULL;
14668 +       struct cache_head **hp, **head;
14669 +       head = &rsc_cache.hash_table[rsc_hash(item)];
14670 +
14671 +       if (set)
14672 +               write_lock(&rsc_cache.hash_lock);
14673 +       else
14674 +               read_lock(&rsc_cache.hash_lock);
14675 +       for (hp = head; *hp != NULL; hp = &tmp->h.next) {
14676 +               tmp = container_of(*hp, struct rsc, h);
14677 +               if (!rsc_match(tmp, item))
14678 +                       continue;
14679 +               cache_get(&tmp->h);
14680 +               if (!set)
14681 +                       goto out_noset;
14682 +               *hp = tmp->h.next;
14683 +               tmp->h.next = NULL;
14684 +               clear_bit(CACHE_HASHED, &tmp->h.flags);
14685 +               rsc_put(&tmp->h, &rsc_cache);
14686 +               goto out_set;
14687 +       }
14688 +       /* Didn't find anything */
14689 +       if (!set)
14690 +               goto out_noset;
14691 +       rsc_cache.entries++;
14692 +out_set:
14693 +       set_bit(CACHE_HASHED, &item->h.flags);
14694 +       item->h.next = *head;
14695 +       *head = &item->h;
14696 +       write_unlock(&rsc_cache.hash_lock);
14697 +       cache_fresh(&rsc_cache, &item->h, item->h.expiry_time);
14698 +       cache_get(&item->h);
14699 +       return item;
14700 +out_noset:
14701 +       read_unlock(&rsc_cache.hash_lock);
14702 +       return tmp;
14703  }
14704  
14705  static int rsc_parse(struct cache_detail *cd,
14706 @@ -353,19 +407,22 @@ static int rsc_parse(struct cache_detail
14707         /* contexthandle expiry [ uid gid N <n gids> mechname ...mechdata... ] */
14708         char *buf = mesg;
14709         int len, rv;
14710 -       struct rsc rsci, *rscp = NULL;
14711 +       struct rsc *rsci, *res = NULL;
14712         time_t expiry;
14713         int status = -EINVAL;
14714  
14715 -       memset(&rsci, 0, sizeof(rsci));
14716 +       rsci = kmalloc(sizeof(*rsci), GFP_KERNEL);
14717 +       if (!rsci)
14718 +               return -ENOMEM;
14719 +       memset(rsci, 0, sizeof(*rsci));
14720 +       cache_init(&rsci->h);
14721         /* context handle */
14722         len = qword_get(&mesg, buf, mlen);
14723         if (len < 0) goto out;
14724         status = -ENOMEM;
14725 -       if (dup_to_netobj(&rsci.handle, buf, len))
14726 +       if (dup_to_netobj(&rsci->handle, buf, len))
14727                 goto out;
14728  
14729 -       rsci.h.flags = 0;
14730         /* expiry */
14731         expiry = get_expiry(&mesg);
14732         status = -EINVAL;
14733 @@ -373,26 +430,26 @@ static int rsc_parse(struct cache_detail
14734                 goto out;
14735  
14736         /* uid, or NEGATIVE */
14737 -       rv = get_int(&mesg, &rsci.cred.cr_uid);
14738 +       rv = get_int(&mesg, &rsci->cred.cr_uid);
14739         if (rv == -EINVAL)
14740                 goto out;
14741         if (rv == -ENOENT)
14742 -               set_bit(CACHE_NEGATIVE, &rsci.h.flags);
14743 +               set_bit(CACHE_NEGATIVE, &rsci->h.flags);
14744         else {
14745                 int N, i;
14746                 struct gss_api_mech *gm;
14747                 struct xdr_netobj tmp_buf;
14748  
14749                 /* gid */
14750 -               if (get_int(&mesg, &rsci.cred.cr_gid))
14751 +               if (get_int(&mesg, &rsci->cred.cr_gid))
14752                         goto out;
14753  
14754                 /* number of additional gid's */
14755                 if (get_int(&mesg, &N))
14756                         goto out;
14757                 status = -ENOMEM;
14758 -               rsci.cred.cr_group_info = groups_alloc(N);
14759 -               if (rsci.cred.cr_group_info == NULL)
14760 +               rsci->cred.cr_group_info = groups_alloc(N);
14761 +               if (rsci->cred.cr_group_info == NULL)
14762                         goto out;
14763  
14764                 /* gid's */
14765 @@ -401,7 +458,7 @@ static int rsc_parse(struct cache_detail
14766                         gid_t gid;
14767                         if (get_int(&mesg, &gid))
14768                                 goto out;
14769 -                       GROUP_AT(rsci.cred.cr_group_info, i) = gid;
14770 +                       GROUP_AT(rsci->cred.cr_group_info, i) = gid;
14771                 }
14772  
14773                 /* mech name */
14774 @@ -422,19 +479,21 @@ static int rsc_parse(struct cache_detail
14775                 }
14776                 tmp_buf.len = len;
14777                 tmp_buf.data = buf;
14778 -               if (gss_import_sec_context(&tmp_buf, gm, &rsci.mechctx)) {
14779 +               if (gss_import_sec_context(&tmp_buf, gm, &rsci->mechctx)) {
14780                         gss_mech_put(gm);
14781                         goto out;
14782                 }
14783                 gss_mech_put(gm);
14784         }
14785 -       rsci.h.expiry_time = expiry;
14786 -       rscp = rsc_lookup(&rsci, 1);
14787 +       rsci->h.expiry_time = expiry;
14788 +       spin_lock_init(&rsci->seqdata.sd_lock);
14789 +       res = rsc_lookup(rsci, 1);
14790 +       rsc_put(&res->h, &rsc_cache);
14791 +       rsci = NULL;
14792         status = 0;
14793  out:
14794 -       rsc_free(&rsci);
14795 -       if (rscp)
14796 -               rsc_put(&rscp->h, &rsc_cache);
14797 +       if (rsci)
14798 +               rsc_put(&rsci->h, &rsc_cache);
14799         return status;
14800  }
14801  
14802 @@ -446,19 +505,14 @@ static struct cache_detail rsc_cache = {
14803         .cache_parse    = rsc_parse,
14804  };
14805  
14806 -static DefineSimpleCacheLookup(rsc, 0);
14807 -
14808  struct rsc *
14809  gss_svc_searchbyctx(struct xdr_netobj *handle)
14810  {
14811         struct rsc rsci;
14812         struct rsc *found;
14813  
14814 -       memset(&rsci, 0, sizeof(rsci));
14815 -       if (dup_to_netobj(&rsci.handle, handle->data, handle->len))
14816 -               return NULL;
14817 +       rsci.handle = *handle;
14818         found = rsc_lookup(&rsci, 0);
14819 -       rsc_free(&rsci);
14820         if (!found)
14821                 return NULL;
14822         if (cache_check(&rsc_cache, &found->h, NULL))
14823 @@ -643,7 +697,6 @@ svcauth_gss_register_pseudoflavor(u32 ps
14824         if (!new)
14825                 goto out;
14826         cache_init(&new->h.h);
14827 -       atomic_inc(&new->h.h.refcnt);
14828         new->h.name = kmalloc(strlen(name) + 1, GFP_KERNEL);
14829         if (!new->h.name)
14830                 goto out_free_dom;
14831 @@ -651,7 +704,6 @@ svcauth_gss_register_pseudoflavor(u32 ps
14832         new->h.flavour = RPC_AUTH_GSS;
14833         new->pseudoflavor = pseudoflavor;
14834         new->h.h.expiry_time = NEVER;
14835 -       new->h.h.flags = 0;
14836  
14837         test = auth_domain_lookup(&new->h, 1);
14838         if (test == &new->h) {
14839 @@ -723,6 +775,45 @@ out:
14840         return stat;
14841  }
14842  
14843 +static int
14844 +unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
14845 +{
14846 +       int stat = -EINVAL;
14847 +       int out_offset;
14848 +       u32 * lenp;
14849 +       u32 priv_len, maj_stat;
14850 +       int saved_len;
14851 +
14852 +       lenp = buf->head[0].iov_base;
14853 +       priv_len = ntohl(svc_getu32(&buf->head[0]));
14854 +       if (priv_len > buf->len) /* XXXJBF: wrong check */
14855 +               goto out;
14856 +       /* XXXJBF: bizarre hack: to handle revisits (and not decrypt
14857 +        * twice), the first time through we write an offset
14858 +        * telling us where to skip to find the already-decrypted data */
14859 +       if (rqstp->rq_deferred) {
14860 +               buf->head[0].iov_base += priv_len;
14861 +               buf->head[0].iov_len -= priv_len;
14862 +               return 0;
14863 +       }
14864 +       saved_len = buf->len; /* XXX HACK */
14865 +       buf->len = priv_len;
14866 +       maj_stat = gss_unwrap(ctx, GSS_C_QOP_DEFAULT, 0, buf, &out_offset);
14867 +       buf->len = saved_len;
14868 +       buf->head[0].iov_base += out_offset;
14869 +       buf->head[0].iov_len -= out_offset;
14870 +       BUG_ON(buf->head[0].iov_len <= 0);
14871 +       if (maj_stat != GSS_S_COMPLETE)
14872 +               goto out;
14873 +       if (ntohl(svc_getu32(&buf->head[0])) != seq)
14874 +               goto out;
14875 +       /* XXXJBF: see "bizarre hack", above. */
14876 +       *lenp = htonl(out_offset + 4);
14877 +       stat = 0;
14878 +out:
14879 +       return stat;
14880 +}
14881 +
14882  struct gss_svc_data {
14883         /* decoded gss client cred: */
14884         struct rpc_gss_wire_cred        clcred;
14885 @@ -750,7 +841,7 @@ svcauth_gss_accept(struct svc_rqst *rqst
14886         struct gss_svc_data *svcdata = rqstp->rq_auth_data;
14887         struct rpc_gss_wire_cred *gc;
14888         struct rsc      *rsci = NULL;
14889 -       struct rsi      *rsip, rsikey;
14890 +       struct rsi      *rsip, *rsikey = NULL;
14891         u32             *rpcstart;
14892         u32             *reject_stat = resv->iov_base + resv->iov_len;
14893         int             ret;
14894 @@ -843,30 +934,23 @@ svcauth_gss_accept(struct svc_rqst *rqst
14895                 *authp = rpc_autherr_badcred;
14896                 if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
14897                         goto auth_err;
14898 -               memset(&rsikey, 0, sizeof(rsikey));
14899 -               if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
14900 +               rsikey = kmalloc(sizeof(*rsikey), GFP_KERNEL);
14901 +               if (!rsikey)
14902 +                       goto drop;
14903 +               memset(rsikey, 0, sizeof(*rsikey));
14904 +               cache_init(&rsikey->h);
14905 +               if (dup_netobj(&rsikey->in_handle, &gc->gc_ctx))
14906                         goto drop;
14907                 *authp = rpc_autherr_badverf;
14908 -               if (svc_safe_getnetobj(argv, &tmpobj)) {
14909 -                       kfree(rsikey.in_handle.data);
14910 +               if (svc_safe_getnetobj(argv, &tmpobj))
14911                         goto auth_err;
14912 -               }
14913 -               if (dup_netobj(&rsikey.in_token, &tmpobj)) {
14914 -                       kfree(rsikey.in_handle.data);
14915 +               if (dup_netobj(&rsikey->in_token, &tmpobj))
14916                         goto drop;
14917 -               }
14918  
14919 -               rsip = rsi_lookup(&rsikey, 0);
14920 -               rsi_free(&rsikey);
14921 -               if (!rsip) {
14922 -                       goto drop;
14923 -               }
14924 -               switch(cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
14925 -               case -EAGAIN:
14926 +               rsip = gssd_upcall(rsikey, rqstp);
14927 +               if (!rsip)
14928                         goto drop;
14929 -               case -ENOENT:
14930 -                       goto drop;
14931 -               case 0:
14932 +               else {
14933                         rsci = gss_svc_searchbyctx(&rsip->out_handle);
14934                         if (!rsci) {
14935                                 goto drop;
14936 @@ -921,7 +1005,16 @@ svcauth_gss_accept(struct svc_rqst *rqst
14937                         svc_putu32(resv, 0);
14938                         break;
14939                 case RPC_GSS_SVC_PRIVACY:
14940 -                       /* currently unsupported */
14941 +                       if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
14942 +                                       gc->gc_seq, rsci->mechctx))
14943 +                               goto auth_err;
14944 +                       svcdata->rsci = rsci;
14945 +                       cache_get(&rsci->h);
14946 +                       /* placeholders for length and seq. number: */
14947 +                       svcdata->body_start = resv->iov_base + resv->iov_len;
14948 +                       svc_putu32(resv, 0);
14949 +                       svc_putu32(resv, 0);
14950 +                       break;
14951                 default:
14952                         goto auth_err;
14953                 }
14954 @@ -939,13 +1032,15 @@ complete:
14955  drop:
14956         ret = SVC_DROP;
14957  out:
14958 +       if (rsikey)
14959 +               rsi_put(&rsikey->h, &rsi_cache);
14960         if (rsci)
14961                 rsc_put(&rsci->h, &rsc_cache);
14962         return ret;
14963  }
14964  
14965 -static int
14966 -svcauth_gss_release(struct svc_rqst *rqstp)
14967 +static inline int
14968 +svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
14969  {
14970         struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
14971         struct rpc_gss_wire_cred *gc = &gsd->clcred;
14972 @@ -957,6 +1052,156 @@ svcauth_gss_release(struct svc_rqst *rqs
14973         int integ_offset, integ_len;
14974         int stat = -EINVAL;
14975  
14976 +       p = gsd->body_start;
14977 +       gsd->body_start = 0;
14978 +       /* move accept_stat to right place: */
14979 +       memcpy(p, p + 2, 4);
14980 +       /* Don't wrap in failure case: */
14981 +       /* Counting on not getting here if call was not even accepted! */
14982 +       if (*p != rpc_success) {
14983 +               resbuf->head[0].iov_len -= 2 * 4;
14984 +               goto out;
14985 +       }
14986 +       p++;
14987 +       integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
14988 +       integ_len = resbuf->len - integ_offset;
14989 +       BUG_ON(integ_len % 4);
14990 +       *p++ = htonl(integ_len);
14991 +       *p++ = htonl(gc->gc_seq);
14992 +       if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
14993 +                               integ_len))
14994 +               BUG();
14995 +       if (resbuf->page_len == 0
14996 +                       && resbuf->tail[0].iov_len + RPC_MAX_AUTH_SIZE
14997 +                       < PAGE_SIZE) {
14998 +               BUG_ON(resbuf->tail[0].iov_len);
14999 +               /* Use head for everything */
15000 +               resv = &resbuf->head[0];
15001 +       } else if (resbuf->tail[0].iov_base == NULL) {
15002 +               /* copied from nfsd4_encode_read */
15003 +               svc_take_page(rqstp);
15004 +               resbuf->tail[0].iov_base = page_address(rqstp
15005 +                               ->rq_respages[rqstp->rq_resused-1]);
15006 +               rqstp->rq_restailpage = rqstp->rq_resused-1;
15007 +               resbuf->tail[0].iov_len = 0;
15008 +               resv = &resbuf->tail[0];
15009 +       } else {
15010 +               resv = &resbuf->tail[0];
15011 +       }
15012 +       mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
15013 +       if (gss_get_mic(gsd->rsci->mechctx, 0, &integ_buf, &mic))
15014 +               goto out_err;
15015 +       svc_putu32(resv, htonl(mic.len));
15016 +       memset(mic.data + mic.len, 0,
15017 +                       round_up_to_quad(mic.len) - mic.len);
15018 +       resv->iov_len += XDR_QUADLEN(mic.len) << 2;
15019 +       /* not strictly required: */
15020 +       resbuf->len += XDR_QUADLEN(mic.len) << 2;
15021 +       BUG_ON(resv->iov_len > PAGE_SIZE);
15022 +out:
15023 +       stat = 0;
15024 +out_err:
15025 +       return stat;
15026 +}
15027 +
15028 +/* XXXJBF: Look for chances to share code with client */
15029 +/* XXXJBF: Do we need to preallocate these pages somehow?  E.g. see
15030 + * buffer size calculations in svcsock.c */
15031 +/* XXXJBF: how does reference counting on pages work? */
15032 +static struct page **
15033 +svc_alloc_enc_pages(struct xdr_buf *buf)
15034 +{
15035 +       struct page **ret;
15036 +       int last, i;
15037 +
15038 +       if (buf->page_len == 0)
15039 +               return NULL;
15040 +       BUG_ON(buf->page_base >> PAGE_CACHE_SHIFT);
15041 +       last = (buf->page_base + buf->page_len - 1) >> PAGE_CACHE_SHIFT;
15042 +       ret = kmalloc((last + 1) * sizeof(struct page *), GFP_KERNEL);
15043 +       if (!ret)
15044 +               goto out;
15045 +       for (i = 0; i<= last; i++) {
15046 +               ret[i] = alloc_page(GFP_KERNEL);
15047 +               if (ret[i] == NULL)
15048 +                       goto out_free;
15049 +       }
15050 +out:
15051 +       return ret;
15052 +out_free:
15053 +       for (i--; i >= 0; i--) {
15054 +               __free_page(ret[i]);
15055 +       }
15056 +       return NULL;
15057 +}
15058 +
15059 +static inline int
15060 +svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
15061 +{
15062 +       struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
15063 +       struct rpc_gss_wire_cred *gc = &gsd->clcred;
15064 +       struct xdr_buf *resbuf = &rqstp->rq_res;
15065 +       struct page **inpages;
15066 +       u32 *p;
15067 +       int offset, *len;
15068 +       int pad;
15069 +       int stat = -EINVAL;
15070 +
15071 +       p = gsd->body_start;
15072 +       gsd->body_start = 0;
15073 +       /* move accept_stat to right place: */
15074 +       memcpy(p, p + 2, 4);
15075 +       /* Don't wrap in failure case: */
15076 +       /* Counting on not getting here if call was not even accepted! */
15077 +       if (*p != rpc_success) {
15078 +               resbuf->head[0].iov_len -= 2 * 4;
15079 +               goto out;
15080 +       }
15081 +       p++;
15082 +       len = p++;
15083 +       offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;
15084 +       *p++ = htonl(gc->gc_seq);
15085 +       stat = -ENOMEM;
15086 +       inpages = resbuf->pages;
15087 +       /* XXXJBF: huge memory leaks here: allocated pages probably aren't
15088 +        * freed, and neither is memory used to hold page array. */
15089 +       resbuf->pages = svc_alloc_enc_pages(resbuf);
15090 +       if (resbuf->page_len && !resbuf->pages)
15091 +               goto out_err; /* XXX sleep and retry? Reserve ahead of time
15092 +                               and BUG_ON? */
15093 +       if (resbuf->tail[0].iov_len == 0 || resbuf->tail[0].iov_base == NULL) {
15094 +               /* copied from nfsd4_encode_read */
15095 +               {int i = svc_take_page(rqstp); BUG_ON(i); }
15096 +               resbuf->tail[0].iov_base = page_address(rqstp
15097 +                               ->rq_respages[rqstp->rq_resused-1]);
15098 +               rqstp->rq_restailpage = rqstp->rq_resused-1;
15099 +               resbuf->tail[0].iov_len = 0;
15100 +       }
15101 +       /* XXX: Will svc code attempt to free stuff in xdr_buf->pages?
15102 +        * Or can we leave it in any old state on error?? */
15103 +       stat = -EINVAL;
15104 +       if (gss_wrap(gsd->rsci->mechctx, GSS_C_QOP_DEFAULT, offset,
15105 +                               resbuf, inpages))
15106 +               goto out_err;
15107 +       *len = htonl(resbuf->len - offset);
15108 +       pad = 3 - ((resbuf->len - offset - 1)&3);
15109 +       p = (u32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len);
15110 +       memset(p, 0, pad);
15111 +       resbuf->tail[0].iov_len += pad;
15112 +out:
15113 +       return 0;
15114 +out_err:
15115 +       return stat;
15116 +}
15117 +
15118 +static int
15119 +svcauth_gss_release(struct svc_rqst *rqstp)
15120 +{
15121 +       struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
15122 +       struct rpc_gss_wire_cred *gc = &gsd->clcred;
15123 +       struct xdr_buf *resbuf = &rqstp->rq_res;
15124 +       int stat = -EINVAL;
15125 +
15126         if (gc->gc_proc != RPC_GSS_PROC_DATA)
15127                 goto out;
15128         /* Release can be called twice, but we only wrap once. */
15129 @@ -969,55 +1214,15 @@ svcauth_gss_release(struct svc_rqst *rqs
15130         case RPC_GSS_SVC_NONE:
15131                 break;
15132         case RPC_GSS_SVC_INTEGRITY:
15133 -               p = gsd->body_start;
15134 -               gsd->body_start = 0;
15135 -               /* move accept_stat to right place: */
15136 -               memcpy(p, p + 2, 4);
15137 -               /* don't wrap in failure case: */
15138 -               /* Note: counting on not getting here if call was not even
15139 -                * accepted! */
15140 -               if (*p != rpc_success) {
15141 -                       resbuf->head[0].iov_len -= 2 * 4;
15142 -                       goto out;
15143 -               }
15144 -               p++;
15145 -               integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
15146 -               integ_len = resbuf->len - integ_offset;
15147 -               BUG_ON(integ_len % 4);
15148 -               *p++ = htonl(integ_len);
15149 -               *p++ = htonl(gc->gc_seq);
15150 -               if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
15151 -                                       integ_len))
15152 -                       BUG();
15153 -               if (resbuf->page_len == 0
15154 -                       && resbuf->tail[0].iov_len + RPC_MAX_AUTH_SIZE
15155 -                               < PAGE_SIZE) {
15156 -                       BUG_ON(resbuf->tail[0].iov_len);
15157 -                       /* Use head for everything */
15158 -                       resv = &resbuf->head[0];
15159 -               } else if (resbuf->tail[0].iov_base == NULL) {
15160 -                       /* copied from nfsd4_encode_read */
15161 -                       svc_take_page(rqstp);
15162 -                       resbuf->tail[0].iov_base = page_address(rqstp
15163 -                                       ->rq_respages[rqstp->rq_resused-1]);
15164 -                       rqstp->rq_restailpage = rqstp->rq_resused-1;
15165 -                       resbuf->tail[0].iov_len = 0;
15166 -                       resv = &resbuf->tail[0];
15167 -               } else {
15168 -                       resv = &resbuf->tail[0];
15169 -               }
15170 -               mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
15171 -               if (gss_get_mic(gsd->rsci->mechctx, 0, &integ_buf, &mic))
15172 +               stat = svcauth_gss_wrap_resp_integ(rqstp);
15173 +               if (stat)
15174                         goto out_err;
15175 -               svc_putu32(resv, htonl(mic.len));
15176 -               memset(mic.data + mic.len, 0,
15177 -                               round_up_to_quad(mic.len) - mic.len);
15178 -               resv->iov_len += XDR_QUADLEN(mic.len) << 2;
15179 -               /* not strictly required: */
15180 -               resbuf->len += XDR_QUADLEN(mic.len) << 2;
15181 -               BUG_ON(resv->iov_len > PAGE_SIZE);
15182                 break;
15183         case RPC_GSS_SVC_PRIVACY:
15184 +               stat = svcauth_gss_wrap_resp_priv(rqstp);
15185 +               if (stat)
15186 +                       goto out_err;
15187 +               break;
15188         default:
15189                 goto out_err;
15190         }
15191 --- linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_wrap.c.lsec        2005-03-23 14:28:24.900264280 -0700
15192 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_wrap.c     2005-03-23 14:28:24.900264280 -0700
15193 @@ -0,0 +1,337 @@
15194 +#include <linux/types.h>
15195 +#include <linux/slab.h>
15196 +#include <linux/jiffies.h>
15197 +#include <linux/sunrpc/gss_krb5.h>
15198 +#include <linux/random.h>
15199 +#include <linux/pagemap.h>
15200 +#include <asm/scatterlist.h>
15201 +#include <linux/crypto.h>
15202 +
15203 +#ifdef RPC_DEBUG
15204 +# define RPCDBG_FACILITY       RPCDBG_AUTH
15205 +#endif
15206 +
15207 +static inline int
15208 +gss_krb5_padding(int blocksize, int length)
15209 +{
15210 +       /* Most of the code is block-size independent but currently we
15211 +        * use only 8: */
15212 +       BUG_ON(blocksize != 8);
15213 +       return 8 - (length & 7);
15214 +}
15215 +
15216 +static inline void
15217 +gss_krb5_add_padding(struct xdr_buf *buf, int offset, int blocksize)
15218 +{
15219 +       int padding = gss_krb5_padding(blocksize, buf->len - offset);
15220 +       char *p;
15221 +       struct iovec *iov;
15222 +
15223 +       if (buf->page_len || buf->tail[0].iov_len)
15224 +               iov = &buf->tail[0];
15225 +       else
15226 +               iov = &buf->head[0];
15227 +       p = iov->iov_base + iov->iov_len;
15228 +       iov->iov_len += padding;
15229 +       buf->len += padding;
15230 +       memset(p, padding, padding);
15231 +}
15232 +
15233 +static inline int
15234 +gss_krb5_remove_padding(struct xdr_buf *buf, int blocksize)
15235 +{
15236 +       u8 *ptr;
15237 +       u8 pad;
15238 +       int len = buf->len;
15239 +
15240 +       if (len <= buf->head[0].iov_len) {
15241 +               pad = *(u8 *)(buf->head[0].iov_base + len - 1);
15242 +               goto out;
15243 +       } else
15244 +               len -= buf->head[0].iov_len;
15245 +       if (len <= buf->page_len) {
15246 +               int last = (buf->page_base + len - 1)
15247 +                                       >>PAGE_CACHE_SHIFT;
15248 +               int offset = (buf->page_base + len - 1)
15249 +                                       & (PAGE_CACHE_SIZE - 1);
15250 +               ptr = kmap_atomic(buf->pages[last], KM_SKB_SUNRPC_DATA);
15251 +               pad = *(ptr + offset);
15252 +               kunmap_atomic(ptr, KM_SKB_SUNRPC_DATA);
15253 +               goto out;
15254 +       } else
15255 +               len -= buf->page_len;
15256 +       BUG_ON(len > buf->tail[0].iov_len);
15257 +       pad = *(u8 *)(buf->tail[0].iov_base + len - 1);
15258 +out:
15259 +       if (pad > blocksize)
15260 +               return -EINVAL;
15261 +       buf->len -= pad;
15262 +       return 0;
15263 +}
15264 +
15265 +static inline void
15266 +make_confounder(char *p, int blocksize)
15267 +{
15268 +       /* XXX?  Is this OK to do on every packet? */
15269 +       get_random_bytes(p, blocksize);
15270 +}
15271 +
15272 +/* Assumptions: the head and tail of inbuf are ours to play with.
15273 + * The pages, however, may be real pages in the page cache and we replace
15274 + * them with scratch pages from **pages before writing to them. */
15275 +/* XXX: obviously the above should be documentation of wrap interface,
15276 + * and shouldn't be in this kerberos-specific file. */
15277 +
15278 +/* XXX factor out common code with seal/unseal. */
15279 +
15280 +u32
15281 +gss_wrap_kerberos(struct gss_ctx *ctx, u32 qop, int offset,
15282 +               struct xdr_buf *buf, struct page **pages)
15283 +{
15284 +       struct krb5_ctx         *kctx = ctx->internal_ctx_id;
15285 +       s32                     checksum_type;
15286 +       struct xdr_netobj       md5cksum = {.len = 0, .data = NULL};
15287 +       int                     blocksize = 0, plainlen;
15288 +       unsigned char           *ptr, *krb5_hdr, *msg_start;
15289 +       s32                     now;
15290 +       int                     headlen;
15291 +       struct page             **tmp_pages;
15292 +       u32                     seq_send;
15293 +
15294 +       dprintk("RPC:     gss_wrap_kerberos\n");
15295 +
15296 +       now = get_seconds();
15297 +
15298 +       if (qop != 0)
15299 +               goto out_err;
15300 +
15301 +       switch (kctx->signalg) {
15302 +               case SGN_ALG_DES_MAC_MD5:
15303 +                       checksum_type = CKSUMTYPE_RSA_MD5;
15304 +                       break;
15305 +               default:
15306 +                       dprintk("RPC:      gss_krb5_seal: kctx->signalg %d not"
15307 +                               " supported\n", kctx->signalg);
15308 +                       goto out_err;
15309 +       }
15310 +       if (kctx->sealalg != SEAL_ALG_NONE && kctx->sealalg != SEAL_ALG_DES) {
15311 +               dprintk("RPC:      gss_krb5_seal: kctx->sealalg %d not supported\n",
15312 +                       kctx->sealalg);
15313 +               goto out_err;
15314 +       }
15315 +
15316 +       blocksize = crypto_tfm_alg_blocksize(kctx->enc);
15317 +       gss_krb5_add_padding(buf, offset, blocksize);
15318 +       BUG_ON((buf->len - offset) % blocksize);
15319 +       plainlen = blocksize + buf->len - offset;
15320 +
15321 +       headlen = g_token_size(&kctx->mech_used, 22 + plainlen) -
15322 +                                               (buf->len - offset);
15323 +
15324 +       ptr = buf->head[0].iov_base + offset;
15325 +       /* shift data to make room for header. */
15326 +       /* XXX Would be cleverer to encrypt while copying. */
15327 +       /* XXX bounds checking, slack, etc. */
15328 +       memmove(ptr + headlen, ptr, buf->head[0].iov_len - offset);
15329 +       buf->head[0].iov_len += headlen;
15330 +       buf->len += headlen;
15331 +       BUG_ON((buf->len - offset - headlen) % blocksize);
15332 +
15333 +       g_make_token_header(&kctx->mech_used, 22 + plainlen, &ptr);
15334 +
15335 +
15336 +       *ptr++ = (unsigned char) ((KG_TOK_WRAP_MSG>>8)&0xff);
15337 +       *ptr++ = (unsigned char) (KG_TOK_WRAP_MSG&0xff);
15338 +
15339 +       /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */
15340 +       krb5_hdr = ptr - 2;
15341 +       msg_start = krb5_hdr + 24;
15342 +       /* XXXJBF: */ BUG_ON(buf->head[0].iov_base + offset + headlen != msg_start + blocksize);
15343 +
15344 +       *(u16 *)(krb5_hdr + 2) = htons(kctx->signalg);
15345 +       memset(krb5_hdr + 4, 0xff, 4);
15346 +       *(u16 *)(krb5_hdr + 4) = htons(kctx->sealalg);
15347 +
15348 +       make_confounder(msg_start, blocksize);
15349 +
15350 +       /* XXXJBF: UGH!: */
15351 +       tmp_pages = buf->pages;
15352 +       buf->pages = pages;
15353 +       if (make_checksum(checksum_type, krb5_hdr, 8, buf,
15354 +                               offset + headlen - blocksize, &md5cksum))
15355 +               goto out_err;
15356 +       buf->pages = tmp_pages;
15357 +
15358 +       switch (kctx->signalg) {
15359 +       case SGN_ALG_DES_MAC_MD5:
15360 +               if (krb5_encrypt(kctx->seq, NULL, md5cksum.data,
15361 +                                 md5cksum.data, md5cksum.len))
15362 +                       goto out_err;
15363 +               memcpy(krb5_hdr + 16,
15364 +                      md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
15365 +                      KRB5_CKSUM_LENGTH);
15366 +
15367 +               dprintk("RPC:      make_seal_token: cksum data: \n");
15368 +               print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0);
15369 +               break;
15370 +       default:
15371 +               BUG();
15372 +       }
15373 +
15374 +       kfree(md5cksum.data);
15375 +
15376 +       spin_lock(&krb5_seq_lock);
15377 +       seq_send = kctx->seq_send++;
15378 +       spin_unlock(&krb5_seq_lock);
15379 +
15380 +       /* XXX would probably be more efficient to compute checksum
15381 +        * and encrypt at the same time: */
15382 +       if ((krb5_make_seq_num(kctx->seq, kctx->initiate ? 0 : 0xff,
15383 +                              seq_send, krb5_hdr + 16, krb5_hdr + 8)))
15384 +               goto out_err;
15385 +
15386 +       if (gss_encrypt_xdr_buf(kctx->enc, buf, offset + headlen - blocksize,
15387 +                                                                       pages))
15388 +               goto out_err;
15389 +
15390 +       return ((kctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE);
15391 +out_err:
15392 +       if (md5cksum.data) kfree(md5cksum.data);
15393 +       return GSS_S_FAILURE;
15394 +}
15395 +
15396 +u32
15397 +gss_unwrap_kerberos(struct gss_ctx *ctx, u32 *qop, int offset,
15398 +                       struct xdr_buf *buf, int *out_offset)
15399 +{
15400 +       struct krb5_ctx         *kctx = ctx->internal_ctx_id;
15401 +       int                     signalg;
15402 +       int                     sealalg;
15403 +       s32                     checksum_type;
15404 +       struct xdr_netobj       md5cksum = {.len = 0, .data = NULL};
15405 +       s32                     now;
15406 +       int                     direction;
15407 +       s32                     seqnum;
15408 +       unsigned char           *ptr;
15409 +       int                     bodysize;
15410 +       u32                     ret = GSS_S_DEFECTIVE_TOKEN;
15411 +       u8                      *data_start;
15412 +       int                     blocksize;
15413 +
15414 +       dprintk("RPC:      gss_unwrap_kerberos\n");
15415 +
15416 +       ptr = (u8 *)buf->head[0].iov_base + offset;
15417 +       if (g_verify_token_header(&kctx->mech_used, &bodysize, &ptr,
15418 +                                       buf->len - offset))
15419 +               goto out;
15420 +
15421 +       if ((*ptr++ != ((KG_TOK_WRAP_MSG>>8)&0xff)) ||
15422 +           (*ptr++ !=  (KG_TOK_WRAP_MSG    &0xff))   )
15423 +               goto out;
15424 +
15425 +       /* XXX sanity-check bodysize?? */
15426 +
15427 +       /* get the sign and seal algorithms */
15428 +
15429 +       signalg = ptr[0] + (ptr[1] << 8);
15430 +       sealalg = ptr[2] + (ptr[3] << 8);
15431 +
15432 +       /* Sanity checks */
15433 +
15434 +       if ((ptr[4] != 0xff) || (ptr[5] != 0xff))
15435 +               goto out;
15436 +
15437 +       if (sealalg == 0xffff)
15438 +               goto out;
15439 +
15440 +       /* in the current spec, there is only one valid seal algorithm per
15441 +          key type, so a simple comparison is ok */
15442 +
15443 +       if (sealalg != kctx->sealalg)
15444 +               goto out;
15445 +
15446 +       /* there are several mappings of seal algorithms to sign algorithms,
15447 +          but few enough that we can try them all. */
15448 +
15449 +       if ((kctx->sealalg == SEAL_ALG_NONE && signalg > 1) ||
15450 +           (kctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) ||
15451 +           (kctx->sealalg == SEAL_ALG_DES3KD &&
15452 +            signalg != SGN_ALG_HMAC_SHA1_DES3_KD))
15453 +               goto out;
15454 +
15455 +       if (gss_decrypt_xdr_buf(kctx->enc, buf,
15456 +                       ptr + 22 - (unsigned char *)buf->head[0].iov_base))
15457 +               goto out;
15458 +
15459 +       /* compute the checksum of the message */
15460 +
15461 +       /* initialize the the cksum */
15462 +       switch (signalg) {
15463 +       case SGN_ALG_DES_MAC_MD5:
15464 +               checksum_type = CKSUMTYPE_RSA_MD5;
15465 +               break;
15466 +       default:
15467 +               ret = GSS_S_DEFECTIVE_TOKEN;
15468 +               goto out;
15469 +       }
15470 +
15471 +       switch (signalg) {
15472 +       case SGN_ALG_DES_MAC_MD5:
15473 +               ret = make_checksum(checksum_type, ptr - 2, 8, buf,
15474 +                        ptr + 22 - (unsigned char *)buf->head[0].iov_base, &md5cksum);
15475 +               if (ret)
15476 +                       goto out;
15477 +
15478 +               ret = krb5_encrypt(kctx->seq, NULL, md5cksum.data,
15479 +                                  md5cksum.data, md5cksum.len);
15480 +               if (ret)
15481 +                       goto out;
15482 +
15483 +               if (memcmp(md5cksum.data + 8, ptr + 14, 8)) {
15484 +                       ret = GSS_S_BAD_SIG;
15485 +                       goto out;
15486 +               }
15487 +               break;
15488 +       default:
15489 +               ret = GSS_S_DEFECTIVE_TOKEN;
15490 +               goto out;
15491 +       }
15492 +
15493 +       /* it got through unscathed.  Make sure the context is unexpired */
15494 +
15495 +       if (qop)
15496 +               *qop = GSS_C_QOP_DEFAULT;
15497 +
15498 +       now = get_seconds();
15499 +
15500 +       ret = GSS_S_CONTEXT_EXPIRED;
15501 +       if (now > kctx->endtime)
15502 +               goto out;
15503 +
15504 +       /* do sequencing checks */
15505 +
15506 +       ret = GSS_S_BAD_SIG;
15507 +       if ((ret = krb5_get_seq_num(kctx->seq, ptr + 14, ptr + 6, &direction,
15508 +                                   &seqnum)))
15509 +               goto out;
15510 +
15511 +       if ((kctx->initiate && direction != 0xff) ||
15512 +           (!kctx->initiate && direction != 0))
15513 +               goto out;
15514 +
15515 +       /* Copy the data back to the right position.  XXX: Would probably be
15516 +        * better to copy and encrypt at the same time. */
15517 +
15518 +       blocksize = crypto_tfm_alg_blocksize(kctx->enc);
15519 +       data_start = ptr + 22 + blocksize;
15520 +       *out_offset = data_start - (u8 *)buf->head[0].iov_base;
15521 +
15522 +       ret = GSS_S_DEFECTIVE_TOKEN;
15523 +       if (gss_krb5_remove_padding(buf, blocksize))
15524 +               goto out;
15525 +
15526 +       ret = GSS_S_COMPLETE;
15527 +out:
15528 +       if (md5cksum.data) kfree(md5cksum.data);
15529 +       return ret;
15530 +}
15531 --- linux-2.6.7/net/sunrpc/auth_gss/gss_mech_switch.c.lsec      2004-06-15 23:19:37.000000000 -0600
15532 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_mech_switch.c   2005-03-23 14:28:24.782282216 -0700
15533 @@ -279,6 +279,29 @@ gss_verify_mic(struct gss_ctx              *context_
15534                                  qstate);
15535  }
15536  
15537 +u32
15538 +gss_wrap(struct gss_ctx        *ctx_id,
15539 +        u32            qop,
15540 +        int            offset,
15541 +        struct xdr_buf *buf,
15542 +        struct page    **inpages)
15543 +{
15544 +       return ctx_id->mech_type->gm_ops
15545 +               ->gss_wrap(ctx_id, qop, offset, buf, inpages);
15546 +}
15547 +
15548 +u32
15549 +gss_unwrap(struct gss_ctx      *ctx_id,
15550 +          u32                  *qop,
15551 +          int                  offset,
15552 +          struct xdr_buf       *buf,
15553 +          int                  *out_offset)
15554 +{
15555 +       return ctx_id->mech_type->gm_ops
15556 +               ->gss_unwrap(ctx_id, qop, offset, buf, out_offset);
15557 +}
15558 +
15559 +
15560  /* gss_delete_sec_context: free all resources associated with context_handle.
15561   * Note this differs from the RFC 2744-specified prototype in that we don't
15562   * bother returning an output token, since it would never be used anyway. */
15563 --- linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_mech.c.lsec        2004-06-15 23:19:42.000000000 -0600
15564 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_mech.c     2005-03-23 14:28:24.841273248 -0700
15565 @@ -182,6 +182,7 @@ gss_delete_sec_context_kerberos(void *in
15566         kfree(kctx);
15567  }
15568  
15569 +/* XXX the following wrappers have become pointless; kill them. */
15570  static u32
15571  gss_verify_mic_kerberos(struct gss_ctx         *ctx,
15572                         struct xdr_buf          *message,
15573 @@ -191,8 +192,7 @@ gss_verify_mic_kerberos(struct gss_ctx              
15574         int qop_state;
15575         struct krb5_ctx *kctx = ctx->internal_ctx_id;
15576  
15577 -       maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state,
15578 -                                  KG_TOK_MIC_MSG);
15579 +       maj_stat = krb5_read_token(kctx, mic_token, message, &qop_state);
15580         if (!maj_stat && qop_state)
15581             *qstate = qop_state;
15582  
15583 @@ -208,7 +208,7 @@ gss_get_mic_kerberos(struct gss_ctx *ctx
15584         u32 err = 0;
15585         struct krb5_ctx *kctx = ctx->internal_ctx_id;
15586  
15587 -       err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG);
15588 +       err = krb5_make_token(kctx, qop, message, mic_token);
15589  
15590         dprintk("RPC:      gss_get_mic_kerberos returning %d\n",err);
15591  
15592 @@ -219,6 +219,8 @@ static struct gss_api_ops gss_kerberos_o
15593         .gss_import_sec_context = gss_import_sec_context_kerberos,
15594         .gss_get_mic            = gss_get_mic_kerberos,
15595         .gss_verify_mic         = gss_verify_mic_kerberos,
15596 +       .gss_wrap               = gss_wrap_kerberos,
15597 +       .gss_unwrap             = gss_unwrap_kerberos,
15598         .gss_delete_sec_context = gss_delete_sec_context_kerberos,
15599  };
15600  
15601 @@ -233,6 +235,11 @@ static struct pf_desc gss_kerberos_pfs[]
15602                 .service = RPC_GSS_SVC_INTEGRITY,
15603                 .name = "krb5i",
15604         },
15605 +       [2] = {
15606 +               .pseudoflavor = RPC_AUTH_GSS_KRB5P,
15607 +               .service = RPC_GSS_SVC_PRIVACY,
15608 +               .name = "krb5p",
15609 +       },
15610  };
15611  
15612  static struct gss_api_mech gss_kerberos_mech = {
15613 --- linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_seal.c.lsec        2004-06-15 23:18:37.000000000 -0600
15614 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_krb5_seal.c     2005-03-23 14:28:24.898264584 -0700
15615 @@ -70,24 +70,17 @@
15616  # define RPCDBG_FACILITY        RPCDBG_AUTH
15617  #endif
15618  
15619 -static inline int
15620 -gss_krb5_padding(int blocksize, int length) {
15621 -       /* Most of the code is block-size independent but in practice we
15622 -        * use only 8: */
15623 -       BUG_ON(blocksize != 8);
15624 -       return 8 - (length & 7);
15625 -}
15626 +spinlock_t krb5_seq_lock = SPIN_LOCK_UNLOCKED;
15627  
15628  u32
15629  krb5_make_token(struct krb5_ctx *ctx, int qop_req,
15630 -                  struct xdr_buf *text, struct xdr_netobj *token,
15631 -                  int toktype)
15632 +                  struct xdr_buf *text, struct xdr_netobj *token)
15633  {
15634         s32                     checksum_type;
15635         struct xdr_netobj       md5cksum = {.len = 0, .data = NULL};
15636 -       int                     blocksize = 0, tmsglen;
15637         unsigned char           *ptr, *krb5_hdr, *msg_start;
15638         s32                     now;
15639 +       u32                     seq_send;
15640  
15641         dprintk("RPC:     gss_krb5_seal\n");
15642  
15643 @@ -111,21 +104,13 @@ krb5_make_token(struct krb5_ctx *ctx, in
15644                 goto out_err;
15645         }
15646  
15647 -       if (toktype == KG_TOK_WRAP_MSG) {
15648 -               blocksize = crypto_tfm_alg_blocksize(ctx->enc);
15649 -               tmsglen = blocksize + text->len
15650 -                       + gss_krb5_padding(blocksize, blocksize + text->len);
15651 -       } else {
15652 -               tmsglen = 0;
15653 -       }
15654 -
15655 -       token->len = g_token_size(&ctx->mech_used, 22 + tmsglen);
15656 +       token->len = g_token_size(&ctx->mech_used, 22);
15657  
15658         ptr = token->data;
15659 -       g_make_token_header(&ctx->mech_used, 22 + tmsglen, &ptr);
15660 +       g_make_token_header(&ctx->mech_used, 22, &ptr);
15661  
15662 -       *ptr++ = (unsigned char) ((toktype>>8)&0xff);
15663 -       *ptr++ = (unsigned char) (toktype&0xff);
15664 +       *ptr++ = (unsigned char) ((KG_TOK_MIC_MSG>>8)&0xff);
15665 +       *ptr++ = (unsigned char) (KG_TOK_MIC_MSG&0xff);
15666  
15667         /* ptr now at byte 2 of header described in rfc 1964, section 1.2.1: */
15668         krb5_hdr = ptr - 2;
15669 @@ -133,17 +118,9 @@ krb5_make_token(struct krb5_ctx *ctx, in
15670  
15671         *(u16 *)(krb5_hdr + 2) = htons(ctx->signalg);
15672         memset(krb5_hdr + 4, 0xff, 4);
15673 -       if (toktype == KG_TOK_WRAP_MSG)
15674 -               *(u16 *)(krb5_hdr + 4) = htons(ctx->sealalg);
15675  
15676 -       if (toktype == KG_TOK_WRAP_MSG) {
15677 -               /* XXX removing support for now */
15678 -               goto out_err;
15679 -       } else { /* Sign only.  */
15680 -               if (make_checksum(checksum_type, krb5_hdr, 8, text,
15681 -                                      &md5cksum))
15682 +       if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum))
15683                         goto out_err;
15684 -       }
15685  
15686         switch (ctx->signalg) {
15687         case SGN_ALG_DES_MAC_MD5:
15688 @@ -163,12 +140,14 @@ krb5_make_token(struct krb5_ctx *ctx, in
15689  
15690         kfree(md5cksum.data);
15691  
15692 +       spin_lock(&krb5_seq_lock);
15693 +       seq_send = ctx->seq_send++;
15694 +       spin_unlock(&krb5_seq_lock);
15695 +
15696         if ((krb5_make_seq_num(ctx->seq, ctx->initiate ? 0 : 0xff,
15697 -                              ctx->seq_send, krb5_hdr + 16, krb5_hdr + 8)))
15698 +                              seq_send, krb5_hdr + 16, krb5_hdr + 8)))
15699                 goto out_err;
15700  
15701 -       ctx->seq_send++;
15702 -
15703         return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE);
15704  out_err:
15705         if (md5cksum.data) kfree(md5cksum.data);
15706 --- linux-2.6.7/net/sunrpc/auth_gss/gss_spkm3_token.c.lsec      2005-03-23 14:28:24.240364600 -0700
15707 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_spkm3_token.c   2005-03-23 14:28:24.239364752 -0700
15708 @@ -0,0 +1,266 @@
15709 +/*
15710 + *  linux/net/sunrpc/gss_spkm3_token.c
15711 + *
15712 + *  Copyright (c) 2003 The Regents of the University of Michigan.
15713 + *  All rights reserved.
15714 + *
15715 + *  Andy Adamson <andros@umich.edu>
15716 + *
15717 + *  Redistribution and use in source and binary forms, with or without
15718 + *  modification, are permitted provided that the following conditions
15719 + *  are met:
15720 + *
15721 + *  1. Redistributions of source code must retain the above copyright
15722 + *     notice, this list of conditions and the following disclaimer.
15723 + *  2. Redistributions in binary form must reproduce the above copyright
15724 + *     notice, this list of conditions and the following disclaimer in the
15725 + *     documentation and/or other materials provided with the distribution.
15726 + *  3. Neither the name of the University nor the names of its
15727 + *     contributors may be used to endorse or promote products derived
15728 + *     from this software without specific prior written permission.
15729 + *
15730 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
15731 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
15732 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15733 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
15734 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
15735 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
15736 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
15737 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
15738 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
15739 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
15740 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15741 + *
15742 + */
15743 +
15744 +#include <linux/types.h>
15745 +#include <linux/slab.h>
15746 +#include <linux/jiffies.h>
15747 +#include <linux/sunrpc/gss_spkm3.h>
15748 +#include <linux/random.h>
15749 +#include <linux/crypto.h>
15750 +
15751 +#ifdef RPC_DEBUG
15752 +# define RPCDBG_FACILITY        RPCDBG_AUTH
15753 +#endif
15754 +
15755 +/*
15756 + * asn1_bitstring_len()
15757 + *
15758 + * calculate the asn1 bitstring length of the xdr_netobject
15759 + */
15760 +void
15761 +asn1_bitstring_len(struct xdr_netobj *in, int *enclen, int *zerobits)
15762 +{
15763 +       int i, zbit = 0,elen = in->len;
15764 +       char *ptr;
15765 +
15766 +       ptr = &in->data[in->len -1];
15767 +
15768 +       /* count trailing 0's */
15769 +       for(i = in->len; i > 0; i--) {
15770 +               if (*ptr == 0) {
15771 +                       ptr--;
15772 +                       elen--;
15773 +               } else
15774 +                       break;
15775 +       }
15776 +
15777 +       /* count number of 0 bits in final octet */
15778 +       ptr = &in->data[elen - 1];
15779 +       for(i = 0; i < 8; i++) {
15780 +               short mask = 0x01;
15781 +
15782 +               if (!((mask << i) & *ptr))
15783 +                       zbit++;
15784 +               else
15785 +                       break;
15786 +       }
15787 +       *enclen = elen;
15788 +       *zerobits = zbit;
15789 +}
15790 +
15791 +/*
15792 + * decode_asn1_bitstring()
15793 + *
15794 + * decode a bitstring into a buffer of the expected length.
15795 + * enclen = bit string length
15796 + * explen = expected length (define in rfc)
15797 + */
15798 +int
15799 +decode_asn1_bitstring(struct xdr_netobj *out, char *in, int enclen, int explen)
15800 +{
15801 +       if (!(out->data = kmalloc(explen,GFP_KERNEL)))
15802 +               return 0;
15803 +       out->len = explen;
15804 +       memset(out->data, 0, explen);
15805 +       memcpy(out->data, in, enclen);
15806 +       return 1;
15807 +}
15808 +
15809 +/*
15810 + * SPKMInnerContextToken choice SPKM_MIC asn1 token layout
15811 + *
15812 + * contextid is always 16 bytes plain data. max asn1 bitstring len = 17.
15813 + *
15814 + * tokenlen = pos[0] to end of token (max pos[45] with MD5 cksum)
15815 + *
15816 + * pos  value
15817 + * ----------
15818 + * [0] a4  SPKM-MIC tag
15819 + * [1] ??  innertoken length  (max 44)
15820 + *
15821 + *
15822 + * tok_hdr piece of checksum data starts here
15823 + *
15824 + * the maximum mic-header len = 9 + 17 = 26
15825 + *     mic-header
15826 + *     ----------
15827 + * [2] 30      SEQUENCE tag
15828 + * [3] ??      mic-header length: (max 23) = TokenID + ContextID
15829 + *
15830 + *             TokenID  - all fields constant and can be hardcoded
15831 + *             -------
15832 + * [4]   02    Type 2
15833 + * [5]   02    Length 2
15834 + * [6][7] 01 01        TokenID (SPKM_MIC_TOK)
15835 + *
15836 + *             ContextID  - encoded length not constant, calculated
15837 + *             ---------
15838 + * [8] 03      Type 3
15839 + * [9] ??      encoded length
15840 + * [10]        ??      ctxzbit
15841 + * [11]                contextid
15842 + *
15843 + * mic_header piece of checksum data ends here.
15844 + *
15845 + *     int-cksum - encoded length not constant, calculated
15846 + *     ---------
15847 + * [??]        03      Type 3
15848 + * [??]        ??      encoded length
15849 + * [??]        ??      md5zbit
15850 + * [??]                int-cksum (NID_md5 = 16)
15851 + *
15852 + * maximum SPKM-MIC innercontext token length =
15853 + *      10 + encoded contextid_size(17 max) + 2 + encoded
15854 + *       cksum_size (17 maxfor NID_md5) = 46
15855 + */
15856 +
15857 +/*
15858 + * spkm3_mic_header()
15859 + *
15860 + * Prepare the SPKM_MIC_TOK mic-header for check-sum calculation
15861 + * elen: 16 byte context id asn1 bitstring encoded length
15862 + */
15863 +void
15864 +spkm3_mic_header(unsigned char **hdrbuf, unsigned int *hdrlen, unsigned char *ctxdata, int elen, int zbit)
15865 +{
15866 +       char *hptr = *hdrbuf;
15867 +       char *top = *hdrbuf;
15868 +
15869 +       *(u8 *)hptr++ = 0x30;
15870 +       *(u8 *)hptr++ = elen + 7;  /* on the wire header length */
15871 +
15872 +       /* tokenid */
15873 +       *(u8 *)hptr++ = 0x02;
15874 +       *(u8 *)hptr++ = 0x02;
15875 +       *(u8 *)hptr++ = 0x01;
15876 +       *(u8 *)hptr++ = 0x01;
15877 +
15878 +       /* coniextid */
15879 +       *(u8 *)hptr++ = 0x03;
15880 +       *(u8 *)hptr++ = elen + 1; /* add 1 to include zbit */
15881 +       *(u8 *)hptr++ = zbit;
15882 +       memcpy(hptr, ctxdata, elen);
15883 +       hptr += elen;
15884 +       *hdrlen = hptr - top;
15885 +}
15886 +
15887 +/*
15888 + * spkm3_mic_innercontext_token()
15889 + *
15890 + * *tokp points to the beginning of the SPKM_MIC token  described
15891 + * in rfc 2025, section 3.2.1:
15892 + *
15893 + */
15894 +void
15895 +spkm3_make_mic_token(unsigned char **tokp, int toklen, struct xdr_netobj *mic_hdr, struct xdr_netobj *md5cksum, int md5elen, int md5zbit)
15896 +{
15897 +       unsigned char *ict = *tokp;
15898 +
15899 +       *(u8 *)ict++ = 0xa4;
15900 +       *(u8 *)ict++ = toklen - 2;
15901 +       memcpy(ict, mic_hdr->data, mic_hdr->len);
15902 +       ict += mic_hdr->len;
15903 +
15904 +       *(u8 *)ict++ = 0x03;
15905 +       *(u8 *)ict++ = md5elen + 1; /* add 1 to include zbit */
15906 +       *(u8 *)ict++ = md5zbit;
15907 +       memcpy(ict, md5cksum->data, md5elen);
15908 +}
15909 +
15910 +u32
15911 +spkm3_verify_mic_token(unsigned char **tokp, int *mic_hdrlen, unsigned char **cksum)
15912 +{
15913 +       struct xdr_netobj       spkm3_ctx_id = {.len =0, .data = NULL};
15914 +       unsigned char           *ptr = *tokp;
15915 +       int                     ctxelen;
15916 +       u32                     ret = GSS_S_DEFECTIVE_TOKEN;
15917 +
15918 +       /* spkm3 innercontext token preamble */
15919 +       if ((ptr[0] != 0xa4) || (ptr[2] != 0x30)) {
15920 +               dprintk("RPC: BAD SPKM ictoken preamble\n");
15921 +               goto out;
15922 +       }
15923 +
15924 +       *mic_hdrlen = ptr[3];
15925 +
15926 +       /* token type */
15927 +       if ((ptr[4] != 0x02) || (ptr[5] != 0x02)) {
15928 +               dprintk("RPC: BAD asn1 SPKM3 token type\n");
15929 +               goto out;
15930 +       }
15931 +
15932 +       /* only support SPKM_MIC_TOK */
15933 +       if((ptr[6] != 0x01) || (ptr[7] != 0x01)) {
15934 +               dprintk("RPC: ERROR unsupported SPKM3 token \n");
15935 +               goto out;
15936 +       }
15937 +
15938 +       /* contextid */
15939 +       if (ptr[8] != 0x03) {
15940 +               dprintk("RPC: BAD SPKM3 asn1 context-id type\n");
15941 +               goto out;
15942 +       }
15943 +
15944 +       ctxelen = ptr[9];
15945 +       if (ctxelen > 17) {  /* length includes asn1 zbit octet */
15946 +               dprintk("RPC: BAD SPKM3 contextid len %d\n", ctxelen);
15947 +               goto out;
15948 +       }
15949 +
15950 +       /* ignore ptr[10] */
15951 +
15952 +       if(!decode_asn1_bitstring(&spkm3_ctx_id, &ptr[11], ctxelen - 1, 16))
15953 +               goto out;
15954 +
15955 +       /*
15956 +       * in the current implementation: the optional int-alg is not present
15957 +       * so the default int-alg (md5) is used the optional snd-seq field is
15958 +       * also not present
15959 +       */
15960 +
15961 +       if (*mic_hdrlen != 6 + ctxelen) {
15962 +               dprintk("RPC: BAD SPKM_ MIC_TOK header len %d: we only support default int-alg (should be absent) and do not support snd-seq\n", *mic_hdrlen);
15963 +               goto out;
15964 +       }
15965 +       /* checksum */
15966 +        *cksum = (&ptr[10] + ctxelen); /* ctxelen includes ptr[10] */
15967 +
15968 +       ret = GSS_S_COMPLETE;
15969 +out:
15970 +       if (spkm3_ctx_id.data)
15971 +               kfree(spkm3_ctx_id.data);
15972 +       return ret;
15973 +}
15974 +
15975 --- linux-2.6.7/net/sunrpc/auth_gss/gss_generic_token.c.lsec    2004-06-15 23:19:10.000000000 -0600
15976 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_generic_token.c 2005-03-23 14:28:23.707445616 -0700
15977 @@ -179,7 +179,7 @@ EXPORT_SYMBOL(g_make_token_header);
15978   */
15979  u32
15980  g_verify_token_header(struct xdr_netobj *mech, int *body_size,
15981 -                     unsigned char **buf_in, int tok_type, int toksize)
15982 +                     unsigned char **buf_in, int toksize)
15983  {
15984         unsigned char *buf = *buf_in;
15985         int seqsize;
15986 --- linux-2.6.7/net/sunrpc/auth_gss/gss_spkm3_unseal.c.lsec     2005-03-23 14:28:24.240364600 -0700
15987 +++ linux-2.6.7/net/sunrpc/auth_gss/gss_spkm3_unseal.c  2005-03-23 14:28:24.240364600 -0700
15988 @@ -0,0 +1,128 @@
15989 +/*
15990 + *  linux/net/sunrpc/gss_spkm3_unseal.c
15991 + *
15992 + *  Copyright (c) 2003 The Regents of the University of Michigan.
15993 + *  All rights reserved.
15994 + *
15995 + *  Andy Adamson <andros@umich.edu>
15996 + *
15997 + *  Redistribution and use in source and binary forms, with or without
15998 + *  modification, are permitted provided that the following conditions
15999 + *  are met:
16000 + *
16001 + *  1. Redistributions of source code must retain the above copyright
16002 + *     notice, this list of conditions and the following disclaimer.
16003 + *  2. Redistributions in binary form must reproduce the above copyright
16004 + *     notice, this list of conditions and the following disclaimer in the
16005 + *     documentation and/or other materials provided with the distribution.
16006 + *  3. Neither the name of the University nor the names of its
16007 + *     contributors may be used to endorse or promote products derived
16008 + *     from this software without specific prior written permission.
16009 + *
16010 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
16011 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
16012 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16013 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
16014 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
16015 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
16016 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
16017 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
16018 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
16019 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
16020 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16021 + *
16022 + */
16023 +
16024 +#include <linux/types.h>
16025 +#include <linux/slab.h>
16026 +#include <linux/jiffies.h>
16027 +#include <linux/sunrpc/gss_spkm3.h>
16028 +#include <linux/crypto.h>
16029 +
16030 +#ifdef RPC_DEBUG
16031 +# define RPCDBG_FACILITY        RPCDBG_AUTH
16032 +#endif
16033 +
16034 +/*
16035 + * spkm3_read_token()
16036 + *
16037 + * only SPKM_MIC_TOK with md5 intg-alg is supported
16038 + */
16039 +u32
16040 +spkm3_read_token(struct spkm3_ctx *ctx,
16041 +               struct xdr_netobj *read_token,    /* checksum */
16042 +               struct xdr_buf *message_buffer, /* signbuf */
16043 +               int *qop_state, int toktype)
16044 +{
16045 +       s32                     code;
16046 +       struct xdr_netobj       wire_cksum = {.len =0, .data = NULL};
16047 +       struct xdr_netobj       md5cksum = {.len = 0, .data = NULL};
16048 +       unsigned char           *ptr = (unsigned char *)read_token->data;
16049 +       unsigned char           *cksum;
16050 +       int                     bodysize, md5elen;
16051 +       int                     mic_hdrlen;
16052 +       u32                     ret = GSS_S_DEFECTIVE_TOKEN;
16053 +
16054 +       dprintk("RPC: spkm3_read_token read_token->len %d\n", read_token->len);
16055 +
16056 +       if (g_verify_token_header((struct xdr_netobj *) &ctx->mech_used,
16057 +                                       &bodysize, &ptr, read_token->len))
16058 +               goto out;
16059 +
16060 +       /* decode the token */
16061 +
16062 +       if (toktype == SPKM_MIC_TOK) {
16063 +
16064 +               if ((ret = spkm3_verify_mic_token(&ptr, &mic_hdrlen, &cksum)))
16065 +                       goto out;
16066 +
16067 +               if (*cksum++ != 0x03) {
16068 +                       dprintk("RPC: spkm3_read_token BAD checksum type\n");
16069 +                       goto out;
16070 +               }
16071 +               md5elen = *cksum++;
16072 +               cksum++;        /* move past the zbit */
16073 +
16074 +               if(!decode_asn1_bitstring(&wire_cksum, cksum, md5elen - 1, 16))
16075 +                       goto out;
16076 +
16077 +               /* HARD CODED FOR MD5 */
16078 +
16079 +               /* compute the checksum of the message.
16080 +               *  ptr + 2 = start of header piece of checksum
16081 +               *  mic_hdrlen + 2 = length of header piece of checksum
16082 +               */
16083 +               ret = GSS_S_DEFECTIVE_TOKEN;
16084 +               code = make_checksum(CKSUMTYPE_RSA_MD5, ptr + 2,
16085 +                                       mic_hdrlen + 2,
16086 +                                       message_buffer, &md5cksum);
16087 +
16088 +               if (code)
16089 +                       goto out;
16090 +
16091 +               dprintk("RPC: spkm3_read_token: digest wire_cksum.len %d:\n",
16092 +                       wire_cksum.len);
16093 +               dprintk("          md5cksum.data\n");
16094 +               print_hexl((u32 *) md5cksum.data, 16, 0);
16095 +               dprintk("          cksum.data:\n");
16096 +               print_hexl((u32 *) wire_cksum.data, wire_cksum.len, 0);
16097 +
16098 +               ret = GSS_S_BAD_SIG;
16099 +               code = memcmp(md5cksum.data, wire_cksum.data, wire_cksum.len);
16100 +               if (code)
16101 +                       goto out;
16102 +
16103 +       } else {
16104 +               dprintk("RPC: BAD or UNSUPPORTED SPKM3 token type: %d\n",toktype);
16105 +               goto out;
16106 +       }
16107 +
16108 +       /* XXX: need to add expiration and sequencing */
16109 +       ret = GSS_S_COMPLETE;
16110 +out:
16111 +       if (md5cksum.data)
16112 +               kfree(md5cksum.data);
16113 +       if (wire_cksum.data)
16114 +               kfree(wire_cksum.data);
16115 +       return ret;
16116 +}
16117 --- linux-2.6.7/net/sunrpc/auth_gss/Makefile.lsec       2004-06-15 23:19:22.000000000 -0600
16118 +++ linux-2.6.7/net/sunrpc/auth_gss/Makefile    2005-03-23 14:28:24.294356392 -0700
16119 @@ -10,5 +10,9 @@ auth_rpcgss-objs := auth_gss.o gss_gener
16120  obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
16121  
16122  rpcsec_gss_krb5-objs := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
16123 -       gss_krb5_seqnum.o
16124 +       gss_krb5_seqnum.o gss_krb5_wrap.o
16125  
16126 +obj-$(CONFIG_RPCSEC_GSS_SPKM3) += rpcsec_gss_spkm3.o
16127 +
16128 +rpcsec_gss_spkm3-objs := gss_spkm3_mech.o gss_spkm3_seal.o gss_spkm3_unseal.o \
16129 +       gss_spkm3_token.o
16130 --- linux-2.6.7/net/sunrpc/cache.c.lsec 2004-06-15 23:19:36.000000000 -0600
16131 +++ linux-2.6.7/net/sunrpc/cache.c      2005-03-23 14:28:24.406339368 -0700
16132 @@ -38,7 +38,7 @@ void cache_init(struct cache_head *h)
16133         time_t now = get_seconds();
16134         h->next = NULL;
16135         h->flags = 0;
16136 -       atomic_set(&h->refcnt, 0);
16137 +       atomic_set(&h->refcnt, 1);
16138         h->expiry_time = now + CACHE_NEW_EXPIRY;
16139         h->last_refresh = now;
16140  }
16141 --- linux-2.6.7/net/sunrpc/svc.c.lsec   2004-06-15 23:20:03.000000000 -0600
16142 +++ linux-2.6.7/net/sunrpc/svc.c        2005-03-23 14:28:23.652453976 -0700
16143 @@ -263,6 +263,7 @@ svc_process(struct svc_serv *serv, struc
16144         u32                     *statp;
16145         u32                     dir, prog, vers, proc,
16146                                 auth_stat, rpc_stat;
16147 +       int                     auth_res;
16148  
16149         rpc_stat = rpc_success;
16150  
16151 @@ -304,12 +305,17 @@ svc_process(struct svc_serv *serv, struc
16152         rqstp->rq_vers = vers = ntohl(svc_getu32(argv));        /* version number */
16153         rqstp->rq_proc = proc = ntohl(svc_getu32(argv));        /* procedure number */
16154  
16155 +       progp = serv->sv_program;
16156         /*
16157          * Decode auth data, and add verifier to reply buffer.
16158          * We do this before anything else in order to get a decent
16159          * auth verifier.
16160          */
16161 -       switch (svc_authenticate(rqstp, &auth_stat)) {
16162 +       if (progp->pg_authenticate != NULL)
16163 +               auth_res = progp->pg_authenticate(rqstp, &auth_stat);
16164 +       else
16165 +               auth_res = svc_authenticate(rqstp, &auth_stat);
16166 +       switch (auth_res) {
16167         case SVC_OK:
16168                 break;
16169         case SVC_GARBAGE:
16170 @@ -326,7 +332,6 @@ svc_process(struct svc_serv *serv, struc
16171                 goto sendit;
16172         }
16173                 
16174 -       progp = serv->sv_program;
16175         if (prog != progp->pg_prog)
16176                 goto err_bad_prog;
16177  
16178 --- linux-2.6.7/net/sunrpc/svcauth.c.lsec       2004-06-15 23:19:44.000000000 -0600
16179 +++ linux-2.6.7/net/sunrpc/svcauth.c    2005-03-23 14:28:24.407339216 -0700
16180 @@ -156,25 +156,47 @@ static inline int auth_domain_match(stru
16181  {
16182         return strcmp(tmp->name, item->name) == 0;
16183  }
16184 -DefineCacheLookup(struct auth_domain,
16185 -                 h,
16186 -                 auth_domain_lookup,
16187 -                 (struct auth_domain *item, int set),
16188 -                 /* no setup */,
16189 -                 &auth_domain_cache,
16190 -                 auth_domain_hash(item),
16191 -                 auth_domain_match(tmp, item),
16192 -                 kfree(new); if(!set) {
16193 -                       if (new)
16194 -                               write_unlock(&auth_domain_cache.hash_lock);
16195 -                       else
16196 -                               read_unlock(&auth_domain_cache.hash_lock);
16197 -                       return NULL;
16198 -                 }
16199 -                 new=item; atomic_inc(&new->h.refcnt),
16200 -                 /* no update */,
16201 -                 0 /* no inplace updates */
16202 -                 )
16203 +
16204 +struct auth_domain *
16205 +auth_domain_lookup(struct auth_domain *item, int set)
16206 +{
16207 +       struct auth_domain *tmp = NULL;
16208 +       struct cache_head **hp, **head;
16209 +       head = &auth_domain_cache.hash_table[auth_domain_hash(item)];
16210 +
16211 +       if (set)
16212 +               write_lock(&auth_domain_cache.hash_lock);
16213 +       else
16214 +               read_lock(&auth_domain_cache.hash_lock);
16215 +       for (hp=head; *hp != NULL; hp = &tmp->h.next) {
16216 +               tmp = container_of(*hp, struct auth_domain, h);
16217 +               if (!auth_domain_match(tmp, item))
16218 +                       continue;
16219 +               cache_get(&tmp->h);
16220 +               if (!set)
16221 +                       goto out_noset;
16222 +               *hp = tmp->h.next;
16223 +               tmp->h.next = NULL;
16224 +               clear_bit(CACHE_HASHED, &tmp->h.flags);
16225 +               auth_domain_drop(&tmp->h, &auth_domain_cache);
16226 +               goto out_set;
16227 +       }
16228 +       /* Didn't find anything */
16229 +       if (!set)
16230 +               goto out_noset;
16231 +       auth_domain_cache.entries++;
16232 +out_set:
16233 +       set_bit(CACHE_HASHED, &item->h.flags);
16234 +       item->h.next = *head;
16235 +       *head = &item->h;
16236 +       write_unlock(&auth_domain_cache.hash_lock);
16237 +       cache_fresh(&auth_domain_cache, &item->h, item->h.expiry_time);
16238 +       cache_get(&item->h);
16239 +       return item;
16240 +out_noset:
16241 +       read_unlock(&auth_domain_cache.hash_lock);
16242 +       return tmp;
16243 +}
16244  
16245  struct auth_domain *auth_domain_find(char *name)
16246  {