Whamcloud - gitweb
- mds->lmv->mdc propagate lower timeout down to import
[fs/lustre-release.git] / lustre / kernel_patches / patches / linux-2.6.3-CITI_NFS4_ALL.patch
1
2 The complete series of citi nfsv4 patches in a single patch
3
4
5  Makefile                                |    2 
6  fs/Kconfig                              |   49 
7  fs/Makefile                             |    1 
8  fs/inode.c                              |    2 
9  fs/nfs/dir.c                            |  181 ++
10  fs/nfs/direct.c                         |    3 
11  fs/nfs/file.c                           |   23 
12  fs/nfs/inode.c                          |  586 +++++----
13  fs/nfs/nfs3proc.c                       |   43 
14  fs/nfs/nfs4proc.c                       |  988 +++++++---------
15  fs/nfs/nfs4xdr.c                        | 1931 ++++++++++++++++++++++++--------
16  fs/nfs/pagelist.c                       |    5 
17  fs/nfs/proc.c                           |   51 
18  fs/nfs/read.c                           |    2 
19  fs/nfs/unlink.c                         |    3 
20  fs/nfs/write.c                          |  207 +--
21  fs/nfs4acl/Makefile                     |    3 
22  fs/nfs4acl/acl.c                        |  921 +++++++++++++++
23  fs/nfs4acl/acl_syms.c                   |   51 
24  fs/nfsd/Makefile                        |    2 
25  fs/nfsd/nfs3xdr.c                       |    2 
26  fs/nfsd/nfs4idmap.c                     |  569 +++++++++
27  fs/nfsd/nfs4proc.c                      |  229 ++-
28  fs/nfsd/nfs4state.c                     |  440 +++++--
29  fs/nfsd/nfs4xdr.c                       |  495 +++++---
30  fs/nfsd/nfsctl.c                        |    7 
31  fs/nfsd/nfsproc.c                       |    1 
32  fs/nfsd/nfsxdr.c                        |    2 
33  fs/nfsd/stats.c                         |   67 -
34  fs/nfsd/vfs.c                           |  218 +++
35  include/linux/fs.h                      |    2 
36  include/linux/nfs.h                     |    2 
37  include/linux/nfs4.h                    |   80 +
38  include/linux/nfs4_acl.h                |   68 +
39  include/linux/nfs_fs.h                  |  138 +-
40  include/linux/nfs_page.h                |    2 
41  include/linux/nfs_xdr.h                 |  256 +---
42  include/linux/nfsd/nfsd.h               |   16 
43  include/linux/nfsd/nfsfh.h              |    8 
44  include/linux/nfsd/state.h              |   21 
45  include/linux/nfsd/xdr4.h               |   37 
46  include/linux/nfsd_idmap.h              |   54 
47  include/linux/sunrpc/auth_gss.h         |    2 
48  include/linux/sunrpc/cache.h            |   13 
49  include/linux/sunrpc/gss_api.h          |    3 
50  include/linux/sunrpc/stats.h            |   20 
51  include/linux/sunrpc/svc.h              |    1 
52  include/linux/sunrpc/svcauth.h          |    5 
53  include/linux/sunrpc/svcauth_gss.h      |   35 
54  include/linux/sunrpc/xdr.h              |    3 
55  include/linux/sunrpc/xprt.h             |   15 
56  net/sunrpc/Makefile                     |    2 
57  net/sunrpc/auth_gss/Makefile            |    2 
58  net/sunrpc/auth_gss/auth_gss.c          |  119 +
59  net/sunrpc/auth_gss/gss_krb5_crypto.c   |   18 
60  net/sunrpc/auth_gss/gss_krb5_mech.c     |   14 
61  net/sunrpc/auth_gss/gss_krb5_seal.c     |    9 
62  net/sunrpc/auth_gss/gss_krb5_seqnum.c   |    2 
63  net/sunrpc/auth_gss/gss_mech_switch.c   |   32 
64  net/sunrpc/auth_gss/gss_pseudoflavors.c |   21 
65  net/sunrpc/auth_gss/sunrpcgss_syms.c    |    2 
66  net/sunrpc/auth_gss/svcauth_gss.c       | 1018 ++++++++++++++++
67  net/sunrpc/cache.c                      |   13 
68  net/sunrpc/stats.c                      |  106 -
69  net/sunrpc/sunrpc_syms.c                |    5 
70  net/sunrpc/svc.c                        |    4 
71  net/sunrpc/svcauth.c                    |    5 
72  net/sunrpc/svcauth_unix.c               |   13 
73  net/sunrpc/xdr.c                        |    4 
74  net/sunrpc/xprt.c                       |  210 +--
75  include/linux/sunrpc/name_lookup.h      |   38 
76  71 files changed, 7194 insertions(+), 2308 deletions(-)
77
78 diff -puN Makefile~CITI_NFS4_ALL Makefile
79 --- linux-2.6.3/Makefile~CITI_NFS4_ALL  2004-02-19 16:47:02.000000000 -0500
80 +++ linux-2.6.3-bfields/Makefile        2004-02-19 16:47:16.000000000 -0500
81 @@ -1,7 +1,7 @@
82  VERSION = 2
83  PATCHLEVEL = 6
84  SUBLEVEL = 3
85 -EXTRAVERSION =
86 +EXTRAVERSION = -CITI_NFS4_ALL-1
87  NAME=Feisty Dunnart
88  
89  # *DOCUMENTATION*
90 diff -puN fs/inode.c~CITI_NFS4_ALL fs/inode.c
91 --- linux-2.6.3/fs/inode.c~CITI_NFS4_ALL        2004-02-19 16:47:03.000000000 -0500
92 +++ linux-2.6.3-bfields/fs/inode.c      2004-02-19 16:47:03.000000000 -0500
93 @@ -1178,6 +1178,8 @@ void inode_update_time(struct inode *ino
94         struct timespec now;
95         int sync_it = 0;
96  
97 +       if (IS_NOCMTIME(inode))
98 +               return;
99         if (IS_RDONLY(inode))
100                 return;
101  
102 diff -puN fs/Kconfig~CITI_NFS4_ALL fs/Kconfig
103 --- linux-2.6.3/fs/Kconfig~CITI_NFS4_ALL        2004-02-19 16:47:03.000000000 -0500
104 +++ linux-2.6.3-bfields/fs/Kconfig      2004-02-19 16:47:07.000000000 -0500
105 @@ -288,7 +288,7 @@ config FS_POSIX_ACL
106  #      Never use this symbol for ifdefs.
107  #
108         bool
109 -       depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL
110 +       depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL || NFS_V4_ACL
111         default y
112  
113  config XFS_FS
114 @@ -1314,21 +1314,25 @@ config NFS_V3
115           Say Y here if you want your NFS client to be able to speak the newer
116           version 3 of the NFS protocol.
117  
118 -         If unsure, say N.
119 +         If unsure, say Y.
120  
121  config NFS_V4
122         bool "Provide NFSv4 client support (EXPERIMENTAL)"
123         depends on NFS_FS && EXPERIMENTAL
124 +       select RPCSEC_GSS_KRB5
125         help
126           Say Y here if you want your NFS client to be able to speak the newer
127 -         version 4 of the NFS protocol.  This feature is experimental, and
128 -         should only be used if you are interested in helping to test NFSv4.
129 +         version 4 of the NFS protocol.
130 +
131 +         Note: Requires auxiliary userspace daemons which may be found on
132 +               http://www.citi.umich.edu/projects/nfsv4/
133  
134           If unsure, say N.
135  
136  config NFS_DIRECTIO
137         bool "Allow direct I/O on NFS files (EXPERIMENTAL)"
138         depends on NFS_FS && EXPERIMENTAL
139 +       select NFS_V4_ACL
140         help
141           This option enables applications to perform uncached I/O on files
142           in NFS file systems using the O_DIRECT open() flag.  When O_DIRECT
143 @@ -1388,6 +1392,7 @@ config NFSD_V3
144  config NFSD_V4
145         bool "Provide NFSv4 server support (EXPERIMENTAL)"
146         depends on NFSD_V3 && EXPERIMENTAL
147 +       select NFS_V4_ACL
148         help
149           If you would like to include the NFSv4 server as well as the NFSv2
150           and NFSv3 servers, say Y here.  This feature is experimental, and
151 @@ -1423,6 +1428,12 @@ config LOCKD_V4
152         depends on NFSD_V3 || NFS_V3
153         default y
154  
155 +config NFS_V4_ACL
156 +       bool "Provide NFSv4 ACL support"
157 +       depends on NFSD_V4 || NFS_V4
158 +       help
159 +         This allows you to use POSIX ACLs with NFSv4.
160 +
161  config EXPORTFS
162         tristate
163         default NFSD
164 @@ -1431,28 +1442,24 @@ config SUNRPC
165         tristate
166  
167  config SUNRPC_GSS
168 -       tristate "Provide RPCSEC_GSS authentication (EXPERIMENTAL)"
169 +       tristate
170 +
171 +config RPCSEC_GSS_KRB5
172 +       tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
173         depends on SUNRPC && EXPERIMENTAL
174 -       default SUNRPC if NFS_V4=y
175 +       select SUNRPC_GSS
176 +       select CRYPTO
177 +       select CRYPTO_MD5
178 +       select CRYPTO_DES
179         help
180 -         Provides cryptographic authentication for NFS rpc requests.  To
181 -         make this useful, you must also select at least one rpcsec_gss
182 -         mechanism.
183 -         Note: You should always select this option if you wish to use
184 +         Provides for secure RPC calls by means of a gss-api
185 +         mechanism based on Kerberos V5. This is required for
186           NFSv4.
187  
188 -config RPCSEC_GSS_KRB5
189 -       tristate "Kerberos V mechanism for RPCSEC_GSS (EXPERIMENTAL)"
190 -       depends on SUNRPC_GSS && CRYPTO_DES && CRYPTO_MD5
191 -       default SUNRPC_GSS if NFS_V4=y
192 -       help
193 -         Provides a gss-api mechanism based on Kerberos V5 (this is
194 -         mandatory for RFC3010-compliant NFSv4 implementations).
195 -         Requires a userspace daemon;
196 -               see http://www.citi.umich.edu/projects/nfsv4/.
197 +         Note: Requires an auxiliary userspace daemon which may be found on
198 +               http://www.citi.umich.edu/projects/nfsv4/
199  
200 -         Note: If you select this option, please ensure that you also
201 -         enable the MD5 and DES crypto ciphers.
202 +         If unsure, say N.
203  
204  config SMB_FS
205         tristate "SMB file system support (to mount Windows shares etc.)"
206 diff -puN fs/nfs/dir.c~CITI_NFS4_ALL fs/nfs/dir.c
207 --- linux-2.6.3/fs/nfs/dir.c~CITI_NFS4_ALL      2004-02-19 16:47:03.000000000 -0500
208 +++ linux-2.6.3-bfields/fs/nfs/dir.c    2004-02-19 16:47:07.000000000 -0500
209 @@ -88,6 +88,10 @@ struct inode_operations nfs4_dir_inode_o
210         .permission     = nfs_permission,
211         .getattr        = nfs_getattr,
212         .setattr        = nfs_setattr,
213 +#ifdef CONFIG_NFS_V4_ACL
214 +       .getxattr       = nfs_getxattr,
215 +       .setxattr       = nfs_setxattr,
216 +#endif /* CONFIG_NFS_V4_ACL */
217  };
218  
219  #endif /* CONFIG_NFS_V4 */
220 @@ -139,11 +143,13 @@ int nfs_readdir_filler(nfs_readdir_descr
221         struct file     *file = desc->file;
222         struct inode    *inode = file->f_dentry->d_inode;
223         struct rpc_cred *cred = nfs_file_cred(file);
224 +       unsigned long   timestamp;
225         int             error;
226  
227         dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
228  
229   again:
230 +       timestamp = jiffies;
231         error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page,
232                                           NFS_SERVER(inode)->dtsize, desc->plus);
233         if (error < 0) {
234 @@ -157,18 +163,21 @@ int nfs_readdir_filler(nfs_readdir_descr
235                 goto error;
236         }
237         SetPageUptodate(page);
238 +       NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
239         /* Ensure consistent page alignment of the data.
240          * Note: assumes we have exclusive access to this mapping either
241          *       throught inode->i_sem or some other mechanism.
242          */
243 -       if (page->index == 0)
244 +       if (page->index == 0) {
245                 invalidate_inode_pages(inode->i_mapping);
246 +               NFS_I(inode)->readdir_timestamp = timestamp;
247 +       }
248         unlock_page(page);
249         return 0;
250   error:
251         SetPageError(page);
252         unlock_page(page);
253 -       invalidate_inode_pages(inode->i_mapping);
254 +       nfs_zap_caches(inode);
255         desc->error = error;
256         return -EIO;
257  }
258 @@ -381,6 +390,7 @@ int uncached_readdir(nfs_readdir_descrip
259                                                 page,
260                                                 NFS_SERVER(inode)->dtsize,
261                                                 desc->plus);
262 +       NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
263         desc->page = page;
264         desc->ptr = kmap(page);         /* matching kunmap in nfs_do_filldir */
265         if (desc->error >= 0) {
266 @@ -459,7 +469,15 @@ static int nfs_readdir(struct file *filp
267                         }
268                         res = 0;
269                         break;
270 -               } else if (res < 0)
271 +               }
272 +               if (res == -ETOOSMALL && desc->plus) {
273 +                       NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
274 +                       nfs_zap_caches(inode);
275 +                       desc->plus = 0;
276 +                       desc->entry->eof = 0;
277 +                       continue;
278 +               }
279 +               if (res < 0)
280                         break;
281  
282                 res = nfs_do_filldir(desc, dirent, filldir);
283 @@ -481,14 +499,19 @@ static int nfs_readdir(struct file *filp
284   * In the case it has, we assume that the dentries are untrustworthy
285   * and may need to be looked up again.
286   */
287 -static inline
288 -int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
289 +static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
290  {
291         if (IS_ROOT(dentry))
292                 return 1;
293 -       if (nfs_revalidate_inode(NFS_SERVER(dir), dir))
294 +       if ((NFS_FLAGS(dir) & NFS_INO_INVALID_ATTR) != 0
295 +                       || nfs_attribute_timeout(dir))
296                 return 0;
297 -       return time_after(dentry->d_time, NFS_MTIME_UPDATE(dir));
298 +       return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata);
299 +}
300 +
301 +static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
302 +{
303 +       dentry->d_fsdata = (void *)verf;
304  }
305  
306  /*
307 @@ -528,9 +551,7 @@ int nfs_neg_need_reval(struct inode *dir
308         /* Don't revalidate a negative dentry if we're creating a new file */
309         if ((ndflags & LOOKUP_CREATE) && !(ndflags & LOOKUP_CONTINUE))
310                 return 0;
311 -       if (!nfs_check_verifier(dir, dentry))
312 -               return 1;
313 -       return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir));
314 +       return !nfs_check_verifier(dir, dentry);
315  }
316  
317  /*
318 @@ -552,6 +573,7 @@ static int nfs_lookup_revalidate(struct 
319         int error;
320         struct nfs_fh fhandle;
321         struct nfs_fattr fattr;
322 +       unsigned long verifier;
323         int isopen = 0;
324  
325         parent = dget_parent(dentry);
326 @@ -574,6 +596,9 @@ static int nfs_lookup_revalidate(struct 
327                 goto out_bad;
328         }
329  
330 +       /* Revalidate parent directory attribute cache */
331 +       nfs_revalidate_inode(NFS_SERVER(dir), dir);
332 +
333         /* Force a full look up iff the parent directory has changed */
334         if (nfs_check_verifier(dir, dentry)) {
335                 if (nfs_lookup_verify_inode(inode, isopen))
336 @@ -581,6 +606,12 @@ static int nfs_lookup_revalidate(struct 
337                 goto out_valid;
338         }
339  
340 +       /*
341 +        * Note: we're not holding inode->i_sem and so may be racing with
342 +        * operations that change the directory. We therefore save the
343 +        * change attribute *before* we do the RPC call.
344 +        */
345 +       verifier = nfs_save_change_attribute(dir);
346         error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);
347         if (!error) {
348                 if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0)
349 @@ -603,6 +634,7 @@ static int nfs_lookup_revalidate(struct 
350  
351   out_valid_renew:
352         nfs_renew_times(dentry);
353 +       nfs_set_verifier(dentry, verifier);
354   out_valid:
355         unlock_kernel();
356         dput(parent);
357 @@ -638,6 +670,11 @@ static int nfs_dentry_delete(struct dent
358                 /* Unhash it, so that ->d_iput() would be called */
359                 return 1;
360         }
361 +       if (!(dentry->d_sb->s_flags & MS_ACTIVE)) {
362 +               /* Unhash it, so that ancestors of killed async unlink
363 +                * files will be cleaned up during umount */
364 +               return 1;
365 +       }
366         return 0;
367  
368  }
369 @@ -693,6 +730,8 @@ static struct dentry *nfs_lookup(struct 
370         dentry->d_op = NFS_PROTO(dir)->dentry_ops;
371  
372         lock_kernel();
373 +       /* Revalidate parent directory attribute cache */
374 +       nfs_revalidate_inode(NFS_SERVER(dir), dir);
375  
376         /* If we're doing an exclusive create, optimize away the lookup */
377         if (nfs_is_exclusive_create(dir, nd))
378 @@ -715,6 +754,7 @@ no_entry:
379         error = 0;
380         d_add(dentry, inode);
381         nfs_renew_times(dentry);
382 +       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
383  out_unlock:
384         unlock_kernel();
385  out:
386 @@ -768,7 +808,15 @@ static struct dentry *nfs_atomic_lookup(
387  
388         /* Open the file on the server */
389         lock_kernel();
390 -       inode = nfs4_atomic_open(dir, dentry, nd);
391 +       /* Revalidate parent directory attribute cache */
392 +       nfs_revalidate_inode(NFS_SERVER(dir), dir);
393 +
394 +       if (nd->intent.open.flags & O_CREAT) {
395 +               nfs_begin_data_update(dir);
396 +               inode = nfs4_atomic_open(dir, dentry, nd);
397 +               nfs_end_data_update(dir);
398 +       } else
399 +               inode = nfs4_atomic_open(dir, dentry, nd);
400         unlock_kernel();
401         if (IS_ERR(inode)) {
402                 error = PTR_ERR(inode);
403 @@ -790,6 +838,7 @@ static struct dentry *nfs_atomic_lookup(
404  no_entry:
405         d_add(dentry, inode);
406         nfs_renew_times(dentry);
407 +       nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
408  out:
409         BUG_ON(error > 0);
410         return ERR_PTR(error);
411 @@ -801,13 +850,16 @@ static int nfs_open_revalidate(struct de
412  {
413         struct dentry *parent = NULL;
414         struct inode *inode = dentry->d_inode;
415 +       struct inode *dir;
416 +       unsigned long verifier;
417         int openflags, ret = 0;
418  
419         /* NFS only supports OPEN for regular files */
420         if (inode && !S_ISREG(inode->i_mode))
421                 goto no_open;
422         parent = dget_parent(dentry);
423 -       if (!is_atomic_open(parent->d_inode, nd))
424 +       dir = parent->d_inode;
425 +       if (!is_atomic_open(dir, nd))
426                 goto no_open;
427         openflags = nd->intent.open.flags;
428         if (openflags & O_CREAT) {
429 @@ -821,8 +873,16 @@ static int nfs_open_revalidate(struct de
430         /* We can't create new files, or truncate existing ones here */
431         openflags &= ~(O_CREAT|O_TRUNC);
432  
433 +       /*
434 +        * Note: we're not holding inode->i_sem and so may be racing with
435 +        * operations that change the directory. We therefore save the
436 +        * change attribute *before* we do the RPC call.
437 +        */
438         lock_kernel();
439 -       ret = nfs4_open_revalidate(parent->d_inode, dentry, openflags);
440 +       verifier = nfs_save_change_attribute(dir);
441 +       ret = nfs4_open_revalidate(dir, dentry, openflags);
442 +       if (!ret)
443 +               nfs_set_verifier(dentry, verifier);
444         unlock_kernel();
445  out:
446         dput(parent);
447 @@ -869,15 +929,20 @@ int nfs_cached_lookup(struct inode *dir,
448         struct nfs_server *server;
449         struct nfs_entry entry;
450         struct page *page;
451 -       unsigned long timestamp = NFS_MTIME_UPDATE(dir);
452 +       unsigned long timestamp;
453         int res;
454  
455         if (!NFS_USE_READDIRPLUS(dir))
456                 return -ENOENT;
457         server = NFS_SERVER(dir);
458 -       if (server->flags & NFS_MOUNT_NOAC)
459 +       /* Don't use readdirplus unless the cache is stable */
460 +       if ((server->flags & NFS_MOUNT_NOAC) != 0
461 +                       || nfs_caches_unstable(dir)
462 +                       || nfs_attribute_timeout(dir))
463                 return -ENOENT;
464 -       nfs_revalidate_inode(server, dir);
465 +       if ((NFS_FLAGS(dir) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) != 0)
466 +               return -ENOENT;
467 +       timestamp = NFS_I(dir)->readdir_timestamp;
468  
469         entry.fh = fh;
470         entry.fattr = fattr;
471 @@ -931,6 +996,7 @@ static int nfs_instantiate(struct dentry
472         if (inode) {
473                 d_instantiate(dentry, inode);
474                 nfs_renew_times(dentry);
475 +               nfs_set_verifier(dentry, nfs_save_change_attribute(dentry->d_parent->d_inode));
476                 error = 0;
477         }
478         return error;
479 @@ -969,11 +1035,13 @@ static int nfs_create(struct inode *dir,
480          * does not pass the create flags.
481          */
482         lock_kernel();
483 -       nfs_zap_caches(dir);
484 +       nfs_begin_data_update(dir);
485         inode = NFS_PROTO(dir)->create(dir, &dentry->d_name, &attr, open_flags);
486 +       nfs_end_data_update(dir);
487         if (!IS_ERR(inode)) {
488                 d_instantiate(dentry, inode);
489                 nfs_renew_times(dentry);
490 +               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
491                 error = 0;
492         } else {
493                 error = PTR_ERR(inode);
494 @@ -1004,9 +1072,10 @@ nfs_mknod(struct inode *dir, struct dent
495         attr.ia_valid = ATTR_MODE;
496  
497         lock_kernel();
498 -       nfs_zap_caches(dir);
499 +       nfs_begin_data_update(dir);
500         error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev,
501                                         &fhandle, &fattr);
502 +       nfs_end_data_update(dir);
503         if (!error)
504                 error = nfs_instantiate(dentry, &fhandle, &fattr);
505         else
506 @@ -1041,9 +1110,10 @@ static int nfs_mkdir(struct inode *dir, 
507          */
508         d_drop(dentry);
509  #endif
510 -       nfs_zap_caches(dir);
511 +       nfs_begin_data_update(dir);
512         error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
513                                         &fattr);
514 +       nfs_end_data_update(dir);
515         if (!error)
516                 error = nfs_instantiate(dentry, &fhandle, &fattr);
517         else
518 @@ -1060,10 +1130,12 @@ static int nfs_rmdir(struct inode *dir, 
519                 dir->i_ino, dentry->d_name.name);
520  
521         lock_kernel();
522 -       nfs_zap_caches(dir);
523 +       nfs_begin_data_update(dir);
524         error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
525 -       if (!error)
526 +       /* Ensure the VFS deletes this inode */
527 +       if (error == 0 && dentry->d_inode != NULL)
528                 dentry->d_inode->i_nlink = 0;
529 +       nfs_end_data_update(dir);
530         unlock_kernel();
531  
532         return error;
533 @@ -1119,12 +1191,21 @@ dentry->d_parent->d_name.name, dentry->d
534                         goto out;
535         } while(sdentry->d_inode != NULL); /* need negative lookup */
536  
537 -       nfs_zap_caches(dir);
538         qsilly.name = silly;
539         qsilly.len  = strlen(silly);
540 -       error = NFS_PROTO(dir)->rename(dir, &dentry->d_name, dir, &qsilly);
541 +       nfs_begin_data_update(dir);
542 +       if (dentry->d_inode) {
543 +               nfs_begin_data_update(dentry->d_inode);
544 +               error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
545 +                               dir, &qsilly);
546 +               nfs_end_data_update(dentry->d_inode);
547 +       } else
548 +               error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
549 +                               dir, &qsilly);
550 +       nfs_end_data_update(dir);
551         if (!error) {
552                 nfs_renew_times(dentry);
553 +               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
554                 d_move(dentry, sdentry);
555                 error = nfs_async_unlink(dentry);
556                 /* If we return 0 we don't unlink */
557 @@ -1156,14 +1237,17 @@ static int nfs_safe_remove(struct dentry
558                 goto out;
559         }
560  
561 -       nfs_zap_caches(dir);
562 -       if (inode)
563 -               NFS_CACHEINV(inode);
564 -       error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
565 -       if (error < 0)
566 -               goto out;
567 -       if (inode)
568 -               inode->i_nlink--;
569 +       nfs_begin_data_update(dir);
570 +       if (inode != NULL) {
571 +               nfs_begin_data_update(inode);
572 +               error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
573 +               /* The VFS may want to delete this inode */
574 +               if (error == 0)
575 +                       inode->i_nlink--;
576 +               nfs_end_data_update(inode);
577 +       } else
578 +               error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
579 +       nfs_end_data_update(dir);
580  out:
581         return error;
582  }
583 @@ -1198,9 +1282,10 @@ static int nfs_unlink(struct inode *dir,
584         spin_unlock(&dentry->d_lock);
585         spin_unlock(&dcache_lock);
586         error = nfs_safe_remove(dentry);
587 -       if (!error)
588 +       if (!error) {
589                 nfs_renew_times(dentry);
590 -       else if (need_rehash)
591 +               nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
592 +       } else if (need_rehash)
593                 d_rehash(dentry);
594         unlock_kernel();
595         return error;
596 @@ -1247,9 +1332,10 @@ dentry->d_parent->d_name.name, dentry->d
597         qsymname.len  = strlen(symname);
598  
599         lock_kernel();
600 -       nfs_zap_caches(dir);
601 +       nfs_begin_data_update(dir);
602         error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
603                                           &attr, &sym_fh, &sym_attr);
604 +       nfs_end_data_update(dir);
605         if (!error) {
606                 error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
607         } else {
608 @@ -1281,9 +1367,12 @@ nfs_link(struct dentry *old_dentry, stru
609          */
610         lock_kernel();
611         d_drop(dentry);
612 -       nfs_zap_caches(dir);
613 -       NFS_CACHEINV(inode);
614 +
615 +       nfs_begin_data_update(dir);
616 +       nfs_begin_data_update(inode);
617         error = NFS_PROTO(dir)->link(inode, dir, &dentry->d_name);
618 +       nfs_end_data_update(inode);
619 +       nfs_end_data_update(dir);
620         unlock_kernel();
621         return error;
622  }
623 @@ -1388,16 +1477,23 @@ go_ahead:
624         if (new_inode)
625                 d_delete(new_dentry);
626  
627 -       nfs_zap_caches(new_dir);
628 -       nfs_zap_caches(old_dir);
629 +       nfs_begin_data_update(old_dir);
630 +       nfs_begin_data_update(new_dir);
631 +       nfs_begin_data_update(old_inode);
632         error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
633                                            new_dir, &new_dentry->d_name);
634 +       nfs_end_data_update(old_inode);
635 +       nfs_end_data_update(new_dir);
636 +       nfs_end_data_update(old_dir);
637  out:
638         if (rehash)
639                 d_rehash(rehash);
640 -       if (!error && !S_ISDIR(old_inode->i_mode))
641 -               d_move(old_dentry, new_dentry);
642 -       nfs_renew_times(new_dentry);
643 +       if (!error) {
644 +               if (!S_ISDIR(old_inode->i_mode))
645 +                       d_move(old_dentry, new_dentry);
646 +               nfs_renew_times(new_dentry);
647 +               nfs_set_verifier(new_dentry, nfs_save_change_attribute(new_dir));
648 +       }
649  
650         /* new dentry created? */
651         if (dentry)
652 @@ -1451,7 +1547,8 @@ nfs_permission(struct inode *inode, int 
653  
654         cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
655         if (cache->cred == cred
656 -           && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))) {
657 +           && time_before(jiffies, cache->jiffies + NFS_ATTRTIMEO(inode))
658 +           && !(NFS_FLAGS(inode) & NFS_INO_INVALID_ATTR)) {
659                 if (!(res = cache->err)) {
660                         /* Is the mask a subset of an accepted mask? */
661                         if ((cache->mask & mask) == mask)
662 diff -puN fs/nfs/direct.c~CITI_NFS4_ALL fs/nfs/direct.c
663 --- linux-2.6.3/fs/nfs/direct.c~CITI_NFS4_ALL   2004-02-19 16:47:03.000000000 -0500
664 +++ linux-2.6.3-bfields/fs/nfs/direct.c 2004-02-19 16:47:03.000000000 -0500
665 @@ -269,6 +269,7 @@ nfs_direct_write_seg(struct inode *inode
666         if (IS_SYNC(inode) || NFS_PROTO(inode)->version == 2 || count <= wsize)
667                 wdata.args.stable = NFS_FILE_SYNC;
668  
669 +       nfs_begin_data_update(inode);
670  retry:
671         need_commit = 0;
672         tot_bytes = 0;
673 @@ -334,6 +335,8 @@ retry:
674                                                 VERF_SIZE) != 0)
675                         goto sync_retry;
676         }
677 +       nfs_end_data_update(inode);
678 +       NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA;
679  
680         return tot_bytes;
681  
682 diff -puN fs/nfs/file.c~CITI_NFS4_ALL fs/nfs/file.c
683 --- linux-2.6.3/fs/nfs/file.c~CITI_NFS4_ALL     2004-02-19 16:47:03.000000000 -0500
684 +++ linux-2.6.3-bfields/fs/nfs/file.c   2004-02-19 16:47:07.000000000 -0500
685 @@ -63,6 +63,20 @@ struct inode_operations nfs_file_inode_o
686         .setattr        = nfs_setattr,
687  };
688  
689 +#ifdef CONFIG_NFS_V4
690 +
691 +struct inode_operations nfs4_file_inode_operations = {
692 +       .permission     = nfs_permission,
693 +       .getattr        = nfs_getattr,
694 +       .setattr        = nfs_setattr,
695 +#ifdef CONFIG_NFS_V4_ACL
696 +       .getxattr       = nfs_getxattr,
697 +       .setxattr       = nfs_setxattr,
698 +#endif /* CONFIG_NFS_V4_ACL */
699 +};
700 +
701 +#endif /* CONFIG_NFS_V4 */
702 +
703  /* Hack for future NFS swap support */
704  #ifndef IS_SWAPFILE
705  # define IS_SWAPFILE(inode)    (0)
706 @@ -104,11 +118,16 @@ nfs_file_flush(struct file *file)
707  
708         dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
709  
710 +       if ((file->f_mode & FMODE_WRITE) == 0)
711 +               return 0;
712         lock_kernel();
713 -       status = nfs_wb_file(inode, file);
714 +       /* Ensure that data+attribute caches are up to date after close() */
715 +       status = nfs_wb_all(inode);
716         if (!status) {
717                 status = file->f_error;
718                 file->f_error = 0;
719 +               if (!status)
720 +                       __nfs_revalidate_inode(NFS_SERVER(inode), inode);
721         }
722         unlock_kernel();
723         return status;
724 @@ -179,7 +198,7 @@ nfs_fsync(struct file *file, struct dent
725         dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
726  
727         lock_kernel();
728 -       status = nfs_wb_file(inode, file);
729 +       status = nfs_wb_all(inode);
730         if (!status) {
731                 status = file->f_error;
732                 file->f_error = 0;
733 diff -puN fs/nfs/inode.c~CITI_NFS4_ALL fs/nfs/inode.c
734 --- linux-2.6.3/fs/nfs/inode.c~CITI_NFS4_ALL    2004-02-19 16:47:03.000000000 -0500
735 +++ linux-2.6.3-bfields/fs/nfs/inode.c  2004-02-19 16:47:15.000000000 -0500
736 @@ -53,8 +53,8 @@
737   */
738  #define NFS_MAX_READAHEAD      RPC_MAXREQS
739  
740 -void nfs_zap_caches(struct inode *);
741  static void nfs_invalidate_inode(struct inode *);
742 +static int nfs_update_inode(struct inode *, struct nfs_fattr *, unsigned long);
743  
744  static struct inode *nfs_alloc_inode(struct super_block *sb);
745  static void nfs_destroy_inode(struct inode *);
746 @@ -118,7 +118,7 @@ nfs_write_inode(struct inode *inode, int
747  {
748         int flags = sync ? FLUSH_WAIT : 0;
749  
750 -       nfs_commit_file(inode, NULL, 0, 0, flags);
751 +       nfs_commit_inode(inode, 0, 0, flags);
752  }
753  
754  static void
755 @@ -136,21 +136,24 @@ nfs_delete_inode(struct inode * inode)
756         clear_inode(inode);
757  }
758  
759 -/*
760 - * For the moment, the only task for the NFS clear_inode method is to
761 - * release the mmap credential
762 - */
763  static void
764  nfs_clear_inode(struct inode *inode)
765  {
766         struct nfs_inode *nfsi = NFS_I(inode);
767         struct rpc_cred *cred = nfsi->mm_cred;
768  
769 +#ifdef CONFIG_NFS_V4_ACL
770 +       if (nfsi->acl != NFS4_ACL_NOT_CACHED)
771 +               posix_acl_release(nfsi->acl);
772 +       if (nfsi->default_acl != NFS4_ACL_NOT_CACHED)
773 +               posix_acl_release(nfsi->default_acl);
774 +#endif /* CONFIG_NFS_V4_ACL */
775         if (cred)
776                 put_rpccred(cred);
777         cred = nfsi->cache_access.cred;
778         if (cred)
779                 put_rpccred(cred);
780 +       BUG_ON(atomic_read(&nfsi->data_updates) != 0);
781  }
782  
783  void
784 @@ -230,50 +233,23 @@ nfs_block_size(unsigned long bsize, unsi
785  /*
786   * Obtain the root inode of the file system.
787   */
788 -static int
789 -nfs_get_root(struct inode **rooti, rpc_authflavor_t authflavor, struct super_block *sb, struct nfs_fh *rootfh)
790 +static struct inode *
791 +nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
792  {
793         struct nfs_server       *server = NFS_SB(sb);
794 -       struct nfs_fattr        fattr = { };
795 +       struct inode *rooti;
796         int                     error;
797  
798 -       error = server->rpc_ops->getroot(server, rootfh, &fattr);
799 -       if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
800 -               /*
801 -                * Some authentication types (gss/krb5, most notably)
802 -                * are such that root won't be able to present a
803 -                * credential for GETATTR (ie, getroot()).
804 -                *
805 -                * We still want the mount to succeed.
806 -                * 
807 -                * So we fake the attr values and mark the inode as such.
808 -                * On the first succesful traversal, we fix everything.
809 -                * The auth type test isn't quite correct, but whatever.
810 -                */
811 -               dfprintk(VFS, "NFS: faking root inode\n");
812 -
813 -               fattr.fileid = 1;
814 -               fattr.nlink = 2;        /* minimum for a dir */
815 -               fattr.type = NFDIR;
816 -               fattr.mode = S_IFDIR|S_IRUGO|S_IXUGO;
817 -               fattr.size = 4096;
818 -               fattr.du.nfs3.used = 1;
819 -               fattr.valid = NFS_ATTR_FATTR|NFS_ATTR_FATTR_V3;
820 -       } else if (error < 0) {
821 +       error = server->rpc_ops->getroot(server, rootfh, fsinfo);
822 +       if (error < 0) {
823                 printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
824 -               *rooti = NULL;  /* superfluous ... but safe */
825 -               return error;
826 +               return ERR_PTR(error);
827         }
828  
829 -       *rooti = nfs_fhget(sb, rootfh, &fattr);
830 -       if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
831 -               if (*rooti) {
832 -                       NFS_FLAGS(*rooti) |= NFS_INO_FAKE_ROOT;
833 -                       NFS_CACHEINV((*rooti));
834 -                       error = 0;
835 -               }
836 -       }
837 -       return error;
838 +       rooti = nfs_fhget(sb, rootfh, fsinfo->fattr);
839 +       if (!rooti)
840 +               return ERR_PTR(-ENOMEM);
841 +       return rooti;
842  }
843  
844  /*
845 @@ -283,7 +259,7 @@ static int
846  nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
847  {
848         struct nfs_server       *server;
849 -       struct inode            *root_inode = NULL;
850 +       struct inode            *root_inode;
851         struct nfs_fattr        fattr;
852         struct nfs_fsinfo       fsinfo = {
853                                         .fattr = &fattr,
854 @@ -299,8 +275,9 @@ nfs_sb_init(struct super_block *sb, rpc_
855  
856         sb->s_magic      = NFS_SUPER_MAGIC;
857  
858 +       root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
859         /* Did getting the root inode fail? */
860 -       if (nfs_get_root(&root_inode, authflavor, sb, &server->fh) < 0)
861 +       if (IS_ERR(root_inode))
862                 goto out_no_root;
863         sb->s_root = d_alloc_root(root_inode);
864         if (!sb->s_root)
865 @@ -309,10 +286,6 @@ nfs_sb_init(struct super_block *sb, rpc_
866         sb->s_root->d_op = server->rpc_ops->dentry_ops;
867  
868         /* Get some general file system info */
869 -        if (server->rpc_ops->fsinfo(server, &server->fh, &fsinfo) < 0) {
870 -               printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
871 -               goto out_no_root;
872 -        }
873         if (server->namelen == 0 &&
874             server->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
875                 server->namelen = pathinfo.max_namelen;
876 @@ -368,13 +341,11 @@ nfs_sb_init(struct super_block *sb, rpc_
877         rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
878         return 0;
879         /* Yargs. It didn't work out. */
880 -out_free_all:
881 -       if (root_inode)
882 -               iput(root_inode);
883 -       return -EINVAL;
884  out_no_root:
885         printk("nfs_read_super: get root inode failed\n");
886 -       goto out_free_all;
887 +       if (!IS_ERR(root_inode))
888 +               iput(root_inode);
889 +       return -EINVAL;
890  }
891  
892  /*
893 @@ -627,13 +598,17 @@ static int nfs_show_options(struct seq_f
894  void
895  nfs_zap_caches(struct inode *inode)
896  {
897 +       struct nfs_inode *nfsi = NFS_I(inode);
898 +       int mode = inode->i_mode;
899 +
900         NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
901         NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
902  
903 -       invalidate_remote_inode(inode);
904 -
905         memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
906 -       NFS_CACHEINV(inode);
907 +       if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))
908 +               nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
909 +       else
910 +               nfsi->flags |= NFS_INO_INVALID_ATTR;
911  }
912  
913  /*
914 @@ -673,9 +648,6 @@ nfs_find_actor(struct inode *inode, void
915                 return 0;
916         if (is_bad_inode(inode))
917                 return 0;
918 -       /* Force an attribute cache update if inode->i_count == 0 */
919 -       if (!atomic_read(&inode->i_count))
920 -               NFS_CACHEINV(inode);
921         return 1;
922  }
923  
924 @@ -729,12 +701,12 @@ nfs_fhget(struct super_block *sb, struct
925                 inode->i_ino = hash;
926  
927                 /* We can't support update_atime(), since the server will reset it */
928 -               inode->i_flags |= S_NOATIME;
929 +               inode->i_flags |= S_NOATIME|S_NOCMTIME;
930                 inode->i_mode = fattr->mode;
931                 /* Why so? Because we want revalidate for devices/FIFOs, and
932                  * that's precisely what we have in nfs_file_inode_operations.
933                  */
934 -               inode->i_op = &nfs_file_inode_operations;
935 +               inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops;
936                 if (S_ISREG(inode->i_mode)) {
937                         inode->i_fop = &nfs_file_operations;
938                         inode->i_data.a_ops = &nfs_file_aops;
939 @@ -754,10 +726,6 @@ nfs_fhget(struct super_block *sb, struct
940                 inode->i_atime = fattr->atime;
941                 inode->i_mtime = fattr->mtime;
942                 inode->i_ctime = fattr->ctime;
943 -               nfsi->read_cache_ctime = fattr->ctime;
944 -               nfsi->read_cache_mtime = fattr->mtime;
945 -               nfsi->cache_mtime_jiffies = fattr->timestamp;
946 -               nfsi->read_cache_isize = fattr->size;
947                 if (fattr->valid & NFS_ATTR_FATTR_V4)
948                         nfsi->change_attr = fattr->change_attr;
949                 inode->i_size = nfs_size_to_loff_t(fattr->size);
950 @@ -778,7 +746,6 @@ nfs_fhget(struct super_block *sb, struct
951                 nfsi->attrtimeo_timestamp = jiffies;
952                 memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
953                 nfsi->cache_access.cred = NULL;
954 -
955                 unlock_new_inode(inode);
956         } else
957                 nfs_refresh_inode(inode, fattr);
958 @@ -804,70 +771,50 @@ nfs_setattr(struct dentry *dentry, struc
959         struct nfs_fattr fattr;
960         int error;
961  
962 +       if (attr->ia_valid & ATTR_SIZE) {
963 +               if (!S_ISREG(inode->i_mode) || attr->ia_size == i_size_read(inode))
964 +                       attr->ia_valid &= ~ATTR_SIZE;
965 +       }
966 +
967         /* Optimization: if the end result is no change, don't RPC */
968         attr->ia_valid &= NFS_VALID_ATTRS;
969         if (attr->ia_valid == 0)
970                 return 0;
971  
972         lock_kernel();
973 -
974 -       /*
975 -        * Make sure the inode is up-to-date.
976 -        */
977 -       error = nfs_revalidate_inode(NFS_SERVER(inode),inode);
978 -       if (error) {
979 -#ifdef NFS_PARANOIA
980 -printk("nfs_setattr: revalidate failed, error=%d\n", error);
981 -#endif
982 -               goto out;
983 -       }
984 -
985 -       if (!S_ISREG(inode->i_mode)) {
986 -               attr->ia_valid &= ~ATTR_SIZE;
987 -               if (attr->ia_valid == 0)
988 -                       goto out;
989 -       } else {
990 -               filemap_fdatawrite(inode->i_mapping);
991 -               error = nfs_wb_all(inode);
992 -               filemap_fdatawait(inode->i_mapping);
993 -               if (error)
994 -                       goto out;
995 -               /* Optimize away unnecessary truncates */
996 -               if ((attr->ia_valid & ATTR_SIZE) && i_size_read(inode) == attr->ia_size)
997 -                       attr->ia_valid &= ~ATTR_SIZE;
998 +       nfs_begin_data_update(inode);
999 +       /* Write all dirty data if we're changing file permissions or size */
1000 +       if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID|ATTR_SIZE)) != 0) {
1001 +               if (filemap_fdatawrite(inode->i_mapping) == 0)
1002 +                       filemap_fdatawait(inode->i_mapping);
1003 +               nfs_wb_all(inode);
1004         }
1005 -       if (!attr->ia_valid)
1006 -               goto out;
1007 -
1008         error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
1009 -       if (error)
1010 -               goto out;
1011 -       /*
1012 -        * If we changed the size or mtime, update the inode
1013 -        * now to avoid invalidating the page cache.
1014 -        */
1015 -       if (attr->ia_valid & ATTR_SIZE) {
1016 -               if (attr->ia_size != fattr.size)
1017 -                       printk("nfs_setattr: attr=%Ld, fattr=%Ld??\n",
1018 -                              (long long) attr->ia_size, (long long)fattr.size);
1019 -               vmtruncate(inode, attr->ia_size);
1020 +       if (error == 0) {
1021 +               nfs_refresh_inode(inode, &fattr);
1022 +               if ((attr->ia_valid & ATTR_MODE) != 0) {
1023 +                       int mode;
1024 +                       mode = inode->i_mode & ~S_IALLUGO;
1025 +                       mode |= attr->ia_mode & S_IALLUGO;
1026 +                       inode->i_mode = mode;
1027 +               }
1028 +               if ((attr->ia_valid & ATTR_UID) != 0)
1029 +                       inode->i_uid = attr->ia_uid;
1030 +               if ((attr->ia_valid & ATTR_GID) != 0)
1031 +                       inode->i_gid = attr->ia_gid;
1032 +               if ((attr->ia_valid & ATTR_SIZE) != 0) {
1033 +                       i_size_write(inode, attr->ia_size);
1034 +                       vmtruncate(inode, attr->ia_size);
1035 +               }
1036         }
1037 -
1038 -       /*
1039 -        * If we changed the size or mtime, update the inode
1040 -        * now to avoid invalidating the page cache.
1041 -        */
1042 -       if (!(fattr.valid & NFS_ATTR_WCC)) {
1043 -               struct nfs_inode *nfsi = NFS_I(inode);
1044 -               fattr.pre_size = nfsi->read_cache_isize;
1045 -               fattr.pre_mtime = nfsi->read_cache_mtime;
1046 -               fattr.pre_ctime = nfsi->read_cache_ctime;
1047 -               fattr.valid |= NFS_ATTR_WCC;
1048 -       }
1049 -       /* Force an attribute cache update */
1050 -       NFS_CACHEINV(inode);
1051 -       error = nfs_refresh_inode(inode, &fattr);
1052 -out:
1053 +       if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
1054 +               struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
1055 +               if (*cred) {
1056 +                       put_rpccred(*cred);
1057 +                       *cred = NULL;
1058 +               }
1059 +       }
1060 +       nfs_end_data_update(inode);
1061         unlock_kernel();
1062         return error;
1063  }
1064 @@ -895,7 +842,19 @@ nfs_wait_on_inode(struct inode *inode, i
1065  int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
1066  {
1067         struct inode *inode = dentry->d_inode;
1068 -       int err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
1069 +       struct nfs_inode *nfsi = NFS_I(inode);
1070 +       int need_atime = nfsi->flags & NFS_INO_INVALID_ATIME;
1071 +       int err;
1072 +
1073 +       if (__IS_FLG(inode, MS_NOATIME))
1074 +               need_atime = 0;
1075 +       else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode))
1076 +               need_atime = 0;
1077 +       /* We may force a getattr if the user cares about atime */
1078 +       if (need_atime)
1079 +               err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
1080 +       else
1081 +               err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
1082         if (!err)
1083                 generic_fillattr(inode, stat);
1084         return err;
1085 @@ -930,8 +889,10 @@ int nfs_open(struct inode *inode, struct
1086         auth = NFS_CLIENT(inode)->cl_auth;
1087         cred = rpcauth_lookupcred(auth, 0);
1088         filp->private_data = cred;
1089 -       if (filp->f_mode & FMODE_WRITE)
1090 +       if ((filp->f_mode & FMODE_WRITE) != 0) {
1091                 nfs_set_mmcred(inode, cred);
1092 +               nfs_begin_data_update(inode);
1093 +       }
1094         return 0;
1095  }
1096  
1097 @@ -940,6 +901,8 @@ int nfs_release(struct inode *inode, str
1098         struct rpc_cred *cred;
1099  
1100         lock_kernel();
1101 +       if ((filp->f_mode & FMODE_WRITE) != 0)
1102 +               nfs_end_data_update(inode);
1103         cred = nfs_file_cred(filp);
1104         if (cred)
1105                 put_rpccred(cred);
1106 @@ -956,6 +919,9 @@ __nfs_revalidate_inode(struct nfs_server
1107  {
1108         int              status = -ESTALE;
1109         struct nfs_fattr fattr;
1110 +       struct nfs_inode *nfsi = NFS_I(inode);
1111 +       unsigned long verifier;
1112 +       unsigned int flags;
1113  
1114         dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
1115                 inode->i_sb->s_id, (long long)NFS_FILEID(inode));
1116 @@ -965,23 +931,22 @@ __nfs_revalidate_inode(struct nfs_server
1117                 goto out_nowait;
1118         if (NFS_STALE(inode) && inode != inode->i_sb->s_root->d_inode)
1119                 goto out_nowait;
1120 -       if (NFS_FAKE_ROOT(inode)) {
1121 -               dfprintk(VFS, "NFS: not revalidating fake root\n");
1122 -               status = 0;
1123 -               goto out_nowait;
1124 -       }
1125  
1126         while (NFS_REVALIDATING(inode)) {
1127                 status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
1128                 if (status < 0)
1129                         goto out_nowait;
1130 -               if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) {
1131 -                       status = NFS_STALE(inode) ? -ESTALE : 0;
1132 -                       goto out_nowait;
1133 -               }
1134 +               if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOAC)
1135 +                       continue;
1136 +               if (NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME))
1137 +                       continue;
1138 +               status = NFS_STALE(inode) ? -ESTALE : 0;
1139 +               goto out_nowait;
1140         }
1141         NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
1142  
1143 +       /* Protect against RPC races by saving the change attribute */
1144 +       verifier = nfs_save_change_attribute(inode);
1145         status = NFS_PROTO(inode)->getattr(inode, &fattr);
1146         if (status) {
1147                 dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
1148 @@ -995,13 +960,36 @@ __nfs_revalidate_inode(struct nfs_server
1149                 goto out;
1150         }
1151  
1152 -       status = nfs_refresh_inode(inode, &fattr);
1153 +       status = nfs_update_inode(inode, &fattr, verifier);
1154         if (status) {
1155                 dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
1156                          inode->i_sb->s_id,
1157                          (long long)NFS_FILEID(inode), status);
1158                 goto out;
1159         }
1160 +       flags = nfsi->flags;
1161 +       /*
1162 +        * We may need to keep the attributes marked as invalid if
1163 +        * we raced with nfs_end_attr_update().
1164 +        */
1165 +       if (verifier == nfsi->cache_change_attribute)
1166 +               nfsi->flags &= ~(NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ATIME);
1167 +       /* Do the page cache invalidation */
1168 +       if (flags & NFS_INO_INVALID_DATA) {
1169 +               if (S_ISREG(inode->i_mode)) {
1170 +                       if (filemap_fdatawrite(inode->i_mapping) == 0)
1171 +                               filemap_fdatawait(inode->i_mapping);
1172 +                       nfs_wb_all(inode);
1173 +               }
1174 +               nfsi->flags &= ~NFS_INO_INVALID_DATA;
1175 +               invalidate_inode_pages2(inode->i_mapping);
1176 +               memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
1177 +               dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
1178 +                               inode->i_sb->s_id,
1179 +                               (long long)NFS_FILEID(inode));
1180 +               /* This ensures we revalidate dentries */
1181 +               nfsi->cache_change_attribute++;
1182 +       }
1183         dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
1184                 inode->i_sb->s_id,
1185                 (long long)NFS_FILEID(inode));
1186 @@ -1009,41 +997,104 @@ __nfs_revalidate_inode(struct nfs_server
1187         NFS_FLAGS(inode) &= ~NFS_INO_STALE;
1188  out:
1189         NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
1190 -       wake_up(&NFS_I(inode)->nfs_i_wait);
1191 +       wake_up(&nfsi->nfs_i_wait);
1192   out_nowait:
1193         unlock_kernel();
1194         return status;
1195  }
1196  
1197 -/*
1198 - * nfs_fattr_obsolete - Test if attribute data is newer than cached data
1199 - * @inode: inode
1200 - * @fattr: attributes to test
1201 +/**
1202 + * nfs_begin_data_update
1203 + * @inode - pointer to inode
1204 + * Declare that a set of operations will update file data on the server
1205 + */
1206 +void nfs_begin_data_update(struct inode *inode)
1207 +{
1208 +       atomic_inc(&NFS_I(inode)->data_updates);
1209 +}
1210 +
1211 +/**
1212 + * nfs_end_data_update
1213 + * @inode - pointer to inode
1214 + * Declare end of the operations that will update file data
1215 + */
1216 +void nfs_end_data_update(struct inode *inode)
1217 +{
1218 +       struct nfs_inode *nfsi = NFS_I(inode);
1219 +
1220 +       if (atomic_dec_and_test(&nfsi->data_updates)) {
1221 +               nfsi->cache_change_attribute ++;
1222 +               /* Mark the attribute cache for revalidation */
1223 +               nfsi->flags |= NFS_INO_INVALID_ATTR;
1224 +               /* Directories and symlinks: invalidate page cache too */
1225 +               if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
1226 +                       nfsi->flags |= NFS_INO_INVALID_DATA;
1227 +       }
1228 +}
1229 +
1230 +/**
1231 + * nfs_refresh_inode - verify consistency of the inode attribute cache
1232 + * @inode - pointer to inode
1233 + * @fattr - updated attributes
1234   *
1235 - * Avoid stuffing the attribute cache with obsolete information.
1236 - * We always accept updates if the attribute cache timed out, or if
1237 - * fattr->ctime is newer than our cached value.
1238 - * If fattr->ctime matches the cached value, we still accept the update
1239 - * if it increases the file size.
1240 + * Verifies the attribute cache. If we have just changed the attributes,
1241 + * so that fattr carries weak cache consistency data, then it may
1242 + * also update the ctime/mtime/change_attribute.
1243   */
1244 -static inline
1245 -int nfs_fattr_obsolete(struct inode *inode, struct nfs_fattr *fattr)
1246 +int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
1247  {
1248         struct nfs_inode *nfsi = NFS_I(inode);
1249 -       long cdif;
1250 +       loff_t cur_size, new_isize;
1251 +       int data_unstable;
1252 +
1253 +       /* Are we in the process of updating data on the server? */
1254 +       data_unstable = nfs_caches_unstable(inode);
1255 +
1256 +       if (fattr->valid & NFS_ATTR_FATTR_V4) {
1257 +               if ((fattr->valid & NFS_ATTR_PRE_CHANGE) != 0
1258 +                               && nfsi->change_attr == fattr->pre_change_attr)
1259 +                       nfsi->change_attr = fattr->change_attr;
1260 +               if (!data_unstable && nfsi->change_attr != fattr->change_attr)
1261 +                       nfsi->flags |= NFS_INO_INVALID_ATTR;
1262 +       }
1263 +
1264 +       if ((fattr->valid & NFS_ATTR_FATTR) == 0)
1265 +               return 0;
1266 +
1267 +       /* Has the inode gone and changed behind our back? */
1268 +       if (nfsi->fileid != fattr->fileid
1269 +                       || (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
1270 +               return -EIO;
1271  
1272 -       if (time_after(jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo))
1273 -               goto out_valid;
1274 -       cdif = fattr->ctime.tv_sec - nfsi->read_cache_ctime.tv_sec;
1275 -       if (cdif == 0)
1276 -               cdif = fattr->ctime.tv_nsec - nfsi->read_cache_ctime.tv_nsec;
1277 -       if (cdif > 0)
1278 -               goto out_valid;
1279 -       /* Ugh... */
1280 -       if (cdif == 0 && fattr->size > nfsi->read_cache_isize)
1281 -               goto out_valid;
1282 -       return -1;
1283 - out_valid:
1284 +       cur_size = i_size_read(inode);
1285 +       new_isize = nfs_size_to_loff_t(fattr->size);
1286 +
1287 +       /* If we have atomic WCC data, we may update some attributes */
1288 +       if ((fattr->valid & NFS_ATTR_WCC) != 0) {
1289 +               if (timespec_equal(&inode->i_ctime, &fattr->pre_ctime))
1290 +                       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
1291 +               if (timespec_equal(&inode->i_mtime, &fattr->pre_mtime))
1292 +                       memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
1293 +       }
1294 +
1295 +       /* Verify a few of the more important attributes */
1296 +       if (!data_unstable) {
1297 +               if (!timespec_equal(&inode->i_mtime, &fattr->mtime)
1298 +                               || cur_size != new_isize)
1299 +                       nfsi->flags |= NFS_INO_INVALID_ATTR;
1300 +       } else if (S_ISREG(inode->i_mode) && new_isize > cur_size)
1301 +                       nfsi->flags |= NFS_INO_INVALID_ATTR;
1302 +
1303 +       /* Have any file permissions changed? */
1304 +       if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
1305 +                       || inode->i_uid != fattr->uid
1306 +                       || inode->i_gid != fattr->gid)
1307 +               nfsi->flags |= NFS_INO_INVALID_ATTR;
1308 +
1309 +       if (!timespec_equal(&inode->i_atime, &fattr->atime))
1310 +               nfsi->flags |= NFS_INO_INVALID_ATIME;
1311 +
1312 +       nfsi->read_cache_jiffies = fattr->timestamp;
1313         return 0;
1314  }
1315  
1316 @@ -1059,20 +1110,22 @@ int nfs_fattr_obsolete(struct inode *ino
1317   *
1318   * A very similar scenario holds for the dir cache.
1319   */
1320 -int
1321 -__nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
1322 +static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsigned long verifier)
1323  {
1324         struct nfs_inode *nfsi = NFS_I(inode);
1325         __u64           new_size;
1326         loff_t          new_isize;
1327 -       int             invalid = 0;
1328 -       int             mtime_update = 0;
1329 +       unsigned int    invalid = 0;
1330         loff_t          cur_isize;
1331 +       int data_unstable;
1332  
1333 -       dfprintk(VFS, "NFS: refresh_inode(%s/%ld ct=%d info=0x%x)\n",
1334 -                       inode->i_sb->s_id, inode->i_ino,
1335 +       dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n",
1336 +                       __FUNCTION__, inode->i_sb->s_id, inode->i_ino,
1337                         atomic_read(&inode->i_count), fattr->valid);
1338  
1339 +       if ((fattr->valid & NFS_ATTR_FATTR) == 0)
1340 +               return 0;
1341 +
1342         /* First successful call after mount, fill real data. */
1343         if (NFS_FAKE_ROOT(inode)) {
1344                 dfprintk(VFS, "NFS: updating fake root\n");
1345 @@ -1081,43 +1134,49 @@ __nfs_refresh_inode(struct inode *inode,
1346         }
1347  
1348         if (nfsi->fileid != fattr->fileid) {
1349 -               printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
1350 +               printk(KERN_ERR "%s: inode number mismatch\n"
1351                        "expected (%s/0x%Lx), got (%s/0x%Lx)\n",
1352 +                      __FUNCTION__,
1353                        inode->i_sb->s_id, (long long)nfsi->fileid,
1354                        inode->i_sb->s_id, (long long)fattr->fileid);
1355                 goto out_err;
1356         }
1357  
1358 -       /* Throw out obsolete READDIRPLUS attributes */
1359 -       if (time_before(fattr->timestamp, NFS_READTIME(inode)))
1360 -               return 0;
1361         /*
1362          * Make sure the inode's type hasn't changed.
1363          */
1364         if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
1365                 goto out_changed;
1366  
1367 -       new_size = fattr->size;
1368 -       new_isize = nfs_size_to_loff_t(fattr->size);
1369 -
1370 -       /* Avoid races */
1371 -       if (nfs_fattr_obsolete(inode, fattr))
1372 -               goto out_nochange;
1373 -
1374         /*
1375          * Update the read time so we don't revalidate too often.
1376          */
1377         nfsi->read_cache_jiffies = fattr->timestamp;
1378  
1379 -       /*
1380 -        * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache.
1381 -        *       NOT inode->i_size!!!
1382 -        */
1383 -       if (nfsi->read_cache_isize != new_size) {
1384 +       /* Are we racing with known updates of the metadata on the server? */
1385 +       data_unstable = ! nfs_verify_change_attribute(inode, verifier);
1386 +
1387 +       /* Check if the file size agrees */
1388 +       new_size = fattr->size;
1389 +       new_isize = nfs_size_to_loff_t(fattr->size);
1390 +       cur_isize = i_size_read(inode);
1391 +       if (cur_isize != new_size) {
1392  #ifdef NFS_DEBUG_VERBOSE
1393                 printk(KERN_DEBUG "NFS: isize change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
1394  #endif
1395 -               invalid = 1;
1396 +               /*
1397 +                * If we have pending writebacks, things can get
1398 +                * messy.
1399 +                */
1400 +               if (S_ISREG(inode->i_mode) && data_unstable) {
1401 +                       if (new_isize > cur_isize) {
1402 +                               i_size_write(inode, new_isize);
1403 +                               invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
1404 +                       }
1405 +               } else {
1406 +                       i_size_write(inode, new_isize);
1407 +                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
1408 +               }
1409         }
1410  
1411         /*
1412 @@ -1125,12 +1184,13 @@ __nfs_refresh_inode(struct inode *inode,
1413          *       can change this value in VFS without requiring a
1414          *       cache revalidation.
1415          */
1416 -       if (!timespec_equal(&nfsi->read_cache_mtime, &fattr->mtime)) {
1417 +       if (!timespec_equal(&inode->i_mtime, &fattr->mtime)) {
1418 +               memcpy(&inode->i_mtime, &fattr->mtime, sizeof(inode->i_mtime));
1419  #ifdef NFS_DEBUG_VERBOSE
1420                 printk(KERN_DEBUG "NFS: mtime change on %s/%ld\n", inode->i_sb->s_id, inode->i_ino);
1421  #endif
1422 -               invalid = 1;
1423 -               mtime_update = 1;
1424 +               if (!data_unstable)
1425 +                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
1426         }
1427  
1428         if ((fattr->valid & NFS_ATTR_FATTR_V4)
1429 @@ -1139,47 +1199,15 @@ __nfs_refresh_inode(struct inode *inode,
1430                 printk(KERN_DEBUG "NFS: change_attr change on %s/%ld\n",
1431                        inode->i_sb->s_id, inode->i_ino);
1432  #endif
1433 -               invalid = 1;
1434 -       }
1435 -
1436 -       /* Check Weak Cache Consistency data.
1437 -        * If size and mtime match the pre-operation values, we can
1438 -        * assume that any attribute changes were caused by our NFS
1439 -         * operation, so there's no need to invalidate the caches.
1440 -         */
1441 -       if ((fattr->valid & NFS_ATTR_PRE_CHANGE)
1442 -           && nfsi->change_attr == fattr->pre_change_attr) {
1443 -               invalid = 0;
1444 -       }
1445 -       else if ((fattr->valid & NFS_ATTR_WCC)
1446 -           && nfsi->read_cache_isize == fattr->pre_size
1447 -           && timespec_equal(&nfsi->read_cache_mtime, &fattr->pre_mtime)) {
1448 -               invalid = 0;
1449 -       }
1450 -
1451 -       /*
1452 -        * If we have pending writebacks, things can get
1453 -        * messy.
1454 -        */
1455 -       cur_isize = i_size_read(inode);
1456 -       if (nfs_have_writebacks(inode) && new_isize < cur_isize)
1457 -               new_isize = cur_isize;
1458 -
1459 -       nfsi->read_cache_ctime = fattr->ctime;
1460 -       inode->i_ctime = fattr->ctime;
1461 -       inode->i_atime = fattr->atime;
1462 -
1463 -       if (mtime_update) {
1464 -               if (invalid)
1465 -                       nfsi->cache_mtime_jiffies = fattr->timestamp;
1466 -               nfsi->read_cache_mtime = fattr->mtime;
1467 -               inode->i_mtime = fattr->mtime;
1468 +               nfsi->change_attr = fattr->change_attr;
1469 +               if (!data_unstable)
1470 +                       invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
1471         }
1472  
1473 -       nfsi->read_cache_isize = new_size;
1474 -       i_size_write(inode, new_isize);
1475 +       memcpy(&inode->i_ctime, &fattr->ctime, sizeof(inode->i_ctime));
1476 +       memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime));
1477  
1478 -       if (inode->i_mode != fattr->mode ||
1479 +       if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
1480             inode->i_uid != fattr->uid ||
1481             inode->i_gid != fattr->gid) {
1482                 struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
1483 @@ -1187,15 +1215,17 @@ __nfs_refresh_inode(struct inode *inode,
1484                         put_rpccred(*cred);
1485                         *cred = NULL;
1486                 }
1487 +               invalid |= NFS_INO_INVALID_ATTR;
1488         }
1489  
1490 -       if (fattr->valid & NFS_ATTR_FATTR_V4)
1491 -               nfsi->change_attr = fattr->change_attr;
1492 -
1493         inode->i_mode = fattr->mode;
1494         inode->i_nlink = fattr->nlink;
1495         inode->i_uid = fattr->uid;
1496         inode->i_gid = fattr->gid;
1497 +#ifdef CONFIG_NFS_V4_ACL
1498 +       nfs4_izap_acl(inode, &nfsi->acl);
1499 +       nfs4_izap_acl(inode, &nfsi->default_acl);
1500 +#endif /* CONFIG_NFS_V4_ACL */
1501  
1502         if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
1503                 /*
1504 @@ -1207,31 +1237,30 @@ __nfs_refresh_inode(struct inode *inode,
1505                 inode->i_blocks = fattr->du.nfs2.blocks;
1506                 inode->i_blksize = fattr->du.nfs2.blocksize;
1507         }
1508
1509 -       /* Update attrtimeo value */
1510 -       if (invalid) {
1511 +
1512 +       /* Update attrtimeo value if we're out of the unstable period */
1513 +       if (invalid & NFS_INO_INVALID_ATTR) {
1514                 nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
1515                 nfsi->attrtimeo_timestamp = jiffies;
1516 -               invalidate_remote_inode(inode);
1517 -               memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
1518         } else if (time_after(jiffies, nfsi->attrtimeo_timestamp+nfsi->attrtimeo)) {
1519                 if ((nfsi->attrtimeo <<= 1) > NFS_MAXATTRTIMEO(inode))
1520                         nfsi->attrtimeo = NFS_MAXATTRTIMEO(inode);
1521                 nfsi->attrtimeo_timestamp = jiffies;
1522         }
1523 +       /* Don't invalidate the data if we were to blame */
1524 +       if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)
1525 +                               || S_ISLNK(inode->i_mode)))
1526 +               invalid &= ~NFS_INO_INVALID_DATA;
1527 +       nfsi->flags |= invalid;
1528  
1529         return 0;
1530 - out_nochange:
1531 -       if (!timespec_equal(&fattr->atime, &inode->i_atime))
1532 -               inode->i_atime = fattr->atime;
1533 -       return 0;
1534   out_changed:
1535         /*
1536          * Big trouble! The inode has become a different object.
1537          */
1538  #ifdef NFS_PARANOIA
1539 -       printk(KERN_DEBUG "nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
1540 -              inode->i_ino, inode->i_mode, fattr->mode);
1541 +       printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n",
1542 +                       __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode);
1543  #endif
1544         /*
1545          * No need to worry about unhashing the dentry, as the
1546 @@ -1355,6 +1384,82 @@ static struct file_system_type nfs_fs_ty
1547         .fs_flags       = FS_ODD_RENAME|FS_REVAL_DOT,
1548  };
1549  
1550 +#ifdef CONFIG_NFS_V4_ACL
1551 +
1552 +int
1553 +nfs_setxattr(struct dentry *dentry, const char *key, const void *buf,
1554 +    size_t buflen, int flags)
1555 +{
1556 +       struct posix_acl *acl;
1557 +       int type, error;
1558 +       struct inode *inode = dentry->d_inode;
1559 +
1560 +       if (strlen(key) == sizeof(XATTR_NAME_ACL_ACCESS) - 1 &&
1561 +           memcmp(key, XATTR_NAME_ACL_ACCESS,
1562 +               sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0)
1563 +               type = ACL_TYPE_ACCESS;
1564 +       else if (strlen(key) == sizeof(XATTR_NAME_ACL_DEFAULT) - 1 &&
1565 +           memcmp(key, XATTR_NAME_ACL_DEFAULT,
1566 +               sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0)
1567 +               type = ACL_TYPE_DEFAULT;
1568 +       else
1569 +               return (-EINVAL);
1570 +
1571 +        if (!S_ISREG(inode->i_mode) &&
1572 +            (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
1573 +                return (-EPERM);
1574 +
1575 +       if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
1576 +               return -EACCES;
1577 +
1578 +       acl = posix_acl_from_xattr(buf, buflen);
1579 +       if (IS_ERR(acl))
1580 +               return (PTR_ERR(acl));
1581 +       if (acl == NULL)
1582 +               return (-ENODATA);
1583 +
1584 +       error = posix_acl_valid(acl);
1585 +       if (error)
1586 +               goto out_free;
1587 +
1588 +       error = nfs4_proc_set_posix_acl(inode, type, acl);
1589 +out_free:
1590 +       posix_acl_release(acl);
1591 +       return error;
1592 +}
1593 +
1594 +ssize_t
1595 +nfs_getxattr(struct dentry *dentry, const char *key, void *buf,
1596 +    size_t buflen)
1597 +{
1598 +       int type = 0;
1599 +       struct inode *inode = dentry->d_inode;
1600 +       struct posix_acl *acl;
1601 +       ssize_t ret;
1602 +
1603 +       if (strlen(key) == sizeof(XATTR_NAME_ACL_ACCESS) - 1 &&
1604 +           memcmp(key, XATTR_NAME_ACL_ACCESS,
1605 +               sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0)
1606 +               type = ACL_TYPE_ACCESS;
1607 +       else if (strlen(key) == sizeof(XATTR_NAME_ACL_DEFAULT) - 1 &&
1608 +           memcmp(key, XATTR_NAME_ACL_DEFAULT,
1609 +               sizeof(XATTR_NAME_ACL_ACCESS) - 1) == 0)
1610 +               type = ACL_TYPE_DEFAULT;
1611 +       else
1612 +               return (-EINVAL);
1613 +
1614 +       acl = nfs4_proc_get_posix_acl(inode, type);
1615 +       if (IS_ERR(acl))
1616 +               return (PTR_ERR(acl));
1617 +
1618 +       ret = posix_acl_to_xattr(acl, buf, buflen);
1619 +
1620 +       posix_acl_release(acl);
1621 +       return ret;
1622 +}
1623 +
1624 +#endif /* CONFIG_NFS_V4_ACL */
1625 +
1626  #ifdef CONFIG_NFS_V4
1627  
1628  static void nfs4_clear_inode(struct inode *);
1629 @@ -1601,7 +1706,7 @@ static struct super_block *nfs4_get_sb(s
1630  
1631         if (data->version != NFS4_MOUNT_VERSION) {
1632                 printk("nfs warning: mount version %s than kernel\n",
1633 -                       data->version < NFS_MOUNT_VERSION ? "older" : "newer");
1634 +                       data->version < NFS4_MOUNT_VERSION ? "older" : "newer");
1635         }
1636  
1637         p = nfs_copy_user_string(NULL, &data->hostname, 256);
1638 @@ -1699,6 +1804,10 @@ static struct inode *nfs_alloc_inode(str
1639                 return NULL;
1640         nfsi->flags = 0;
1641         nfsi->mm_cred = NULL;
1642 +#ifdef CONFIG_NFS_V4_ACL
1643 +       nfsi->acl = NFS4_ACL_NOT_CACHED;
1644 +       nfsi->default_acl = NFS4_ACL_NOT_CACHED;
1645 +#endif /* CONFIG_NFS_V4_ACL */
1646         nfs4_zero_state(nfsi);
1647         return &nfsi->vfs_inode;
1648  }
1649 @@ -1718,6 +1827,7 @@ static void init_once(void * foo, kmem_c
1650                 INIT_LIST_HEAD(&nfsi->dirty);
1651                 INIT_LIST_HEAD(&nfsi->commit);
1652                 INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
1653 +               atomic_set(&nfsi->data_updates, 0);
1654                 nfsi->ndirty = 0;
1655                 nfsi->ncommit = 0;
1656                 nfsi->npages = 0;
1657 diff -puN fs/nfs/nfs3proc.c~CITI_NFS4_ALL fs/nfs/nfs3proc.c
1658 --- linux-2.6.3/fs/nfs/nfs3proc.c~CITI_NFS4_ALL 2004-02-19 16:47:03.000000000 -0500
1659 +++ linux-2.6.3-bfields/fs/nfs/nfs3proc.c       2004-02-19 16:47:07.000000000 -0500
1660 @@ -68,20 +68,6 @@ nfs3_async_handle_jukebox(struct rpc_tas
1661         return 1;
1662  }
1663  
1664 -static void
1665 -nfs3_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
1666 -{
1667 -       if (fattr->valid & NFS_ATTR_FATTR) {
1668 -               if (!(fattr->valid & NFS_ATTR_WCC)) {
1669 -                       fattr->pre_size  = NFS_CACHE_ISIZE(inode);
1670 -                       fattr->pre_mtime = NFS_CACHE_MTIME(inode);
1671 -                       fattr->pre_ctime = NFS_CACHE_CTIME(inode);
1672 -                       fattr->valid |= NFS_ATTR_WCC;
1673 -               }
1674 -               nfs_refresh_inode(inode, fattr);
1675 -       }
1676 -}
1677 -
1678  static struct rpc_cred *
1679  nfs_cred(struct inode *inode, struct file *filp)
1680  {
1681 @@ -99,14 +85,18 @@ nfs_cred(struct inode *inode, struct fil
1682   */
1683  static int
1684  nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
1685 -                  struct nfs_fattr *fattr)
1686 +                  struct nfs_fsinfo *info)
1687  {
1688         int     status;
1689  
1690 -       dprintk("NFS call  getroot\n");
1691 -       fattr->valid = 0;
1692 -       status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0);
1693 -       dprintk("NFS reply getroot\n");
1694 +       dprintk("%s: call  fsinfo\n", __FUNCTION__);
1695 +       info->fattr->valid = 0;
1696 +       status = rpc_call(server->client_sys, NFS3PROC_FSINFO, fhandle, info, 0);
1697 +       dprintk("%s: reply fsinfo %d\n", __FUNCTION__, status);
1698 +       if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
1699 +               status = rpc_call(server->client_sys, NFS3PROC_GETATTR, fhandle, info->fattr, 0);
1700 +               dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
1701 +       }
1702         return status;
1703  }
1704  
1705 @@ -280,7 +270,7 @@ nfs3_proc_write(struct nfs_write_data *w
1706         msg.rpc_cred = nfs_cred(inode, filp);
1707         status = rpc_call_sync(NFS_CLIENT(inode), &msg, rpcflags);
1708         if (status >= 0)
1709 -               nfs3_write_refresh_inode(inode, fattr);
1710 +               nfs_refresh_inode(inode, fattr);
1711         dprintk("NFS reply write: %d\n", status);
1712         return status < 0? status : wdata->res.count;
1713  }
1714 @@ -303,7 +293,7 @@ nfs3_proc_commit(struct nfs_write_data *
1715         msg.rpc_cred = nfs_cred(inode, filp);
1716         status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
1717         if (status >= 0)
1718 -               nfs3_write_refresh_inode(inode, fattr);
1719 +               nfs_refresh_inode(inode, fattr);
1720         dprintk("NFS reply commit: %d\n", status);
1721         return status;
1722  }
1723 @@ -777,12 +767,13 @@ nfs3_proc_read_setup(struct nfs_read_dat
1724  static void
1725  nfs3_write_done(struct rpc_task *task)
1726  {
1727 -       struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
1728 +       struct nfs_write_data *data;
1729  
1730         if (nfs3_async_handle_jukebox(task))
1731                 return;
1732 +       data = (struct nfs_write_data *)task->tk_calldata;
1733         if (task->tk_status >= 0)
1734 -               nfs3_write_refresh_inode(data->inode, data->res.fattr);
1735 +               nfs_refresh_inode(data->inode, data->res.fattr);
1736         nfs_writeback_done(task);
1737  }
1738  
1739 @@ -835,12 +826,13 @@ nfs3_proc_write_setup(struct nfs_write_d
1740  static void
1741  nfs3_commit_done(struct rpc_task *task)
1742  {
1743 -       struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
1744 +       struct nfs_write_data *data;
1745  
1746         if (nfs3_async_handle_jukebox(task))
1747                 return;
1748 +       data = (struct nfs_write_data *)task->tk_calldata;
1749         if (task->tk_status >= 0)
1750 -               nfs3_write_refresh_inode(data->inode, data->res.fattr);
1751 +               nfs_refresh_inode(data->inode, data->res.fattr);
1752         nfs_commit_done(task);
1753  }
1754  
1755 @@ -907,6 +899,7 @@ struct nfs_rpc_ops  nfs_v3_clientops = {
1756         .version        = 3,                    /* protocol version */
1757         .dentry_ops     = &nfs_dentry_operations,
1758         .dir_inode_ops  = &nfs_dir_inode_operations,
1759 +       .file_inode_ops = &nfs_file_inode_operations,
1760         .getroot        = nfs3_proc_get_root,
1761         .getattr        = nfs3_proc_getattr,
1762         .setattr        = nfs3_proc_setattr,
1763 diff -puN fs/nfs/nfs4proc.c~CITI_NFS4_ALL fs/nfs/nfs4proc.c
1764 --- linux-2.6.3/fs/nfs/nfs4proc.c~CITI_NFS4_ALL 2004-02-19 16:47:03.000000000 -0500
1765 +++ linux-2.6.3-bfields/fs/nfs/nfs4proc.c       2004-02-19 16:47:15.000000000 -0500
1766 @@ -46,112 +46,20 @@
1767  #include <linux/nfs_page.h>
1768  #include <linux/smp_lock.h>
1769  #include <linux/namei.h>
1770 +#include <linux/nfs4_acl.h>
1771 +#include <linux/nfs_idmap.h>
1772  
1773  #define NFSDBG_FACILITY                NFSDBG_PROC
1774  
1775  #define NFS4_POLL_RETRY_TIME   (15*HZ)
1776  
1777 -#define GET_OP(cp,name)                &cp->ops[cp->req_nops].u.name
1778 -#define OPNUM(cp)              cp->ops[cp->req_nops].opnum
1779 -
1780 +static int nfs4_proc_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
1781  static int nfs4_async_handle_error(struct rpc_task *, struct nfs_server *);
1782  extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
1783  extern struct rpc_procinfo nfs4_procedures[];
1784  
1785  extern nfs4_stateid zero_stateid;
1786  
1787 -static void
1788 -nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
1789 -                   struct nfs_server *server, char *tag)
1790 -{
1791 -       memset(cp, 0, sizeof(*cp));
1792 -       cp->ops = ops;
1793 -       cp->server = server;
1794 -}
1795 -
1796 -static void
1797 -nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported, u32 *resp_access)
1798 -{
1799 -       struct nfs4_access *access = GET_OP(cp, access);
1800 -       
1801 -       access->ac_req_access = req_access;
1802 -       access->ac_resp_supported = resp_supported;
1803 -       access->ac_resp_access = resp_access;
1804 -       
1805 -       OPNUM(cp) = OP_ACCESS;
1806 -       cp->req_nops++;
1807 -}
1808 -
1809 -static void
1810 -nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name,
1811 -                     struct iattr *sattr, struct nfs4_change_info *info)
1812 -{
1813 -       struct nfs4_create *create = GET_OP(cp, create);
1814 -       
1815 -       create->cr_ftype = NF4DIR;
1816 -       create->cr_namelen = name->len;
1817 -       create->cr_name = name->name;
1818 -       create->cr_attrs = sattr;
1819 -       create->cr_cinfo = info;
1820 -       
1821 -       OPNUM(cp) = OP_CREATE;
1822 -       cp->req_nops++;
1823 -}
1824 -
1825 -static void
1826 -nfs4_setup_create_symlink(struct nfs4_compound *cp, struct qstr *name,
1827 -                         struct qstr *linktext, struct iattr *sattr,
1828 -                         struct nfs4_change_info *info)
1829 -{
1830 -       struct nfs4_create *create = GET_OP(cp, create);
1831 -
1832 -       create->cr_ftype = NF4LNK;
1833 -       create->cr_textlen = linktext->len;
1834 -       create->cr_text = linktext->name;
1835 -       create->cr_namelen = name->len;
1836 -       create->cr_name = name->name;
1837 -       create->cr_attrs = sattr;
1838 -       create->cr_cinfo = info;
1839 -
1840 -       OPNUM(cp) = OP_CREATE;
1841 -       cp->req_nops++;
1842 -}
1843 -
1844 -static void
1845 -nfs4_setup_create_special(struct nfs4_compound *cp, struct qstr *name,
1846 -                           dev_t dev, struct iattr *sattr,
1847 -                           struct nfs4_change_info *info)
1848 -{
1849 -       int mode = sattr->ia_mode;
1850 -       struct nfs4_create *create = GET_OP(cp, create);
1851 -
1852 -       BUG_ON(!(sattr->ia_valid & ATTR_MODE));
1853 -       BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
1854 -       
1855 -       if (S_ISFIFO(mode))
1856 -               create->cr_ftype = NF4FIFO;
1857 -       else if (S_ISBLK(mode)) {
1858 -               create->cr_ftype = NF4BLK;
1859 -               create->cr_specdata1 = MAJOR(dev);
1860 -               create->cr_specdata2 = MINOR(dev);
1861 -       }
1862 -       else if (S_ISCHR(mode)) {
1863 -               create->cr_ftype = NF4CHR;
1864 -               create->cr_specdata1 = MAJOR(dev);
1865 -               create->cr_specdata2 = MINOR(dev);
1866 -       }
1867 -       else
1868 -               create->cr_ftype = NF4SOCK;
1869 -       
1870 -       create->cr_namelen = name->len;
1871 -       create->cr_name = name->name;
1872 -       create->cr_attrs = sattr;
1873 -       create->cr_cinfo = info;
1874 -
1875 -       OPNUM(cp) = OP_CREATE;
1876 -       cp->req_nops++;
1877 -}
1878 -
1879  /*
1880   * This is our standard bitmap for GETATTR requests.
1881   */
1882 @@ -181,126 +89,15 @@ u32 nfs4_statfs_bitmap[2] = {
1883         | FATTR4_WORD1_SPACE_TOTAL
1884  };
1885  
1886 -u32 nfs4_pathconf_bitmap[2] = {
1887 -       FATTR4_WORD0_MAXLINK
1888 -       | FATTR4_WORD0_MAXNAME,
1889 -       0
1890 -};
1891 -
1892 -static inline void
1893 -__nfs4_setup_getattr(struct nfs4_compound *cp, u32 *bitmap,
1894 -                    struct nfs_fattr *fattr,
1895 -                    struct nfs_fsstat *fsstat,
1896 -                    struct nfs_pathconf *pathconf)
1897 -{
1898 -        struct nfs4_getattr *getattr = GET_OP(cp, getattr);
1899 -
1900 -        getattr->gt_bmval = bitmap;
1901 -        getattr->gt_attrs = fattr;
1902 -       getattr->gt_fsstat = fsstat;
1903 -       getattr->gt_pathconf = pathconf;
1904 -
1905 -        OPNUM(cp) = OP_GETATTR;
1906 -        cp->req_nops++;
1907 -}
1908 -
1909 -static void
1910 -nfs4_setup_getattr(struct nfs4_compound *cp,
1911 -               struct nfs_fattr *fattr)
1912 -{
1913 -       __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr,
1914 -                       NULL, NULL);
1915 -}
1916 -
1917 -static void
1918 -nfs4_setup_statfs(struct nfs4_compound *cp,
1919 -               struct nfs_fsstat *fsstat)
1920 -{
1921 -       __nfs4_setup_getattr(cp, nfs4_statfs_bitmap,
1922 -                       NULL, fsstat, NULL);
1923 -}
1924 -
1925 -static void
1926 -nfs4_setup_pathconf(struct nfs4_compound *cp,
1927 -               struct nfs_pathconf *pathconf)
1928 -{
1929 -       __nfs4_setup_getattr(cp, nfs4_pathconf_bitmap,
1930 -                       NULL, NULL, pathconf);
1931 -}
1932 -
1933 -static void
1934 -nfs4_setup_getfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
1935 -{
1936 -       struct nfs4_getfh *getfh = GET_OP(cp, getfh);
1937 -
1938 -       getfh->gf_fhandle = fhandle;
1939 -
1940 -       OPNUM(cp) = OP_GETFH;
1941 -       cp->req_nops++;
1942 -}
1943 -
1944 -static void
1945 -nfs4_setup_link(struct nfs4_compound *cp, struct qstr *name,
1946 -               struct nfs4_change_info *info)
1947 -{
1948 -       struct nfs4_link *link = GET_OP(cp, link);
1949 -
1950 -       link->ln_namelen = name->len;
1951 -       link->ln_name = name->name;
1952 -       link->ln_cinfo = info;
1953 -
1954 -       OPNUM(cp) = OP_LINK;
1955 -       cp->req_nops++;
1956 -}
1957 -
1958  static void
1959 -nfs4_setup_lookup(struct nfs4_compound *cp, struct qstr *q)
1960 -{
1961 -       struct nfs4_lookup *lookup = GET_OP(cp, lookup);
1962 -
1963 -       lookup->lo_name = q;
1964 -
1965 -       OPNUM(cp) = OP_LOOKUP;
1966 -       cp->req_nops++;
1967 -}
1968 -
1969 -static void
1970 -nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
1971 -{
1972 -       struct nfs4_putfh *putfh = GET_OP(cp, putfh);
1973 -
1974 -       putfh->pf_fhandle = fhandle;
1975 -
1976 -       OPNUM(cp) = OP_PUTFH;
1977 -       cp->req_nops++;
1978 -}
1979 -
1980 -static void
1981 -nfs4_setup_putrootfh(struct nfs4_compound *cp)
1982 -{
1983 -        OPNUM(cp) = OP_PUTROOTFH;
1984 -        cp->req_nops++;
1985 -}
1986 -
1987 -static void
1988 -nfs4_setup_readdir(struct nfs4_compound *cp, u64 cookie, u32 *verifier,
1989 -                    struct page **pages, unsigned int bufsize, struct dentry *dentry)
1990 +nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry, struct nfs4_readdir_arg *readdir)
1991  {
1992         u32 *start, *p;
1993 -       struct nfs4_readdir *readdir = GET_OP(cp, readdir);
1994  
1995 -       BUG_ON(bufsize < 80);
1996 -       readdir->rd_cookie = (cookie > 2) ? cookie : 0;
1997 -       memcpy(&readdir->rd_req_verifier, verifier, sizeof(readdir->rd_req_verifier));
1998 -       readdir->rd_count = bufsize;
1999 -       readdir->rd_bmval[0] = FATTR4_WORD0_FILEID;
2000 -       readdir->rd_bmval[1] = 0;
2001 -       readdir->rd_pages = pages;
2002 -       readdir->rd_pgbase = 0;
2003 +       BUG_ON(readdir->count < 80);
2004 +       readdir->cookie = (cookie > 2) ? cookie : 0;
2005 +       memcpy(&readdir->req_verifier, verifier, sizeof(readdir->req_verifier));
2006         
2007 -       OPNUM(cp) = OP_READDIR;
2008 -       cp->req_nops++;
2009 -
2010         if (cookie >= 2)
2011                 return;
2012         
2013 @@ -311,7 +108,7 @@ nfs4_setup_readdir(struct nfs4_compound 
2014          * when talking to the server, we always send cookie 0
2015          * instead of 1 or 2.
2016          */
2017 -       start = p = (u32 *)kmap_atomic(*pages, KM_USER0);
2018 +       start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0);
2019         
2020         if (cookie == 0) {
2021                 *p++ = xdr_one;                                  /* next */
2022 @@ -337,68 +134,12 @@ nfs4_setup_readdir(struct nfs4_compound 
2023         *p++ = htonl(8);              /* attribute buffer length */
2024         p = xdr_encode_hyper(p, NFS_FILEID(dentry->d_parent->d_inode));
2025  
2026 -       readdir->rd_pgbase = (char *)p - (char *)start;
2027 -       readdir->rd_count -= readdir->rd_pgbase;
2028 +       readdir->pgbase = (char *)p - (char *)start;
2029 +       readdir->count -= readdir->pgbase;
2030         kunmap_atomic(start, KM_USER0);
2031  }
2032  
2033  static void
2034 -nfs4_setup_readlink(struct nfs4_compound *cp, int count, struct page **pages)
2035 -{
2036 -       struct nfs4_readlink *readlink = GET_OP(cp, readlink);
2037 -
2038 -       readlink->rl_count = count;
2039 -       readlink->rl_pages = pages;
2040 -
2041 -       OPNUM(cp) = OP_READLINK;
2042 -       cp->req_nops++;
2043 -}
2044 -
2045 -static void
2046 -nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_change_info *cinfo)
2047 -{
2048 -       struct nfs4_remove *remove = GET_OP(cp, remove);
2049 -
2050 -       remove->rm_namelen = name->len;
2051 -       remove->rm_name = name->name;
2052 -       remove->rm_cinfo = cinfo;
2053 -
2054 -       OPNUM(cp) = OP_REMOVE;
2055 -       cp->req_nops++;
2056 -}
2057 -
2058 -static void
2059 -nfs4_setup_rename(struct nfs4_compound *cp, struct qstr *old, struct qstr *new,
2060 -                 struct nfs4_change_info *old_cinfo, struct nfs4_change_info *new_cinfo)
2061 -{
2062 -       struct nfs4_rename *rename = GET_OP(cp, rename);
2063 -
2064 -       rename->rn_oldnamelen = old->len;
2065 -       rename->rn_oldname = old->name;
2066 -       rename->rn_newnamelen = new->len;
2067 -       rename->rn_newname = new->name;
2068 -       rename->rn_src_cinfo = old_cinfo;
2069 -       rename->rn_dst_cinfo = new_cinfo;
2070 -
2071 -       OPNUM(cp) = OP_RENAME;
2072 -       cp->req_nops++;
2073 -}
2074 -
2075 -static void
2076 -nfs4_setup_restorefh(struct nfs4_compound *cp)
2077 -{
2078 -        OPNUM(cp) = OP_RESTOREFH;
2079 -        cp->req_nops++;
2080 -}
2081 -
2082 -static void
2083 -nfs4_setup_savefh(struct nfs4_compound *cp)
2084 -{
2085 -        OPNUM(cp) = OP_SAVEFH;
2086 -        cp->req_nops++;
2087 -}
2088 -
2089 -static void
2090  renew_lease(struct nfs_server *server, unsigned long timestamp)
2091  {
2092         struct nfs4_client *clp = server->nfs4_state;
2093 @@ -409,47 +150,6 @@ renew_lease(struct nfs_server *server, u
2094  }
2095  
2096  static inline void
2097 -process_lease(struct nfs4_compound *cp)
2098 -{
2099 -        /*
2100 -         * Generic lease processing: If this operation contains a
2101 -        * lease-renewing operation, and it succeeded, update the RENEW time
2102 -        * in the superblock.  Instead of the current time, we use the time
2103 -        * when the request was sent out.  (All we know is that the lease was
2104 -        * renewed sometime between then and now, and we have to assume the
2105 -        * worst case.)
2106 -        *
2107 -        * Notes:
2108 -        *   (1) renewd doesn't acquire the spinlock when messing with
2109 -        *     server->last_renewal; this is OK since rpciod always runs
2110 -        *     under the BKL.
2111 -        *   (2) cp->timestamp was set at the end of XDR encode.
2112 -         */
2113 -       if (!cp->renew_index)
2114 -               return;
2115 -       if (!cp->toplevel_status || cp->resp_nops > cp->renew_index)
2116 -               renew_lease(cp->server, cp->timestamp);
2117 -}
2118 -
2119 -static int
2120 -nfs4_call_compound(struct nfs4_compound *cp, struct rpc_cred *cred, int flags)
2121 -{
2122 -       int status;
2123 -       struct rpc_message msg = {
2124 -               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND],
2125 -               .rpc_argp = cp,
2126 -               .rpc_resp = cp,
2127 -               .rpc_cred = cred,
2128 -       };
2129 -
2130 -       status = rpc_call_sync(cp->server->client, &msg, flags);
2131 -       if (!status)
2132 -               process_lease(cp);
2133 -       
2134 -       return status;
2135 -}
2136 -
2137 -static inline void
2138  process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr)
2139  {
2140         BUG_ON((fattr->valid & NFS_ATTR_FATTR) == 0);
2141 @@ -476,11 +176,6 @@ nfs4_open_reclaim(struct nfs4_state_owne
2142                 .valid = 0,
2143         };
2144         struct nfs4_change_info d_cinfo;
2145 -       struct nfs4_getattr     f_getattr = {
2146 -               .gt_bmval       = nfs4_fattr_bitmap,
2147 -               .gt_attrs       = &fattr,
2148 -       };
2149 -
2150         struct nfs_open_reclaimargs o_arg = {
2151                 .fh = NFS_FH(inode),
2152                 .seqid = sp->so_seqid,
2153 @@ -488,11 +183,10 @@ nfs4_open_reclaim(struct nfs4_state_owne
2154                 .share_access = state->state,
2155                 .clientid = server->nfs4_state->cl_clientid,
2156                 .claim = NFS4_OPEN_CLAIM_PREVIOUS,
2157 -               .f_getattr = &f_getattr,
2158         };
2159         struct nfs_openres o_res = {
2160 -               .cinfo = &d_cinfo,
2161 -               .f_getattr = &f_getattr,
2162 +               .cinfo  = &d_cinfo,
2163 +               .f_attr = &fattr,
2164                 .server = server,       /* Grrr */
2165         };
2166         struct rpc_message msg = {
2167 @@ -528,28 +222,18 @@ nfs4_do_open(struct inode *dir, struct q
2168         struct nfs_fattr        f_attr = {
2169                 .valid          = 0,
2170         };
2171 -       struct nfs4_getattr     f_getattr = {
2172 -               .gt_bmval       = nfs4_fattr_bitmap,
2173 -               .gt_attrs       = &f_attr,
2174 -       };
2175 -       struct nfs4_getattr     d_getattr = {
2176 -               .gt_bmval       = nfs4_fattr_bitmap,
2177 -               .gt_attrs       = &d_attr,
2178 -       };
2179         struct nfs_openargs o_arg = {
2180                 .fh             = NFS_FH(dir),
2181                 .share_access   = flags & (FMODE_READ|FMODE_WRITE),
2182                 .opentype       = (flags & O_CREAT) ? NFS4_OPEN_CREATE : NFS4_OPEN_NOCREATE,
2183                 .createmode     = (flags & O_EXCL) ? NFS4_CREATE_EXCLUSIVE : NFS4_CREATE_UNCHECKED,
2184                 .name           = name,
2185 -               .f_getattr      = &f_getattr,
2186 -               .d_getattr      = &d_getattr,
2187                 .server         = server,
2188         };
2189         struct nfs_openres o_res = {
2190                 .cinfo          = &d_cinfo,
2191 -               .f_getattr      = &f_getattr,
2192 -               .d_getattr      = &d_getattr,
2193 +               .f_attr         = &f_attr,
2194 +               .d_attr         = &d_attr,
2195                 .server         = server,
2196         };
2197         struct rpc_message msg = {
2198 @@ -665,18 +349,14 @@ nfs4_do_setattr(struct nfs_server *serve
2199                  struct nfs_fh *fhandle, struct iattr *sattr,
2200                  struct nfs4_state *state)
2201  {
2202 -        struct nfs4_getattr     getattr = {
2203 -                .gt_bmval       = nfs4_fattr_bitmap,
2204 -                .gt_attrs       = fattr,
2205 -        };
2206          struct nfs_setattrargs  arg = {
2207                  .fh             = fhandle,
2208                  .iap            = sattr,
2209 -                .attr           = &getattr,
2210 +                .fattr          = fattr,
2211                 .server         = server,
2212          };
2213          struct nfs_setattrres  res = {
2214 -                .attr           = &getattr,
2215 +                .fattr          = fattr,
2216                 .server         = server,
2217          };
2218          struct rpc_message msg = {
2219 @@ -822,27 +502,43 @@ nfs4_open_revalidate(struct inode *dir, 
2220  
2221  static int
2222  nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
2223 -                  struct nfs_fattr *fattr)
2224 +                  struct nfs_fsinfo *info)
2225  {
2226 -       struct nfs4_compound    compound;
2227 -       struct nfs4_op          ops[4];
2228 +       struct nfs_fattr *      fattr = info->fattr;
2229         unsigned char *         p;
2230         struct qstr             q;
2231         int                     status;
2232 +       struct nfs4_getroot_arg args = {
2233 +               .fhandle = fhandle,
2234 +               .name = &q,
2235 +       };
2236 +       struct nfs4_getroot_res res = {
2237 +               .server = server,
2238 +               .fattr = fattr,
2239 +               .fhandle = fhandle,
2240 +       };
2241 +       struct rpc_message msg_head = {
2242 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETROOT_HEAD],
2243 +               .rpc_argp = NULL,
2244 +               .rpc_resp = &res,
2245 +       };
2246 +       struct rpc_message msg_path = {
2247 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETROOT_PATH],
2248 +               .rpc_argp = &args,
2249 +               .rpc_resp = &res,
2250 +       };
2251  
2252         /*
2253          * Now we do a separate LOOKUP for each component of the mount path.
2254          * The LOOKUPs are done separately so that we can conveniently
2255          * catch an ERR_WRONGSEC if it occurs along the way...
2256          */
2257 -       p = server->mnt_path;
2258         fattr->valid = 0;
2259 -       nfs4_setup_compound(&compound, ops, server, "getrootfh");
2260 -       nfs4_setup_putrootfh(&compound);
2261 -       nfs4_setup_getattr(&compound, fattr);
2262 -       nfs4_setup_getfh(&compound, fhandle);
2263 -       if ((status = nfs4_call_compound(&compound, NULL, 0)))
2264 +       status = rpc_call_sync(server->client, &msg_head, 0);
2265 +       if (status)
2266                 goto out;
2267 +
2268 +       p = server->mnt_path;
2269         for (;;) {
2270                 while (*p == '/')
2271                         p++;
2272 @@ -854,12 +550,7 @@ nfs4_proc_get_root(struct nfs_server *se
2273                 q.len = p - q.name;
2274  
2275                 fattr->valid = 0;
2276 -               nfs4_setup_compound(&compound, ops, server, "mount");
2277 -               nfs4_setup_putfh(&compound, fhandle);
2278 -               nfs4_setup_lookup(&compound, &q);
2279 -               nfs4_setup_getattr(&compound, fattr);
2280 -               nfs4_setup_getfh(&compound, fhandle);
2281 -               status = nfs4_call_compound(&compound, NULL, 0);
2282 +               status = rpc_call_sync(server->client,&msg_path,0);
2283                 if (!status)
2284                         continue;
2285                 if (status == -ENOENT) {
2286 @@ -869,21 +560,27 @@ nfs4_proc_get_root(struct nfs_server *se
2287                 break;
2288         }
2289  out:
2290 -       return status;
2291 +       if (status)
2292 +               return status;
2293 +       return nfs4_proc_fsinfo(server, fhandle, info);
2294  }
2295  
2296  static int
2297  nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
2298  {
2299 -       struct nfs4_compound compound;
2300 -       struct nfs4_op ops[2];
2301 -
2302 +       struct nfs4_getattr_res res = {
2303 +               .fattr = fattr,
2304 +               .server = NFS_SERVER(inode),
2305 +       };
2306 +       struct rpc_message msg = {
2307 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
2308 +               .rpc_argp = NFS_FH(inode),
2309 +               .rpc_resp = &res,
2310 +       };
2311 +       
2312         fattr->valid = 0;
2313  
2314 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "getattr");
2315 -       nfs4_setup_putfh(&compound, NFS_FH(inode));
2316 -       nfs4_setup_getattr(&compound, fattr);
2317 -       return nfs4_call_compound(&compound, NULL, 0);
2318 +       return rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
2319  }
2320  
2321  /* 
2322 @@ -945,26 +642,218 @@ out:
2323         return status;
2324  }
2325  
2326 +#ifdef CONFIG_NFS_V4_ACL
2327 +
2328 +static inline int
2329 +nfs_name_to_uid_wrapper(void *arg, const char *name, size_t len, __u32 *id)
2330 +{
2331 +       return nfs_map_name_to_uid((struct nfs4_client *)arg, name, len, id);
2332 +}
2333 +
2334 +static inline int
2335 +nfs_name_to_gid_wrapper(void *arg, const char *name, size_t len, __u32 *id)
2336 +{
2337 +       return nfs_map_group_to_gid((struct nfs4_client*)arg, name, len, id);
2338 +}
2339 +
2340 +static inline int
2341 +nfs_uid_to_name_wrapper(void *arg, __u32 id, char *name)
2342 +{
2343 +       return nfs_map_uid_to_name((struct nfs4_client *)arg, id, name);
2344 +}
2345 +
2346 +static inline int
2347 +nfs_gid_to_name_wrapper(void *arg, __u32 id, char *name)
2348 +{
2349 +       return nfs_map_gid_to_group((struct nfs4_client *)arg, id, name);
2350 +}
2351 +
2352 +static struct nfs4_acl_idmapper nfs4_idmapper = {
2353 +       .name2uid = nfs_name_to_uid_wrapper,
2354 +       .name2gid = nfs_name_to_gid_wrapper,
2355 +       .uid2name = nfs_uid_to_name_wrapper,
2356 +       .gid2name = nfs_gid_to_name_wrapper,
2357 +};
2358 +
2359 +/* From fs/ext2/acl.c: */
2360 +
2361 +static inline struct posix_acl *
2362 +nfs4_iget_acl(struct inode *inode, struct posix_acl **i_acl)
2363 +{
2364 +       struct posix_acl *acl = NFS4_ACL_NOT_CACHED;
2365 +
2366 +       spin_lock(&inode->i_lock);
2367 +       if (*i_acl != NFS4_ACL_NOT_CACHED)
2368 +               acl = posix_acl_dup(*i_acl);
2369 +       spin_unlock(&inode->i_lock);
2370 +       return acl;
2371 +}
2372 +
2373 +void
2374 +nfs4_iset_acl(struct inode *inode, struct posix_acl **i_acl,
2375 +               struct posix_acl *acl)
2376 +{
2377 +       spin_lock(&inode->i_lock);
2378 +       if (*i_acl != NFS4_ACL_NOT_CACHED)
2379 +               posix_acl_release(*i_acl);
2380 +       *i_acl = posix_acl_dup(acl);
2381 +       spin_unlock(&inode->i_lock);
2382 +}
2383 +
2384 +void
2385 +nfs4_izap_acl(struct inode *inode, struct posix_acl **i_acl)
2386 +{
2387 +       spin_lock(&inode->i_lock);
2388 +       if (*i_acl != NFS4_ACL_NOT_CACHED)
2389 +               posix_acl_release(*i_acl);
2390 +       *i_acl = NFS4_ACL_NOT_CACHED;
2391 +       spin_unlock(&inode->i_lock);
2392 +}
2393 +
2394 +struct posix_acl *
2395 +nfs4_proc_get_posix_acl(struct inode *inode, int type)
2396 +{
2397 +       struct nfs4_acl *acl = NULL;
2398 +       int error;
2399 +       struct posix_acl *pacl, *dpacl, *ret = NULL;
2400 +       struct rpc_message msg = {
2401 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETACL],
2402 +               .rpc_argp = NFS_FH(inode),
2403 +               .rpc_resp = &acl,
2404 +       };
2405 +
2406 +       lock_kernel();
2407 +       error = nfs_revalidate_inode(NFS_SERVER(inode), inode);
2408 +       if (error < 0) {
2409 +               unlock_kernel();
2410 +               return ERR_PTR(error);
2411 +       }
2412 +       if (type == ACL_TYPE_ACCESS)
2413 +               ret = nfs4_iget_acl(inode, &NFS_I(inode)->acl);
2414 +       else
2415 +               ret = nfs4_iget_acl(inode, &NFS_I(inode)->default_acl);
2416 +
2417 +       if (ret != NFS4_ACL_NOT_CACHED) {
2418 +               if (ret == NULL)
2419 +                       ret = ERR_PTR(-ENODATA);
2420 +               unlock_kernel();
2421 +               return ret;
2422 +       }
2423 +
2424 +       error = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
2425 +       unlock_kernel();
2426 +
2427 +       if (error < 0)
2428 +               goto out_free;
2429 +
2430 +       error = -ENODATA;
2431 +       if (acl == NULL)
2432 +               goto out_free;
2433 +
2434 +       error = nfs4_acl_nfsv4_to_posix(&nfs4_idmapper, NFS_SERVER(inode)->nfs4_state, acl, &pacl, &dpacl);
2435 +       if (error < 0)
2436 +               goto out_free;
2437 +
2438 +       error = -ERANGE;
2439 +       if (pacl && pacl->a_count > NFS_ACL_MAX_ENTRIES)
2440 +               goto out_free;
2441 +       if (dpacl && dpacl->a_count > NFS_ACL_MAX_ENTRIES)
2442 +               goto out_free;
2443 +
2444 +       nfs4_iset_acl(inode, &NFS_I(inode)->acl, pacl);
2445 +       nfs4_iset_acl(inode, &NFS_I(inode)->default_acl, dpacl);
2446 +
2447 +       ret = (type == ACL_TYPE_ACCESS) ? pacl : dpacl;
2448 +       error = -ENODATA;
2449 +       if (ret == NULL)
2450 +               goto out_free;
2451 +       error = 0;
2452 +out_free:
2453 +       if (error < 0)
2454 +               ret = ERR_PTR(error);
2455 +       nfs4_acl_free(acl);
2456 +       return ret;
2457 +}
2458 +
2459 +int
2460 +nfs4_proc_set_posix_acl(struct inode *inode, int type, struct posix_acl *pacl)
2461 +{
2462 +       struct iattr ia;
2463 +       struct nfs4_acl *acl;
2464 +       struct nfs_fattr fattr;
2465 +       int error;
2466 +       struct nfs_setaclargs arg = {
2467 +               .fh             = NFS_FH(inode),
2468 +       };
2469 +       struct rpc_message msg = {
2470 +               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_SETACL],
2471 +               .rpc_argp       = &arg,
2472 +               .rpc_resp       = NULL,
2473 +       };
2474 +
2475 +       ia.ia_valid = 0;
2476 +        fattr.valid = 0;
2477 +
2478 +       if (pacl && pacl->a_count > NFS_ACL_MAX_ENTRIES)
2479 +               return -ERANGE;
2480 +
2481 +       if (type == ACL_TYPE_ACCESS)
2482 +               acl = nfs4_acl_posix_to_nfsv4(&nfs4_idmapper, NFS_SERVER(inode)->nfs4_state, pacl, NULL);
2483 +       else
2484 +               acl = nfs4_acl_posix_to_nfsv4(&nfs4_idmapper, NFS_SERVER(inode)->nfs4_state, NULL, pacl);
2485 +       if (IS_ERR(acl))
2486 +               return PTR_ERR(acl);
2487 +       arg.acl = acl;
2488 +
2489 +       lock_kernel();
2490 +       error = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0);
2491 +       unlock_kernel();
2492 +
2493 +       nfs4_acl_free(acl);
2494 +
2495 +       if (error)
2496 +               return error;
2497 +
2498 +       if (type == ACL_TYPE_ACCESS)
2499 +               nfs4_iset_acl(inode, &NFS_I(inode)->acl, pacl);
2500 +       else
2501 +               nfs4_iset_acl(inode, &NFS_I(inode)->default_acl, pacl);
2502 +
2503 +       if (type == ACL_TYPE_ACCESS)
2504 +               posix_acl_equiv_mode(pacl, &inode->i_mode);
2505 +
2506 +       return error;
2507 +}
2508 +
2509 +#endif /* CONFIG_NFS_V4_ACL */
2510 +
2511  static int
2512  nfs4_proc_lookup(struct inode *dir, struct qstr *name,
2513                  struct nfs_fh *fhandle, struct nfs_fattr *fattr)
2514  {
2515 -       struct nfs4_compound    compound;
2516 -       struct nfs4_op          ops[5];
2517 -       struct nfs_fattr        dir_attr;
2518 -       int                     status;
2519 -
2520 +       struct nfs_fattr       dir_attr;
2521 +       int                    status;
2522 +       struct nfs4_lookupargs args = {
2523 +               .dir_fh   = NFS_FH(dir),
2524 +               .name     = name,
2525 +       };
2526 +       struct nfs4_lookupres  res = {
2527 +               .server   = NFS_SERVER(dir),
2528 +               .dirattr  = &dir_attr,
2529 +               .fattr    = fattr,
2530 +               .fhandle  = fhandle,
2531 +       };
2532 +       struct rpc_message     msg = {
2533 +               .rpc_proc  = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
2534 +               .rpc_argp  = &args,
2535 +               .rpc_resp  = &res,
2536 +       };
2537 +       
2538         dir_attr.valid = 0;
2539         fattr->valid = 0;
2540         
2541         dprintk("NFS call  lookup %s\n", name->name);
2542 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "lookup");
2543 -       nfs4_setup_putfh(&compound, NFS_FH(dir));
2544 -       nfs4_setup_getattr(&compound, &dir_attr);
2545 -       nfs4_setup_lookup(&compound, name);
2546 -       nfs4_setup_getattr(&compound, fattr);
2547 -       nfs4_setup_getfh(&compound, fhandle);
2548 -       status = nfs4_call_compound(&compound, NULL, 0);
2549 +       status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
2550         dprintk("NFS reply lookup: %d\n", status);
2551  
2552         if (status >= 0)
2553 @@ -975,11 +864,24 @@ nfs4_proc_lookup(struct inode *dir, stru
2554  static int
2555  nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
2556  {
2557 -       struct nfs4_compound    compound;
2558 -       struct nfs4_op          ops[3];
2559         struct nfs_fattr        fattr;
2560         u32                     req_access = 0, resp_supported, resp_access;
2561         int                     status;
2562 +       struct nfs4_accessargs args = {
2563 +               .fhandle        = NFS_FH(inode),
2564 +       };
2565 +       struct nfs4_accessres res = {
2566 +               .server         = NFS_SERVER(inode),
2567 +               .fattr          = &fattr,
2568 +               .resp_supported  = &resp_supported,
2569 +               .resp_access    = &resp_access,
2570 +       };
2571 +       struct rpc_message msg = {
2572 +               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
2573 +               .rpc_argp       = &args,
2574 +               .rpc_resp       = &res,
2575 +               .rpc_cred       = cred,
2576 +       };
2577  
2578         fattr.valid = 0;
2579  
2580 @@ -1000,12 +902,9 @@ nfs4_proc_access(struct inode *inode, st
2581                 if (mode & MAY_EXEC)
2582                         req_access |= NFS4_ACCESS_EXECUTE;
2583         }
2584 +       res.req_access = args.req_access = req_access;
2585  
2586 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "access");
2587 -       nfs4_setup_putfh(&compound, NFS_FH(inode));
2588 -       nfs4_setup_getattr(&compound, &fattr);
2589 -       nfs4_setup_access(&compound, req_access, &resp_supported, &resp_access);
2590 -       status = nfs4_call_compound(&compound, cred, 0);
2591 +       status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
2592         nfs_refresh_inode(inode, &fattr);
2593  
2594         if (!status) {
2595 @@ -1046,13 +945,18 @@ nfs4_proc_access(struct inode *inode, st
2596  static int
2597  nfs4_proc_readlink(struct inode *inode, struct page *page)
2598  {
2599 -       struct nfs4_compound    compound;
2600 -       struct nfs4_op          ops[2];
2601 +       struct nfs4_readlink args = {
2602 +               .fh       = NFS_FH(inode),
2603 +               .count    = PAGE_CACHE_SIZE,
2604 +               .pages    = &page,
2605 +       };
2606 +       struct rpc_message msg = {
2607 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK],
2608 +               .rpc_argp = &args,
2609 +               .rpc_resp = NULL,
2610 +       };
2611  
2612 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "readlink");
2613 -       nfs4_setup_putfh(&compound, NFS_FH(inode));
2614 -       nfs4_setup_readlink(&compound, PAGE_CACHE_SIZE, &page);
2615 -       return nfs4_call_compound(&compound, NULL, 0);
2616 +       return rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
2617  }
2618  
2619  static int
2620 @@ -1088,12 +992,8 @@ nfs4_proc_read(struct nfs_read_data *rda
2621  
2622         fattr->valid = 0;
2623         status = rpc_call_sync(server->client, &msg, flags);
2624 -       if (!status) {
2625 +       if (!status)
2626                 renew_lease(server, timestamp);
2627 -               /* Check cache consistency */
2628 -               if (fattr->change_attr != NFS_CHANGE_ATTR(inode))
2629 -                       nfs_zap_caches(inode);
2630 -       }
2631         dprintk("NFS reply read: %d\n", status);
2632         return status;
2633  }
2634 @@ -1130,7 +1030,6 @@ nfs4_proc_write(struct nfs_write_data *w
2635  
2636         fattr->valid = 0;
2637         status = rpc_call_sync(server->client, &msg, rpcflags);
2638 -       NFS_CACHEINV(inode);
2639         dprintk("NFS reply write: %d\n", status);
2640         return status;
2641  }
2642 @@ -1217,18 +1116,26 @@ nfs4_proc_create(struct inode *dir, stru
2643  static int
2644  nfs4_proc_remove(struct inode *dir, struct qstr *name)
2645  {
2646 -       struct nfs4_compound    compound;
2647 -       struct nfs4_op          ops[3];
2648         struct nfs4_change_info dir_cinfo;
2649         struct nfs_fattr        dir_attr;
2650         int                     status;
2651 +       struct nfs4_remove_arg args = {
2652 +               .fhandle = NFS_FH(dir),
2653 +               .name = name,
2654 +       };
2655 +       struct nfs4_remove_res res = {
2656 +               .server = NFS_SERVER(dir),
2657 +               .dir_cinfo = &dir_cinfo,
2658 +               .dir_attr = &dir_attr,
2659 +       };
2660 +       struct rpc_message msg = {
2661 +               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
2662 +               .rpc_argp       = &args,
2663 +               .rpc_resp       = &res,
2664 +       };
2665  
2666         dir_attr.valid = 0;
2667 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "remove");
2668 -       nfs4_setup_putfh(&compound, NFS_FH(dir));
2669 -       nfs4_setup_remove(&compound, name, &dir_cinfo);
2670 -       nfs4_setup_getattr(&compound, &dir_attr);
2671 -       status = nfs4_call_compound(&compound, NULL, 0);
2672 +       status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
2673  
2674         if (!status) {
2675                 process_cinfo(&dir_cinfo, &dir_attr);
2676 @@ -1237,32 +1144,22 @@ nfs4_proc_remove(struct inode *dir, stru
2677         return status;
2678  }
2679  
2680 -struct unlink_desc {
2681 -       struct nfs4_compound    compound;
2682 -       struct nfs4_op          ops[3];
2683 -       struct nfs4_change_info cinfo;
2684 -       struct nfs_fattr        attrs;
2685 -};
2686 -
2687  static int
2688  nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
2689  {
2690 -       struct unlink_desc *    up;
2691 -       struct nfs4_compound *  cp;
2692 +       struct nfs4_unlink *up;
2693  
2694 -       up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL);
2695 +       up = (struct nfs4_unlink *) kmalloc(sizeof(*up), GFP_KERNEL);
2696         if (!up)
2697                 return -ENOMEM;
2698 -       cp = &up->compound;
2699         
2700 -       nfs4_setup_compound(cp, up->ops, NFS_SERVER(dir->d_inode), "unlink_setup");
2701 -       nfs4_setup_putfh(cp, NFS_FH(dir->d_inode));
2702 -       nfs4_setup_remove(cp, name, &up->cinfo);
2703 -       nfs4_setup_getattr(cp, &up->attrs);
2704 -       
2705 -       msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND];
2706 -       msg->rpc_argp = cp;
2707 -       msg->rpc_resp = cp;
2708 +       up->server = NFS_SERVER(dir->d_inode);
2709 +       up->fh     = NFS_FH(dir->d_inode);
2710 +       up->name   = name;
2711 +       
2712 +       msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_UNLINK];
2713 +       msg->rpc_argp = up;
2714 +       msg->rpc_resp = up;
2715         return 0;
2716  }
2717  
2718 @@ -1270,11 +1167,10 @@ static int
2719  nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
2720  {
2721         struct rpc_message *msg = &task->tk_msg;
2722 -       struct unlink_desc *up;
2723 +       struct nfs4_unlink *up;
2724         
2725         if (msg->rpc_argp) {
2726 -               up = (struct unlink_desc *) msg->rpc_argp;
2727 -               process_lease(&up->compound);
2728 +               up = (struct nfs4_unlink *) msg->rpc_argp;
2729                 process_cinfo(&up->cinfo, &up->attrs);
2730                 nfs_refresh_inode(dir->d_inode, &up->attrs);
2731                 kfree(up);
2732 @@ -1287,24 +1183,32 @@ static int
2733  nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
2734                  struct inode *new_dir, struct qstr *new_name)
2735  {
2736 -       struct nfs4_compound    compound;
2737 -       struct nfs4_op          ops[7];
2738         struct nfs4_change_info old_cinfo, new_cinfo;
2739         struct nfs_fattr        old_dir_attr, new_dir_attr;
2740         int                     status;
2741 -
2742 +       struct nfs4_rename_arg arg = {
2743 +               .old_dir = NFS_FH(old_dir),
2744 +               .new_dir = NFS_FH(new_dir),
2745 +               .old_name = old_name,
2746 +               .new_name = new_name,
2747 +       };
2748 +       struct nfs4_rename_res res = {
2749 +               .server = NFS_SERVER(old_dir),
2750 +               .old_cinfo = &old_cinfo,
2751 +               .new_cinfo = &new_cinfo,
2752 +               .old_fattr = &old_dir_attr,
2753 +               .new_fattr = &new_dir_attr,
2754 +       };
2755 +        struct rpc_message msg = {
2756 +                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_RENAME],
2757 +                .rpc_argp       = &arg,
2758 +                .rpc_resp       = &res,
2759 +        };
2760 +       
2761         old_dir_attr.valid = 0;
2762         new_dir_attr.valid = 0;
2763         
2764 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(old_dir), "rename");
2765 -       nfs4_setup_putfh(&compound, NFS_FH(old_dir));
2766 -       nfs4_setup_savefh(&compound);
2767 -       nfs4_setup_putfh(&compound, NFS_FH(new_dir));
2768 -       nfs4_setup_rename(&compound, old_name, new_name, &old_cinfo, &new_cinfo);
2769 -       nfs4_setup_getattr(&compound, &new_dir_attr);
2770 -       nfs4_setup_restorefh(&compound);
2771 -       nfs4_setup_getattr(&compound, &old_dir_attr);
2772 -       status = nfs4_call_compound(&compound, NULL, 0);
2773 +       status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
2774  
2775         if (!status) {
2776                 process_cinfo(&old_cinfo, &old_dir_attr);
2777 @@ -1318,24 +1222,30 @@ nfs4_proc_rename(struct inode *old_dir, 
2778  static int
2779  nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
2780  {
2781 -       struct nfs4_compound    compound;
2782 -       struct nfs4_op          ops[7];
2783         struct nfs4_change_info dir_cinfo;
2784         struct nfs_fattr        dir_attr, fattr;
2785         int                     status;
2786 -       
2787 +       struct nfs4_link_arg arg = {
2788 +               .fh     = NFS_FH(inode),
2789 +               .dir_fh = NFS_FH(dir),
2790 +               .name   = name,
2791 +       };
2792 +       struct nfs4_link_res res = {
2793 +               .server    = NFS_SERVER(inode),
2794 +               .fattr     = &fattr,
2795 +               .dir_attr  = &dir_attr,
2796 +               .dir_cinfo = &dir_cinfo,
2797 +       };
2798 +        struct rpc_message msg = {
2799 +                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_LINK],
2800 +                .rpc_argp       = &arg,
2801 +                .rpc_resp       = &res,
2802 +        };
2803 +
2804         dir_attr.valid = 0;
2805         fattr.valid = 0;
2806         
2807 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(inode), "link");
2808 -       nfs4_setup_putfh(&compound, NFS_FH(inode));
2809 -       nfs4_setup_savefh(&compound);
2810 -       nfs4_setup_putfh(&compound, NFS_FH(dir));
2811 -       nfs4_setup_link(&compound, name, &dir_cinfo);
2812 -       nfs4_setup_getattr(&compound, &dir_attr);
2813 -       nfs4_setup_restorefh(&compound);
2814 -       nfs4_setup_getattr(&compound, &fattr);
2815 -       status = nfs4_call_compound(&compound, NULL, 0);
2816 +       status = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
2817  
2818         if (!status) {
2819                 process_cinfo(&dir_cinfo, &dir_attr);
2820 @@ -1350,24 +1260,34 @@ nfs4_proc_symlink(struct inode *dir, str
2821                   struct iattr *sattr, struct nfs_fh *fhandle,
2822                   struct nfs_fattr *fattr)
2823  {
2824 -       struct nfs4_compound    compound;
2825 -       struct nfs4_op          ops[7];
2826         struct nfs_fattr        dir_attr;
2827         struct nfs4_change_info dir_cinfo;
2828         int                     status;
2829 +       struct nfs4_create_arg arg = {
2830 +               .dir_fh = NFS_FH(dir),
2831 +               .server = NFS_SERVER(dir),
2832 +               .name = name,
2833 +               .u.symlink = path,
2834 +               .attrs = sattr,
2835 +               .ftype = NF4LNK,
2836 +       };
2837 +       struct nfs4_create_res res = {
2838 +               .server = NFS_SERVER(dir),
2839 +               .fhandle = fhandle,
2840 +               .fattr = fattr,
2841 +               .dir_attr = &dir_attr,
2842 +               .dir_cinfo = &dir_cinfo,
2843 +       };
2844 +        struct rpc_message msg = {
2845 +                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
2846 +                .rpc_argp       = &arg,
2847 +                .rpc_resp       = &res,
2848 +        };
2849  
2850         dir_attr.valid = 0;
2851         fattr->valid = 0;
2852         
2853 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "symlink");
2854 -       nfs4_setup_putfh(&compound, NFS_FH(dir));
2855 -       nfs4_setup_savefh(&compound);
2856 -       nfs4_setup_create_symlink(&compound, name, path, sattr, &dir_cinfo);
2857 -       nfs4_setup_getattr(&compound, fattr);
2858 -       nfs4_setup_getfh(&compound, fhandle);
2859 -       nfs4_setup_restorefh(&compound);
2860 -       nfs4_setup_getattr(&compound, &dir_attr);
2861 -       status = nfs4_call_compound(&compound, NULL, 0);
2862 +       status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
2863  
2864         if (!status) {
2865                 process_cinfo(&dir_cinfo, &dir_attr);
2866 @@ -1380,24 +1300,33 @@ static int
2867  nfs4_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
2868                 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
2869  {
2870 -       struct nfs4_compound    compound;
2871 -       struct nfs4_op          ops[7];
2872         struct nfs_fattr        dir_attr;
2873         struct nfs4_change_info dir_cinfo;
2874         int                     status;
2875 +       struct nfs4_create_arg arg = {
2876 +               .dir_fh = NFS_FH(dir),
2877 +               .server = NFS_SERVER(dir),
2878 +               .name = name,
2879 +               .attrs = sattr,
2880 +               .ftype = NF4DIR,
2881 +       };
2882 +       struct nfs4_create_res res = {
2883 +               .server = NFS_SERVER(dir),
2884 +               .fhandle = fhandle,
2885 +               .fattr = fattr,
2886 +               .dir_attr = &dir_attr,
2887 +               .dir_cinfo = &dir_cinfo,
2888 +       };
2889 +        struct rpc_message msg = {
2890 +                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
2891 +                .rpc_argp       = &arg,
2892 +                .rpc_resp       = &res,
2893 +        };
2894  
2895         dir_attr.valid = 0;
2896         fattr->valid = 0;
2897         
2898 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mkdir");
2899 -       nfs4_setup_putfh(&compound, NFS_FH(dir));
2900 -       nfs4_setup_savefh(&compound);
2901 -       nfs4_setup_create_dir(&compound, name, sattr, &dir_cinfo);
2902 -       nfs4_setup_getattr(&compound, fattr);
2903 -       nfs4_setup_getfh(&compound, fhandle);
2904 -       nfs4_setup_restorefh(&compound);
2905 -       nfs4_setup_getattr(&compound, &dir_attr);
2906 -       status = nfs4_call_compound(&compound, NULL, 0);
2907 +       status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
2908  
2909         if (!status) {
2910                 process_cinfo(&dir_cinfo, &dir_attr);
2911 @@ -1411,17 +1340,25 @@ nfs4_proc_readdir(struct dentry *dentry,
2912                    u64 cookie, struct page *page, unsigned int count, int plus)
2913  {
2914         struct inode            *dir = dentry->d_inode;
2915 -       struct nfs4_compound    compound;
2916 -       struct nfs4_op          ops[2];
2917         int                     status;
2918 +       struct nfs4_readdir_arg args = {
2919 +               .fh = NFS_FH(dir),
2920 +               .pages = &page,
2921 +               .pgbase = 0,
2922 +               .count = count,
2923 +       };
2924 +       struct nfs4_readdir_res res;
2925 +       struct rpc_message msg = {
2926 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
2927 +               .rpc_argp = &args,
2928 +               .rpc_resp = &res,
2929 +               .rpc_cred = cred,
2930 +       };
2931  
2932         lock_kernel();
2933 -
2934 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "readdir");
2935 -       nfs4_setup_putfh(&compound, NFS_FH(dir));
2936 -       nfs4_setup_readdir(&compound, cookie, NFS_COOKIEVERF(dir), &page, count, dentry);
2937 -       status = nfs4_call_compound(&compound, cred, 0);
2938 -
2939 +       nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
2940 +       res.pgbase = args.pgbase;
2941 +       status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
2942         unlock_kernel();
2943         return status;
2944  }
2945 @@ -1430,24 +1367,50 @@ static int
2946  nfs4_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
2947                 dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
2948  {
2949 -       struct nfs4_compound    compound;
2950 -       struct nfs4_op          ops[7];
2951         struct nfs_fattr        dir_attr;
2952         struct nfs4_change_info dir_cinfo;
2953         int                     status;
2954 +       int                     mode = sattr->ia_mode;
2955 +       struct nfs4_create_arg arg = {
2956 +               .dir_fh = NFS_FH(dir),
2957 +               .server = NFS_SERVER(dir),
2958 +               .name = name,
2959 +               .attrs = sattr,
2960 +       };
2961 +       struct nfs4_create_res res = {
2962 +               .server = NFS_SERVER(dir),
2963 +               .fhandle = fh,
2964 +               .fattr = fattr,
2965 +               .dir_attr = &dir_attr,
2966 +               .dir_cinfo = &dir_cinfo,
2967 +       };
2968 +        struct rpc_message msg = {
2969 +                .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
2970 +                .rpc_argp       = &arg,
2971 +                .rpc_resp       = &res,
2972 +        };
2973  
2974         dir_attr.valid = 0;
2975         fattr->valid = 0;
2976 +
2977 +       BUG_ON(!(sattr->ia_valid & ATTR_MODE));
2978 +       BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
2979 +       if (S_ISFIFO(mode))
2980 +               arg.ftype = NF4FIFO;
2981 +       else if (S_ISBLK(mode)) {
2982 +               arg.ftype = NF4BLK;
2983 +               arg.u.device.specdata1 = MAJOR(rdev);
2984 +               arg.u.device.specdata2 = MINOR(rdev);
2985 +       }
2986 +       else if (S_ISCHR(mode)) {
2987 +               arg.ftype = NF4CHR;
2988 +               arg.u.device.specdata1 = MAJOR(rdev);
2989 +               arg.u.device.specdata2 = MINOR(rdev);
2990 +       }
2991 +       else
2992 +               arg.ftype = NF4SOCK;
2993         
2994 -       nfs4_setup_compound(&compound, ops, NFS_SERVER(dir), "mknod");
2995 -       nfs4_setup_putfh(&compound, NFS_FH(dir));
2996 -       nfs4_setup_savefh(&compound);
2997 -       nfs4_setup_create_special(&compound, name, rdev,sattr, &dir_cinfo);
2998 -       nfs4_setup_getattr(&compound, fattr);
2999 -       nfs4_setup_getfh(&compound, fh);
3000 -       nfs4_setup_restorefh(&compound);
3001 -       nfs4_setup_getattr(&compound, &dir_attr);
3002 -       status = nfs4_call_compound(&compound, NULL, 0);
3003 +       status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
3004  
3005         if (!status) {
3006                 process_cinfo(&dir_cinfo, &dir_attr);
3007 @@ -1460,14 +1423,13 @@ static int
3008  nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
3009                  struct nfs_fsstat *fsstat)
3010  {
3011 -       struct nfs4_compound compound;
3012 -       struct nfs4_op ops[2];
3013 +       struct rpc_message msg = {
3014 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_STATFS],
3015 +               .rpc_argp = fhandle,
3016 +               .rpc_resp = fsstat,
3017 +       };
3018  
3019 -       memset(fsstat, 0, sizeof(*fsstat));
3020 -       nfs4_setup_compound(&compound, ops, server, "statfs");
3021 -       nfs4_setup_putfh(&compound, fhandle);
3022 -       nfs4_setup_statfs(&compound, fsstat);
3023 -       return nfs4_call_compound(&compound, NULL, 0);
3024 +       return rpc_call_sync(server->client, &msg, 0);
3025  }
3026  
3027  static int
3028 @@ -1480,7 +1442,6 @@ nfs4_proc_fsinfo(struct nfs_server *serv
3029                 .rpc_resp = fsinfo,
3030         };
3031  
3032 -       memset(fsinfo, 0, sizeof(*fsinfo));
3033         return rpc_call_sync(server->client, &msg, 0);
3034  }
3035  
3036 @@ -1488,14 +1449,13 @@ static int
3037  nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
3038                    struct nfs_pathconf *pathconf)
3039  {
3040 -       struct nfs4_compound compound;
3041 -       struct nfs4_op ops[2];
3042 +       struct rpc_message msg = {
3043 +               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_PATHCONF],
3044 +               .rpc_argp = fhandle,
3045 +               .rpc_resp = pathconf,
3046 +       };
3047  
3048 -       memset(pathconf, 0, sizeof(*pathconf));
3049 -       nfs4_setup_compound(&compound, ops, server, "statfs");
3050 -       nfs4_setup_putfh(&compound, fhandle);
3051 -       nfs4_setup_pathconf(&compound, pathconf);
3052 -       return nfs4_call_compound(&compound, NULL, 0);
3053 +       return rpc_call_sync(server->client, &msg, 0);
3054  }
3055  
3056  static void
3057 @@ -1517,7 +1477,6 @@ nfs4_read_done(struct rpc_task *task)
3058  {
3059         struct nfs_read_data *data = (struct nfs_read_data *) task->tk_calldata;
3060         struct inode *inode = data->inode;
3061 -       struct nfs_fattr *fattr = data->res.fattr;
3062  
3063         if (nfs4_async_handle_error(task, NFS_SERVER(inode)) == -EAGAIN) {
3064                 task->tk_action = nfs4_restart_read;
3065 @@ -1525,11 +1484,6 @@ nfs4_read_done(struct rpc_task *task)
3066         }
3067         if (task->tk_status > 0)
3068                 renew_lease(NFS_SERVER(inode), data->timestamp);
3069 -       /* Check cache consistency */
3070 -       if (fattr->change_attr != NFS_CHANGE_ATTR(inode))
3071 -               nfs_zap_caches(inode);
3072 -       if (fattr->bitmap[1] & FATTR4_WORD1_TIME_ACCESS)
3073 -               inode->i_atime = fattr->atime;
3074         /* Call back common NFS readpage processing */
3075         nfs_readpage_result(task);
3076  }
3077 @@ -1577,21 +1531,6 @@ nfs4_proc_read_setup(struct nfs_read_dat
3078  }
3079  
3080  static void
3081 -nfs4_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
3082 -{
3083 -       /* Check cache consistency */
3084 -       if (fattr->pre_change_attr != NFS_CHANGE_ATTR(inode))
3085 -               nfs_zap_caches(inode);
3086 -       NFS_CHANGE_ATTR(inode) = fattr->change_attr;
3087 -       if (fattr->bitmap[1] & FATTR4_WORD1_SPACE_USED)
3088 -               inode->i_blocks = (fattr->du.nfs3.used + 511) >> 9;
3089 -       if (fattr->bitmap[1] & FATTR4_WORD1_TIME_METADATA)
3090 -               inode->i_ctime = fattr->ctime;
3091 -       if (fattr->bitmap[1] & FATTR4_WORD1_TIME_MODIFY)
3092 -               inode->i_mtime = fattr->mtime;
3093 -}
3094 -
3095 -static void
3096  nfs4_restart_write(struct rpc_task *task)
3097  {
3098         struct nfs_write_data *data = (struct nfs_write_data *)task->tk_calldata;
3099 @@ -1617,7 +1556,6 @@ nfs4_write_done(struct rpc_task *task)
3100         }
3101         if (task->tk_status >= 0)
3102                 renew_lease(NFS_SERVER(inode), data->timestamp);
3103 -       nfs4_write_refresh_inode(inode, data->res.fattr);
3104         /* Call back common NFS writeback processing */
3105         nfs_writeback_done(task);
3106  }
3107 @@ -1684,7 +1622,6 @@ nfs4_commit_done(struct rpc_task *task)
3108                 task->tk_action = nfs4_restart_write;
3109                 return;
3110         }
3111 -       nfs4_write_refresh_inode(inode, data->res.fattr);
3112         /* Call back common NFS writeback processing */
3113         nfs_commit_done(task);
3114  }
3115 @@ -1807,6 +1744,7 @@ nfs4_proc_file_open(struct inode *inode,
3116         if (filp->f_mode & FMODE_WRITE) {
3117                 lock_kernel();
3118                 nfs_set_mmcred(inode, state->owner->so_cred);
3119 +               nfs_begin_data_update(inode);
3120                 unlock_kernel();
3121         }
3122         filp->private_data = state;
3123 @@ -1823,6 +1761,11 @@ nfs4_proc_file_release(struct inode *ino
3124  
3125         if (state)
3126                 nfs4_close_state(state, filp->f_mode);
3127 +       if (filp->f_mode & FMODE_WRITE) {
3128 +               lock_kernel();
3129 +               nfs_end_data_update(inode);
3130 +               unlock_kernel();
3131 +       }
3132         return 0;
3133  }
3134  
3135 @@ -2294,6 +2237,7 @@ struct nfs_rpc_ops        nfs_v4_clientops = {
3136         .version        = 4,                    /* protocol version */
3137         .dentry_ops     = &nfs4_dentry_operations,
3138         .dir_inode_ops  = &nfs4_dir_inode_operations,
3139 +       .file_inode_ops = &nfs4_file_inode_operations,
3140         .getroot        = nfs4_proc_get_root,
3141         .getattr        = nfs4_proc_getattr,
3142         .setattr        = nfs4_proc_setattr,
3143 diff -puN fs/nfs/pagelist.c~CITI_NFS4_ALL fs/nfs/pagelist.c
3144 --- linux-2.6.3/fs/nfs/pagelist.c~CITI_NFS4_ALL 2004-02-19 16:47:03.000000000 -0500
3145 +++ linux-2.6.3-bfields/fs/nfs/pagelist.c       2004-02-19 16:47:03.000000000 -0500
3146 @@ -246,7 +246,6 @@ nfs_coalesce_requests(struct list_head *
3147   * nfs_scan_list - Scan a list for matching requests
3148   * @head: One of the NFS inode request lists
3149   * @dst: Destination list
3150 - * @file: if set, ensure we match requests from this file
3151   * @idx_start: lower bound of page->index to scan
3152   * @npages: idx_start + npages sets the upper bound to scan.
3153   *
3154 @@ -258,7 +257,6 @@ nfs_coalesce_requests(struct list_head *
3155   */
3156  int
3157  nfs_scan_list(struct list_head *head, struct list_head *dst,
3158 -             struct file *file,
3159               unsigned long idx_start, unsigned int npages)
3160  {
3161         struct list_head        *pos, *tmp;
3162 @@ -276,9 +274,6 @@ nfs_scan_list(struct list_head *head, st
3163  
3164                 req = nfs_list_entry(pos);
3165  
3166 -               if (file && req->wb_file != file)
3167 -                       continue;
3168 -
3169                 if (req->wb_index < idx_start)
3170                         continue;
3171                 if (req->wb_index > idx_end)
3172 diff -puN fs/nfs/proc.c~CITI_NFS4_ALL fs/nfs/proc.c
3173 --- linux-2.6.3/fs/nfs/proc.c~CITI_NFS4_ALL     2004-02-19 16:47:03.000000000 -0500
3174 +++ linux-2.6.3-bfields/fs/nfs/proc.c   2004-02-19 16:47:07.000000000 -0500
3175 @@ -49,18 +49,6 @@
3176  
3177  extern struct rpc_procinfo nfs_procedures[];
3178  
3179 -static void
3180 -nfs_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
3181 -{
3182 -       if (!(fattr->valid & NFS_ATTR_WCC)) {
3183 -               fattr->pre_size  = NFS_CACHE_ISIZE(inode);
3184 -               fattr->pre_mtime = NFS_CACHE_MTIME(inode);
3185 -               fattr->pre_ctime = NFS_CACHE_CTIME(inode);
3186 -               fattr->valid |= NFS_ATTR_WCC;
3187 -       }
3188 -       nfs_refresh_inode(inode, fattr);
3189 -}
3190 -
3191  static struct rpc_cred *
3192  nfs_cred(struct inode *inode, struct file *filp)
3193  {
3194 @@ -78,15 +66,33 @@ nfs_cred(struct inode *inode, struct fil
3195   */
3196  static int
3197  nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
3198 -                 struct nfs_fattr *fattr)
3199 +                 struct nfs_fsinfo *info)
3200  {
3201 -       int             status;
3202 +       struct nfs_fattr *fattr = info->fattr;
3203 +       struct nfs2_fsstat fsinfo;
3204 +       int status;
3205  
3206 -       dprintk("NFS call  getroot\n");
3207 +       dprintk("%s: call getattr\n", __FUNCTION__);
3208         fattr->valid = 0;
3209 -       status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
3210 -       dprintk("NFS reply getroot\n");
3211 -       return status;
3212 +       status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0);
3213 +       dprintk("%s: reply getattr %d\n", __FUNCTION__, status);
3214 +       if (status)
3215 +               return status;
3216 +       dprintk("%s: call statfs\n", __FUNCTION__);
3217 +       status = rpc_call(server->client_sys, NFSPROC_STATFS, fhandle, &fsinfo, 0);
3218 +       dprintk("%s: reply statfs %d\n", __FUNCTION__, status);
3219 +       if (status)
3220 +               return status;
3221 +       info->rtmax  = NFS_MAXDATA;
3222 +       info->rtpref = fsinfo.tsize;
3223 +       info->rtmult = fsinfo.bsize;
3224 +       info->wtmax  = NFS_MAXDATA;
3225 +       info->wtpref = fsinfo.tsize;
3226 +       info->wtmult = fsinfo.bsize;
3227 +       info->dtpref = fsinfo.tsize;
3228 +       info->maxfilesize = 0x7FFFFFFF;
3229 +       info->lease_time = 0;
3230 +       return 0;
3231  }
3232  
3233  /*
3234 @@ -205,7 +211,7 @@ nfs_proc_write(struct nfs_write_data *wd
3235         msg.rpc_cred = nfs_cred(inode, filp);
3236         status = rpc_call_sync(NFS_CLIENT(inode), &msg, flags);
3237         if (status >= 0) {
3238 -               nfs_write_refresh_inode(inode, fattr);
3239 +               nfs_refresh_inode(inode, fattr);
3240                 wdata->res.count = wdata->args.count;
3241                 wdata->verf.committed = NFS_FILE_SYNC;
3242         }
3243 @@ -331,10 +337,8 @@ nfs_proc_unlink_done(struct dentry *dir,
3244  {
3245         struct rpc_message *msg = &task->tk_msg;
3246         
3247 -       if (msg->rpc_argp) {
3248 -               NFS_CACHEINV(dir->d_inode);
3249 +       if (msg->rpc_argp)
3250                 kfree(msg->rpc_argp);
3251 -       }
3252         return 0;
3253  }
3254  
3255 @@ -584,7 +588,7 @@ nfs_write_done(struct rpc_task *task)
3256         struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
3257  
3258         if (task->tk_status >= 0)
3259 -               nfs_write_refresh_inode(data->inode, data->res.fattr);
3260 +               nfs_refresh_inode(data->inode, data->res.fattr);
3261         nfs_writeback_done(task);
3262  }
3263  
3264 @@ -665,6 +669,7 @@ struct nfs_rpc_ops  nfs_v2_clientops = {
3265         .version        = 2,                   /* protocol version */
3266         .dentry_ops     = &nfs_dentry_operations,
3267         .dir_inode_ops  = &nfs_dir_inode_operations,
3268 +       .file_inode_ops = &nfs_file_inode_operations,
3269         .getroot        = nfs_proc_get_root,
3270         .getattr        = nfs_proc_getattr,
3271         .setattr        = nfs_proc_setattr,
3272 diff -puN fs/nfs/read.c~CITI_NFS4_ALL fs/nfs/read.c
3273 --- linux-2.6.3/fs/nfs/read.c~CITI_NFS4_ALL     2004-02-19 16:47:03.000000000 -0500
3274 +++ linux-2.6.3-bfields/fs/nfs/read.c   2004-02-19 16:47:03.000000000 -0500
3275 @@ -124,6 +124,7 @@ nfs_readpage_sync(struct file *file, str
3276                 if (result < rdata.args.count)  /* NFSv2ism */
3277                         break;
3278         } while (count);
3279 +       NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
3280  
3281         if (count)
3282                 memclear_highpage_flush(page, rdata.args.pgbase, count);
3283 @@ -266,6 +267,7 @@ nfs_readpage_result(struct rpc_task *tas
3284         dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
3285                 task->tk_pid, task->tk_status);
3286  
3287 +       NFS_FLAGS(data->inode) |= NFS_INO_INVALID_ATIME;
3288         while (!list_empty(&data->pages)) {
3289                 struct nfs_page *req = nfs_list_entry(data->pages.next);
3290                 struct page *page = req->wb_page;
3291 diff -puN fs/nfs/unlink.c~CITI_NFS4_ALL fs/nfs/unlink.c
3292 --- linux-2.6.3/fs/nfs/unlink.c~CITI_NFS4_ALL   2004-02-19 16:47:03.000000000 -0500
3293 +++ linux-2.6.3-bfields/fs/nfs/unlink.c 2004-02-19 16:47:03.000000000 -0500
3294 @@ -104,6 +104,7 @@ nfs_async_unlink_init(struct rpc_task *t
3295         status = NFS_PROTO(dir->d_inode)->unlink_setup(&msg, dir, &data->name);
3296         if (status < 0)
3297                 goto out_err;
3298 +       nfs_begin_data_update(dir->d_inode);
3299         rpc_call_setup(task, &msg, 0);
3300         return;
3301   out_err:
3302 @@ -126,7 +127,7 @@ nfs_async_unlink_done(struct rpc_task *t
3303         if (!dir)
3304                 return;
3305         dir_i = dir->d_inode;
3306 -       nfs_zap_caches(dir_i);
3307 +       nfs_end_data_update(dir_i);
3308         if (NFS_PROTO(dir_i)->unlink_done(dir, task))
3309                 return;
3310         put_rpccred(data->cred);
3311 diff -puN fs/nfs/write.c~CITI_NFS4_ALL fs/nfs/write.c
3312 --- linux-2.6.3/fs/nfs/write.c~CITI_NFS4_ALL    2004-02-19 16:47:03.000000000 -0500
3313 +++ linux-2.6.3-bfields/fs/nfs/write.c  2004-02-19 16:47:03.000000000 -0500
3314 @@ -74,7 +74,6 @@
3315  static struct nfs_page * nfs_update_request(struct file*, struct inode *,
3316                                             struct page *,
3317                                             unsigned int, unsigned int);
3318 -static void    nfs_strategy(struct inode *inode);
3319  
3320  static kmem_cache_t *nfs_wdata_cachep;
3321  static mempool_t *nfs_wdata_mempool;
3322 @@ -124,6 +123,52 @@ void nfs_commit_release(struct rpc_task 
3323         nfs_commit_free(wdata);
3324  }
3325  
3326 +/* Adjust the file length if we're writing beyond the end */
3327 +static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)
3328 +{
3329 +       struct inode *inode = page->mapping->host;
3330 +       loff_t end, i_size = i_size_read(inode);
3331 +       unsigned long end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
3332 +
3333 +       if (i_size > 0 && page->index < end_index)
3334 +               return;
3335 +       end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count);
3336 +       if (i_size >= end)
3337 +               return;
3338 +       i_size_write(inode, end);
3339 +}
3340 +
3341 +/* We can set the PG_uptodate flag if we see that a write request
3342 + * covers the full page.
3343 + */
3344 +static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count)
3345 +{
3346 +       loff_t end_offs;
3347 +
3348 +       if (PageUptodate(page))
3349 +               return;
3350 +       if (base != 0)
3351 +               return;
3352 +       if (count == PAGE_CACHE_SIZE) {
3353 +               SetPageUptodate(page);
3354 +               return;
3355 +       }
3356 +
3357 +       end_offs = i_size_read(page->mapping->host) - 1;
3358 +       if (end_offs < 0)
3359 +               return;
3360 +       /* Is this the last page? */
3361 +       if (page->index != (unsigned long)(end_offs >> PAGE_CACHE_SHIFT))
3362 +               return;
3363 +       /* This is the last page: set PG_uptodate if we cover the entire
3364 +        * extent of the data, then zero the rest of the page.
3365 +        */
3366 +       if (count == (unsigned int)(end_offs & (PAGE_CACHE_SIZE - 1)) + 1) {
3367 +               memclear_highpage_flush(page, count, PAGE_CACHE_SIZE - count);
3368 +               SetPageUptodate(page);
3369 +       }
3370 +}
3371 +
3372  /*
3373   * Write a page synchronously.
3374   * Offset is the data offset within the page.
3375 @@ -157,6 +202,7 @@ nfs_writepage_sync(struct file *file, st
3376                 (long long)NFS_FILEID(inode),
3377                 count, (long long)(page_offset(page) + offset));
3378  
3379 +       nfs_begin_data_update(inode);
3380         do {
3381                 if (count < wsize && !swapfile)
3382                         wdata.args.count = count;
3383 @@ -177,14 +223,12 @@ nfs_writepage_sync(struct file *file, st
3384                 wdata.args.pgbase += result;
3385                 written += result;
3386                 count -= result;
3387 -
3388 -               /*
3389 -                * If we've extended the file, update the inode
3390 -                * now so we don't invalidate the cache.
3391 -                */
3392 -               if (wdata.args.offset > i_size_read(inode))
3393 -                       i_size_write(inode, wdata.args.offset);
3394         } while (count);
3395 +       /* Update file length */
3396 +       nfs_grow_file(page, offset, written);
3397 +       /* Set the PG_uptodate flag? */
3398 +       nfs_mark_uptodate(page, offset, written);
3399 +       nfs_end_data_update(inode);
3400  
3401         if (PageError(page))
3402                 ClearPageError(page);
3403 @@ -201,18 +245,19 @@ nfs_writepage_async(struct file *file, s
3404                     unsigned int offset, unsigned int count)
3405  {
3406         struct nfs_page *req;
3407 -       loff_t          end;
3408         int             status;
3409  
3410 +       nfs_begin_data_update(inode);
3411         req = nfs_update_request(file, inode, page, offset, count);
3412         status = (IS_ERR(req)) ? PTR_ERR(req) : 0;
3413         if (status < 0)
3414                 goto out;
3415 +       /* Update file length */
3416 +       nfs_grow_file(page, offset, count);
3417 +       /* Set the PG_uptodate flag? */
3418 +       nfs_mark_uptodate(page, offset, count);
3419         nfs_unlock_request(req);
3420 -       nfs_strategy(inode);
3421 -       end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count);
3422 -       if (i_size_read(inode) < end)
3423 -               i_size_write(inode, end);
3424 +       nfs_end_data_update(inode);
3425  
3426   out:
3427         return status;
3428 @@ -286,7 +331,7 @@ nfs_writepages(struct address_space *map
3429         err = generic_writepages(mapping, wbc);
3430         if (err)
3431                 goto out;
3432 -       err = nfs_flush_file(inode, NULL, 0, 0, 0);
3433 +       err = nfs_flush_inode(inode, 0, 0, 0);
3434         if (err < 0)
3435                 goto out;
3436         if (wbc->sync_mode == WB_SYNC_HOLD)
3437 @@ -294,7 +339,7 @@ nfs_writepages(struct address_space *map
3438         if (is_sync && wbc->sync_mode == WB_SYNC_ALL) {
3439                 err = nfs_wb_all(inode);
3440         } else
3441 -               nfs_commit_file(inode, NULL, 0, 0, 0);
3442 +               nfs_commit_inode(inode, 0, 0, 0);
3443  out:
3444         return err;
3445  }
3446 @@ -312,8 +357,10 @@ nfs_inode_add_request(struct inode *inod
3447         BUG_ON(error == -EEXIST);
3448         if (error)
3449                 return error;
3450 -       if (!nfsi->npages)
3451 +       if (!nfsi->npages) {
3452                 igrab(inode);
3453 +               nfs_begin_data_update(inode);
3454 +       }
3455         nfsi->npages++;
3456         req->wb_count++;
3457         return 0;
3458 @@ -336,6 +383,7 @@ nfs_inode_remove_request(struct nfs_page
3459         nfsi->npages--;
3460         if (!nfsi->npages) {
3461                 spin_unlock(&nfs_wreq_lock);
3462 +               nfs_end_data_update(inode);
3463                 iput(inode);
3464         } else
3465                 spin_unlock(&nfs_wreq_lock);
3466 @@ -421,7 +469,7 @@ nfs_mark_request_commit(struct nfs_page 
3467   * Interruptible by signals only if mounted with intr flag.
3468   */
3469  static int
3470 -nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages)
3471 +nfs_wait_on_requests(struct inode *inode, unsigned long idx_start, unsigned int npages)
3472  {
3473         struct nfs_inode *nfsi = NFS_I(inode);
3474         struct nfs_page *req;
3475 @@ -441,8 +489,6 @@ nfs_wait_on_requests(struct inode *inode
3476                         break;
3477  
3478                 next = req->wb_index + 1;
3479 -               if (file && req->wb_file != file)
3480 -                       continue;
3481                 if (!NFS_WBACK_BUSY(req))
3482                         continue;
3483  
3484 @@ -453,7 +499,6 @@ nfs_wait_on_requests(struct inode *inode
3485                 if (error < 0)
3486                         return error;
3487                 spin_lock(&nfs_wreq_lock);
3488 -               next = idx_start;
3489                 res++;
3490         }
3491         spin_unlock(&nfs_wreq_lock);
3492 @@ -464,7 +509,6 @@ nfs_wait_on_requests(struct inode *inode
3493   * nfs_scan_dirty - Scan an inode for dirty requests
3494   * @inode: NFS inode to scan
3495   * @dst: destination list
3496 - * @file: if set, ensure we match requests from this file
3497   * @idx_start: lower bound of page->index to scan.
3498   * @npages: idx_start + npages sets the upper bound to scan.
3499   *
3500 @@ -472,11 +516,11 @@ nfs_wait_on_requests(struct inode *inode
3501   * The requests are *not* checked to ensure that they form a contiguous set.
3502   */
3503  static int
3504 -nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
3505 +nfs_scan_dirty(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
3506  {
3507         struct nfs_inode *nfsi = NFS_I(inode);
3508         int     res;
3509 -       res = nfs_scan_list(&nfsi->dirty, dst, file, idx_start, npages);
3510 +       res = nfs_scan_list(&nfsi->dirty, dst, idx_start, npages);
3511         nfsi->ndirty -= res;
3512         sub_page_state(nr_dirty,res);
3513         if ((nfsi->ndirty == 0) != list_empty(&nfsi->dirty))
3514 @@ -489,7 +533,6 @@ nfs_scan_dirty(struct inode *inode, stru
3515   * nfs_scan_commit - Scan an inode for commit requests
3516   * @inode: NFS inode to scan
3517   * @dst: destination list
3518 - * @file: if set, ensure we collect requests from this file only.
3519   * @idx_start: lower bound of page->index to scan.
3520   * @npages: idx_start + npages sets the upper bound to scan.
3521   *
3522 @@ -497,11 +540,11 @@ nfs_scan_dirty(struct inode *inode, stru
3523   * The requests are *not* checked to ensure that they form a contiguous set.
3524   */
3525  static int
3526 -nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
3527 +nfs_scan_commit(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
3528  {
3529         struct nfs_inode *nfsi = NFS_I(inode);
3530         int     res;
3531 -       res = nfs_scan_list(&nfsi->commit, dst, file, idx_start, npages);
3532 +       res = nfs_scan_list(&nfsi->commit, dst, idx_start, npages);
3533         nfsi->ncommit -= res;
3534         if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
3535                 printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
3536 @@ -600,46 +643,6 @@ nfs_update_request(struct file* file, st
3537         return req;
3538  }
3539  
3540 -/*
3541 - * This is the strategy routine for NFS.
3542 - * It is called by nfs_updatepage whenever the user wrote up to the end
3543 - * of a page.
3544 - *
3545 - * We always try to submit a set of requests in parallel so that the
3546 - * server's write code can gather writes. This is mainly for the benefit
3547 - * of NFSv2.
3548 - *
3549 - * We never submit more requests than we think the remote can handle.
3550 - * For UDP sockets, we make sure we don't exceed the congestion window;
3551 - * for TCP, we limit the number of requests to 8.
3552 - *
3553 - * NFS_STRATEGY_PAGES gives the minimum number of requests for NFSv2 that
3554 - * should be sent out in one go. This is for the benefit of NFSv2 servers
3555 - * that perform write gathering.
3556 - *
3557 - * FIXME: Different servers may have different sweet spots.
3558 - * Record the average congestion window in server struct?
3559 - */
3560 -#define NFS_STRATEGY_PAGES      8
3561 -static void
3562 -nfs_strategy(struct inode *inode)
3563 -{
3564 -       unsigned int    dirty, wpages;
3565 -
3566 -       dirty  = NFS_I(inode)->ndirty;
3567 -       wpages = NFS_SERVER(inode)->wpages;
3568 -#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
3569 -       if (NFS_PROTO(inode)->version == 2) {
3570 -               if (dirty >= NFS_STRATEGY_PAGES * wpages)
3571 -                       nfs_flush_file(inode, NULL, 0, 0, 0);
3572 -       } else if (dirty >= wpages)
3573 -               nfs_flush_file(inode, NULL, 0, 0, 0);
3574 -#else
3575 -       if (dirty >= NFS_STRATEGY_PAGES * wpages)
3576 -               nfs_flush_file(inode, NULL, 0, 0, 0);
3577 -#endif
3578 -}
3579 -
3580  int
3581  nfs_flush_incompatible(struct file *file, struct page *page)
3582  {
3583 @@ -675,7 +678,6 @@ nfs_updatepage(struct file *file, struct
3584         struct dentry   *dentry = file->f_dentry;
3585         struct inode    *inode = page->mapping->host;
3586         struct nfs_page *req;
3587 -       loff_t          end;
3588         int             status = 0;
3589  
3590         dprintk("NFS:      nfs_updatepage(%s/%s %d@%Ld)\n",
3591 @@ -696,6 +698,30 @@ nfs_updatepage(struct file *file, struct
3592                 return status;
3593         }
3594  
3595 +       nfs_begin_data_update(inode);
3596 +
3597 +
3598 +       /* If we're not using byte range locks, and we know the page
3599 +        * is entirely in cache, it may be more efficient to avoid
3600 +        * fragmenting write requests.
3601 +        */
3602 +       if (PageUptodate(page) && inode->i_flock == NULL) {
3603 +               loff_t end_offs = i_size_read(inode) - 1;
3604 +               unsigned long end_index = end_offs >> PAGE_CACHE_SHIFT;
3605 +
3606 +               count += offset;
3607 +               offset = 0;
3608 +               if (end_offs < 0) {
3609 +                       /* Do nothing */
3610 +               } else if (page->index == end_index) {
3611 +                       unsigned int pglen;
3612 +                       pglen = (unsigned int)(end_offs & (PAGE_CACHE_SIZE-1)) + 1;
3613 +                       if (count < pglen)
3614 +                               count = pglen;
3615 +               } else if (page->index < end_index)
3616 +                       count = PAGE_CACHE_SIZE;
3617 +       }
3618 +
3619         /*
3620          * Try to find an NFS request corresponding to this page
3621          * and update it.
3622 @@ -714,21 +740,14 @@ nfs_updatepage(struct file *file, struct
3623                 goto done;
3624  
3625         status = 0;
3626 -       end = ((loff_t)page->index<<PAGE_CACHE_SHIFT) + (loff_t)(offset + count);
3627 -       if (i_size_read(inode) < end)
3628 -               i_size_write(inode, end);
3629 -
3630 -       /* If we wrote past the end of the page.
3631 -        * Call the strategy routine so it can send out a bunch
3632 -        * of requests.
3633 -        */
3634 -       if (req->wb_pgbase == 0 && req->wb_bytes == PAGE_CACHE_SIZE) {
3635 -               SetPageUptodate(page);
3636 -               nfs_unlock_request(req);
3637 -               nfs_strategy(inode);
3638 -       } else
3639 -               nfs_unlock_request(req);
3640 +
3641 +       /* Update file length */
3642 +       nfs_grow_file(page, offset, count);
3643 +       /* Set the PG_uptodate flag? */
3644 +       nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
3645 +       nfs_unlock_request(req);
3646  done:
3647 +       nfs_end_data_update(inode);
3648          dprintk("NFS:      nfs_updatepage returns %d (isize %Ld)\n",
3649                         status, (long long)i_size_read(inode));
3650         if (status < 0)
3651 @@ -891,10 +910,7 @@ nfs_writeback_done(struct rpc_task *task
3652  #endif
3653  
3654         /*
3655 -        * Update attributes as result of writeback.
3656 -        * FIXME: There is an inherent race with invalidate_inode_pages and
3657 -        *        writebacks since the page->count is kept > 1 for as long
3658 -        *        as the page has a write request pending.
3659 +        * Process the nfs_page list
3660          */
3661         while (!list_empty(&data->pages)) {
3662                 req = nfs_list_entry(data->pages.next);
3663 @@ -1061,7 +1077,7 @@ nfs_commit_done(struct rpc_task *task)
3664  }
3665  #endif
3666  
3667 -int nfs_flush_file(struct inode *inode, struct file *file, unsigned long idx_start,
3668 +int nfs_flush_inode(struct inode *inode, unsigned long idx_start,
3669                    unsigned int npages, int how)
3670  {
3671         LIST_HEAD(head);
3672 @@ -1069,7 +1085,7 @@ int nfs_flush_file(struct inode *inode, 
3673                                 error = 0;
3674  
3675         spin_lock(&nfs_wreq_lock);
3676 -       res = nfs_scan_dirty(inode, &head, file, idx_start, npages);
3677 +       res = nfs_scan_dirty(inode, &head, idx_start, npages);
3678         spin_unlock(&nfs_wreq_lock);
3679         if (res)
3680                 error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how);
3681 @@ -1079,7 +1095,7 @@ int nfs_flush_file(struct inode *inode, 
3682  }
3683  
3684  #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
3685 -int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start,
3686 +int nfs_commit_inode(struct inode *inode, unsigned long idx_start,
3687                     unsigned int npages, int how)
3688  {
3689         LIST_HEAD(head);
3690 @@ -1087,9 +1103,9 @@ int nfs_commit_file(struct inode *inode,
3691                                 error = 0;
3692  
3693         spin_lock(&nfs_wreq_lock);
3694 -       res = nfs_scan_commit(inode, &head, file, idx_start, npages);
3695 +       res = nfs_scan_commit(inode, &head, idx_start, npages);
3696         if (res) {
3697 -               res += nfs_scan_commit(inode, &head, NULL, 0, 0);
3698 +               res += nfs_scan_commit(inode, &head, 0, 0);
3699                 spin_unlock(&nfs_wreq_lock);
3700                 error = nfs_commit_list(&head, how);
3701         } else
3702 @@ -1100,7 +1116,7 @@ int nfs_commit_file(struct inode *inode,
3703  }
3704  #endif
3705  
3706 -int nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start,
3707 +int nfs_sync_inode(struct inode *inode, unsigned long idx_start,
3708                   unsigned int npages, int how)
3709  {
3710         int     error,
3711 @@ -1109,18 +1125,15 @@ int nfs_sync_file(struct inode *inode, s
3712         wait = how & FLUSH_WAIT;
3713         how &= ~FLUSH_WAIT;
3714  
3715 -       if (!inode && file)
3716 -               inode = file->f_dentry->d_inode;
3717 -
3718         do {
3719                 error = 0;
3720                 if (wait)
3721 -                       error = nfs_wait_on_requests(inode, file, idx_start, npages);
3722 +                       error = nfs_wait_on_requests(inode, idx_start, npages);
3723                 if (error == 0)
3724 -                       error = nfs_flush_file(inode, file, idx_start, npages, how);
3725 +                       error = nfs_flush_inode(inode, idx_start, npages, how);
3726  #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
3727                 if (error == 0)
3728 -                       error = nfs_commit_file(inode, file, idx_start, npages, how);
3729 +                       error = nfs_commit_inode(inode, idx_start, npages, how);
3730  #endif
3731         } while (error > 0);
3732         return error;
3733 diff -puN include/linux/fs.h~CITI_NFS4_ALL include/linux/fs.h
3734 --- linux-2.6.3/include/linux/fs.h~CITI_NFS4_ALL        2004-02-19 16:47:03.000000000 -0500
3735 +++ linux-2.6.3-bfields/include/linux/fs.h      2004-02-19 16:47:03.000000000 -0500
3736 @@ -137,6 +137,7 @@ extern int leases_enable, dir_notify_ena
3737  #define S_DEAD         32      /* removed, but still open directory */
3738  #define S_NOQUOTA      64      /* Inode is not counted to quota */
3739  #define S_DIRSYNC      128     /* Directory modifications are synchronous */
3740 +#define S_NOCMTIME     256     /* Do not update file c/mtime */
3741  
3742  /*
3743   * Note that nosuid etc flags are inode-specific: setting some file-system
3744 @@ -170,6 +171,7 @@ extern int leases_enable, dir_notify_ena
3745  #define IS_ONE_SECOND(inode)   __IS_FLG(inode, MS_ONE_SECOND)
3746  
3747  #define IS_DEADDIR(inode)      ((inode)->i_flags & S_DEAD)
3748 +#define IS_NOCMTIME(inode)     ((inode)->i_flags & S_NOCMTIME)
3749  
3750  /* the read-only stuff doesn't really belong here, but any other place is
3751     probably as bad and I don't want to create yet another include file. */
3752 diff -puN include/linux/nfs_fs.h~CITI_NFS4_ALL include/linux/nfs_fs.h
3753 --- linux-2.6.3/include/linux/nfs_fs.h~CITI_NFS4_ALL    2004-02-19 16:47:03.000000000 -0500
3754 +++ linux-2.6.3-bfields/include/linux/nfs_fs.h  2004-02-19 16:47:07.000000000 -0500
3755 @@ -23,6 +23,10 @@
3756  #include <linux/sunrpc/auth.h>
3757  #include <linux/sunrpc/clnt.h>
3758  
3759 +#ifdef CONFIG_NFS_V4
3760 +#include <linux/xattr_acl.h>
3761 +#endif /* CONFIG_NFS_V4 */
3762 +
3763  #include <linux/nfs.h>
3764  #include <linux/nfs2.h>
3765  #include <linux/nfs3.h>
3766 @@ -99,7 +103,7 @@ struct nfs_inode {
3767         /*
3768          * Various flags
3769          */
3770 -       unsigned short          flags;
3771 +       unsigned int            flags;
3772  
3773         /*
3774          * read_cache_jiffies is when we started read-caching this inode,
3775 @@ -118,19 +122,22 @@ struct nfs_inode {
3776          *
3777          *      mtime != read_cache_mtime
3778          */
3779 +       unsigned long           readdir_timestamp;
3780         unsigned long           read_cache_jiffies;
3781 -       struct timespec         read_cache_ctime;
3782 -       struct timespec         read_cache_mtime;
3783 -       __u64                   read_cache_isize;
3784         unsigned long           attrtimeo;
3785         unsigned long           attrtimeo_timestamp;
3786         __u64                   change_attr;            /* v4 only */
3787  
3788 +       /* "Generation counter" for the attribute cache. This is
3789 +        * bumped whenever we update the metadata on the
3790 +        * server.
3791 +        */
3792 +       unsigned long           cache_change_attribute;
3793         /*
3794 -        * Timestamp that dates the change made to read_cache_mtime.
3795 -        * This is of use for dentry revalidation
3796 +        * Counter indicating the number of outstanding requests that
3797 +        * will cause a file data update.
3798          */
3799 -       unsigned long           cache_mtime_jiffies;
3800 +       atomic_t                data_updates;
3801  
3802         struct nfs_access_cache cache_access;
3803  
3804 @@ -160,7 +167,10 @@ struct nfs_inode {
3805          /* NFSv4 state */
3806         struct list_head        open_states;
3807  #endif /* CONFIG_NFS_V4*/
3808 -
3809 +#ifdef CONFIG_NFS_V4_ACL
3810 +       struct posix_acl        *acl;
3811 +       struct posix_acl        *default_acl;
3812 +#endif /* CONFIG_NFS_V4_ACL */
3813         struct inode            vfs_inode;
3814  };
3815  
3816 @@ -170,7 +180,9 @@ struct nfs_inode {
3817  #define NFS_INO_STALE          0x0001          /* possible stale inode */
3818  #define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
3819  #define NFS_INO_REVALIDATING   0x0004          /* revalidating attrs */
3820 -#define NFS_INO_FLUSH          0x0008          /* inode is due for flushing */
3821 +#define NFS_INO_INVALID_ATTR   0x0008          /* cached attrs are invalid */
3822 +#define NFS_INO_INVALID_DATA   0x0010          /* cached data is invalid */
3823 +#define NFS_INO_INVALID_ATIME  0x0020          /* cached atime is invalid */
3824  #define NFS_INO_FAKE_ROOT      0x0080          /* root inode placeholder */
3825  
3826  static inline struct nfs_inode *NFS_I(struct inode *inode)
3827 @@ -186,15 +198,7 @@ static inline struct nfs_inode *NFS_I(st
3828  #define NFS_ADDR(inode)                        (RPC_PEERADDR(NFS_CLIENT(inode)))
3829  #define NFS_COOKIEVERF(inode)          (NFS_I(inode)->cookieverf)
3830  #define NFS_READTIME(inode)            (NFS_I(inode)->read_cache_jiffies)
3831 -#define NFS_MTIME_UPDATE(inode)                (NFS_I(inode)->cache_mtime_jiffies)
3832 -#define NFS_CACHE_CTIME(inode)         (NFS_I(inode)->read_cache_ctime)
3833 -#define NFS_CACHE_MTIME(inode)         (NFS_I(inode)->read_cache_mtime)
3834 -#define NFS_CACHE_ISIZE(inode)         (NFS_I(inode)->read_cache_isize)
3835  #define NFS_CHANGE_ATTR(inode)         (NFS_I(inode)->change_attr)
3836 -#define NFS_CACHEINV(inode) \
3837 -do { \
3838 -       NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
3839 -} while (0)
3840  #define NFS_ATTRTIMEO(inode)           (NFS_I(inode)->attrtimeo)
3841  #define NFS_MINATTRTIMEO(inode) \
3842         (S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmin \
3843 @@ -211,6 +215,17 @@ do { \
3844  
3845  #define NFS_FILEID(inode)              (NFS_I(inode)->fileid)
3846  
3847 +static inline int nfs_caches_unstable(struct inode *inode)
3848 +{
3849 +       return atomic_read(&NFS_I(inode)->data_updates) != 0;
3850 +}
3851 +
3852 +static inline void NFS_CACHEINV(struct inode *inode)
3853 +{
3854 +       if (!nfs_caches_unstable(inode))
3855 +               NFS_FLAGS(inode) |= NFS_INO_INVALID_ATTR;
3856 +}
3857 +
3858  static inline int nfs_server_capable(struct inode *inode, int cap)
3859  {
3860         return NFS_SERVER(inode)->caps & cap;
3861 @@ -227,13 +242,37 @@ loff_t page_offset(struct page *page)
3862         return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
3863  }
3864  
3865 +/**
3866 + * nfs_save_change_attribute - Returns the inode attribute change cookie
3867 + * @inode - pointer to inode
3868 + * The "change attribute" is updated every time we finish an operation
3869 + * that will result in a metadata change on the server.
3870 + */
3871 +static inline long nfs_save_change_attribute(struct inode *inode)
3872 +{
3873 +       return NFS_I(inode)->cache_change_attribute;
3874 +}
3875 +
3876 +/**
3877 + * nfs_verify_change_attribute - Detects NFS inode cache updates
3878 + * @inode - pointer to inode
3879 + * @chattr - previously saved change attribute
3880 + * Return "false" if metadata has been updated (or is in the process of
3881 + * being updated) since the change attribute was saved.
3882 + */
3883 +static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr)
3884 +{
3885 +       return !nfs_caches_unstable(inode)
3886 +               && chattr == NFS_I(inode)->cache_change_attribute;
3887 +}
3888 +
3889  /*
3890   * linux/fs/nfs/inode.c
3891   */
3892  extern void nfs_zap_caches(struct inode *);
3893  extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
3894                                 struct nfs_fattr *);
3895 -extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *);
3896 +extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
3897  extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
3898  extern int nfs_permission(struct inode *, int, struct nameidata *);
3899  extern void nfs_set_mmcred(struct inode *, struct rpc_cred *);
3900 @@ -241,6 +280,10 @@ extern int nfs_open(struct inode *, stru
3901  extern int nfs_release(struct inode *, struct file *);
3902  extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *);
3903  extern int nfs_setattr(struct dentry *, struct iattr *);
3904 +extern void nfs_begin_attr_update(struct inode *);
3905 +extern void nfs_end_attr_update(struct inode *);
3906 +extern void nfs_begin_data_update(struct inode *);
3907 +extern void nfs_end_data_update(struct inode *);
3908  
3909  /*
3910   * linux/fs/nfs/file.c
3911 @@ -309,11 +352,11 @@ extern void nfs_commit_done(struct rpc_t
3912   * Try to write back everything synchronously (but check the
3913   * return value!)
3914   */
3915 -extern int  nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int);
3916 -extern int  nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int);
3917 +extern int  nfs_sync_inode(struct inode *, unsigned long, unsigned int, int);
3918 +extern int  nfs_flush_inode(struct inode *, unsigned long, unsigned int, int);
3919  extern int  nfs_flush_list(struct list_head *, int, int);
3920  #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
3921 -extern int  nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int);
3922 +extern int  nfs_commit_inode(struct inode *, unsigned long, unsigned int, int);
3923  extern int  nfs_commit_list(struct list_head *, int);
3924  #else
3925  static inline int
3926 @@ -333,7 +376,7 @@ nfs_have_writebacks(struct inode *inode)
3927  static inline int
3928  nfs_wb_all(struct inode *inode)
3929  {
3930 -       int error = nfs_sync_file(inode, 0, 0, 0, FLUSH_WAIT);
3931 +       int error = nfs_sync_inode(inode, 0, 0, FLUSH_WAIT);
3932         return (error < 0) ? error : 0;
3933  }
3934  
3935 @@ -343,21 +386,11 @@ nfs_wb_all(struct inode *inode)
3936  static inline int
3937  nfs_wb_page(struct inode *inode, struct page* page)
3938  {
3939 -       int error = nfs_sync_file(inode, 0, page->index, 1,
3940 +       int error = nfs_sync_inode(inode, page->index, 1,
3941                                                 FLUSH_WAIT | FLUSH_STABLE);
3942         return (error < 0) ? error : 0;
3943  }
3944  
3945 -/*
3946 - * Write back all pending writes for one user.. 
3947 - */
3948 -static inline int
3949 -nfs_wb_file(struct inode *inode, struct file *file)
3950 -{
3951 -       int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT);
3952 -       return (error < 0) ? error : 0;
3953 -}
3954 -
3955  /* Hack for future NFS swap support */
3956  #ifndef IS_SWAPFILE
3957  # define IS_SWAPFILE(inode)    (0)
3958 @@ -383,20 +416,27 @@ extern int  nfsroot_mount(struct sockadd
3959  /*
3960   * inline functions
3961   */
3962 -static inline int
3963 -nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
3964 +
3965 +static inline int nfs_attribute_timeout(struct inode *inode)
3966  {
3967 -       if (time_before(jiffies, NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
3968 -               return NFS_STALE(inode) ? -ESTALE : 0;
3969 -       return __nfs_revalidate_inode(server, inode);
3970 +       struct nfs_inode *nfsi = NFS_I(inode);
3971 +
3972 +       return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
3973  }
3974  
3975 -static inline int
3976 -nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
3977 +/**
3978 + * nfs_revalidate_inode - Revalidate the inode attributes
3979 + * @server - pointer to nfs_server struct
3980 + * @inode - pointer to inode struct
3981 + *
3982 + * Updates inode attribute information by retrieving the data from the server.
3983 + */
3984 +static inline int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
3985  {
3986 -       if ((fattr->valid & NFS_ATTR_FATTR) == 0)
3987 -               return 0;
3988 -       return __nfs_refresh_inode(inode,fattr);
3989 +       if (!(NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
3990 +                       && !nfs_attribute_timeout(inode))
3991 +               return NFS_STALE(inode) ? -ESTALE : 0;
3992 +       return __nfs_revalidate_inode(server, inode);
3993  }
3994  
3995  static inline loff_t
3996 @@ -590,6 +630,15 @@ struct nfs4_state {
3997  
3998  extern struct dentry_operations nfs4_dentry_operations;
3999  extern struct inode_operations nfs4_dir_inode_operations;
4000 +extern struct inode_operations nfs4_file_inode_operations;
4001 +
4002 +#define NFS_ACL_MAX_ENTRIES    32
4003 +
4004 +/* inode.c */
4005 +extern ssize_t nfs_getxattr(struct dentry *, const char *, void *, size_t);
4006 +extern int nfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
4007 +
4008 +#define NFS4_ACL_NOT_CACHED    ((void *)-1)
4009  
4010  /* nfs4proc.c */
4011  extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
4012 @@ -602,6 +651,9 @@ int nfs4_do_downgrade(struct inode *inod
4013  extern int nfs4_wait_clnt_recover(struct rpc_clnt *, struct nfs4_client *);
4014  extern struct inode *nfs4_atomic_open(struct inode *, struct dentry *, struct nameidata *);
4015  extern int nfs4_open_revalidate(struct inode *, struct dentry *, int);
4016 +struct posix_acl * nfs4_proc_get_posix_acl(struct inode *, int);
4017 +extern int nfs4_proc_set_posix_acl(struct inode *, int, struct posix_acl *);
4018 +void nfs4_izap_acl(struct inode *inode, struct posix_acl **i_acl);
4019  
4020  /* nfs4renewd.c */
4021  extern void nfs4_schedule_state_renewal(struct nfs4_client *);
4022 diff -puN include/linux/nfs_page.h~CITI_NFS4_ALL include/linux/nfs_page.h
4023 --- linux-2.6.3/include/linux/nfs_page.h~CITI_NFS4_ALL  2004-02-19 16:47:03.000000000 -0500
4024 +++ linux-2.6.3-bfields/include/linux/nfs_page.h        2004-02-19 16:47:03.000000000 -0500
4025 @@ -53,7 +53,7 @@ extern        void nfs_release_request(struct n
4026  extern void nfs_list_add_request(struct nfs_page *, struct list_head *);
4027  
4028  extern int nfs_scan_list(struct list_head *, struct list_head *,
4029 -                         struct file *, unsigned long, unsigned int);
4030 +                         unsigned long, unsigned int);
4031  extern int nfs_coalesce_requests(struct list_head *, struct list_head *,
4032                                   unsigned int);
4033  extern  int nfs_wait_on_request(struct nfs_page *);
4034 diff -puN include/linux/nfs_xdr.h~CITI_NFS4_ALL include/linux/nfs_xdr.h
4035 --- linux-2.6.3/include/linux/nfs_xdr.h~CITI_NFS4_ALL   2004-02-19 16:47:03.000000000 -0500
4036 +++ linux-2.6.3-bfields/include/linux/nfs_xdr.h 2004-02-19 16:47:15.000000000 -0500
4037 @@ -39,6 +39,9 @@ struct nfs_fattr {
4038         __u64                   change_attr;    /* NFSv4 change attribute */
4039         __u64                   pre_change_attr;/* pre-op NFSv4 change attribute */
4040         unsigned long           timestamp;
4041 +#ifdef CONFIG_NFS_V4
4042 +       struct nfs4_acl        *acl;            /* NFSv4 ACL */
4043 +#endif /* CONFIG_NFS_V4 */
4044  };
4045  
4046  #define NFS_ATTR_WCC           0x0001          /* pre-op WCC data    */
4047 @@ -103,8 +106,6 @@ struct nfs_openargs {
4048                 nfs4_verifier   verifier; /* EXCLUSIVE */
4049         } u;
4050         struct qstr *           name;
4051 -       struct nfs4_getattr *   f_getattr;
4052 -       struct nfs4_getattr *   d_getattr;
4053         struct nfs_server *     server;  /* Needed for ID mapping */
4054  };
4055  
4056 @@ -113,8 +114,8 @@ struct nfs_openres {
4057         struct nfs_fh           fh;
4058         struct nfs4_change_info * cinfo;
4059         __u32                   rflags;
4060 -       struct nfs4_getattr *   f_getattr;
4061 -       struct nfs4_getattr *   d_getattr;
4062 +       struct nfs_fattr *      f_attr;
4063 +       struct nfs_fattr *      d_attr;
4064         struct nfs_server *     server;
4065  };
4066  
4067 @@ -141,7 +142,6 @@ struct nfs_open_reclaimargs {
4068         __u32                   id;
4069         __u32                   share_access;
4070         __u32                   claim;
4071 -       struct nfs4_getattr *   f_getattr;
4072  };
4073  
4074  /*
4075 @@ -319,12 +319,22 @@ struct nfs_setattrargs {
4076         struct nfs_fh *                 fh;
4077         nfs4_stateid                    stateid;
4078         struct iattr *                  iap;
4079 -       struct nfs4_getattr *           attr;
4080 +       struct nfs_fattr *              fattr;
4081         struct nfs_server *             server; /* Needed for name mapping */
4082 +#ifdef CONFIG_NFS_V4
4083 +       struct nfs4_acl *               acl;
4084 +#endif /* CONFIG_NFS_V4 */
4085  };
4086  
4087 +#ifdef CONFIG_NFS_V4
4088 +struct nfs_setaclargs {
4089 +       struct nfs_fh *                 fh;
4090 +       struct nfs4_acl *               acl;
4091 +};
4092 +#endif /* CONFIG_NFS_V4 */
4093 +
4094  struct nfs_setattrres {
4095 -       struct nfs4_getattr *           attr;
4096 +       struct nfs_fattr *              fattr;
4097         struct nfs_server *             server;
4098  };
4099  
4100 @@ -482,118 +492,127 @@ struct nfs4_change_info {
4101         u64                             after;
4102  };
4103  
4104 -struct nfs4_access {
4105 -       u32                             ac_req_access;     /* request */
4106 -       u32 *                           ac_resp_supported; /* response */
4107 -       u32 *                           ac_resp_access;    /* response */
4108 +struct nfs4_accessargs {
4109 +       struct nfs_fh *                 fhandle;
4110 +       u32                             req_access;
4111  };
4112  
4113 -struct nfs4_close {
4114 -       char *                          cl_stateid;        /* request */
4115 -       u32                             cl_seqid;          /* request */
4116 +struct nfs4_accessres {
4117 +       struct nfs_server *             server;
4118 +       struct nfs_fattr *              fattr;
4119 +       u32                             req_access;
4120 +       u32 *                           resp_supported;
4121 +       u32 *                           resp_access;
4122  };
4123  
4124 -struct nfs4_create {
4125 -       u32                             cr_ftype;          /* request */
4126 -       union {                                            /* request */
4127 -               struct {
4128 -                       u32             textlen;
4129 -                       const char *    text;
4130 -               } symlink;   /* NF4LNK */
4131 +struct nfs4_create_arg {
4132 +       u32                             ftype;
4133 +       union {
4134 +               struct qstr *           symlink;    /* NF4LNK */
4135                 struct {
4136                         u32             specdata1;
4137                         u32             specdata2;
4138                 } device;    /* NF4BLK, NF4CHR */
4139         } u;
4140 -       u32                             cr_namelen;        /* request */
4141 -       const char *                    cr_name;           /* request */
4142 -       struct iattr *                  cr_attrs;          /* request */
4143 -       struct nfs4_change_info *       cr_cinfo;          /* response */
4144 +       struct qstr *                   name;
4145 +       struct nfs_server *             server;
4146 +       struct iattr *                  attrs;
4147 +       struct nfs_fh *                 dir_fh;
4148  };
4149 -#define cr_textlen                     u.symlink.textlen
4150 -#define cr_text                                u.symlink.text
4151 -#define cr_specdata1                   u.device.specdata1
4152 -#define cr_specdata2                   u.device.specdata2
4153  
4154 -struct nfs4_getattr {
4155 -        u32 *                          gt_bmval;          /* request */
4156 -        struct nfs_fattr *             gt_attrs;          /* response */
4157 -       struct nfs_fsstat *             gt_fsstat;         /* response */
4158 -       struct nfs_pathconf *           gt_pathconf;       /* response */
4159 +struct nfs4_create_res {
4160 +       struct nfs_server *             server;
4161 +       struct nfs_fh *                 fhandle;
4162 +       struct nfs_fattr *              fattr;
4163 +       struct nfs_fattr *              dir_attr;
4164 +       struct nfs4_change_info *       dir_cinfo;
4165  };
4166  
4167 -struct nfs4_getfh {
4168 -       struct nfs_fh *                 gf_fhandle;       /* response */
4169 +struct nfs4_getattr_res {
4170 +       struct nfs_server *             server;
4171 +       struct nfs_fattr *              fattr;
4172  };
4173  
4174 -struct nfs4_link {
4175 -       u32                             ln_namelen;       /* request */
4176 -       const char *                    ln_name;          /* request */
4177 -       struct nfs4_change_info *       ln_cinfo;         /* response */
4178 +struct nfs4_getroot_res {
4179 +       struct nfs_server *             server;
4180 +       struct nfs_fattr *              fattr;
4181 +       struct nfs_fh *                 fhandle;
4182  };
4183  
4184 -struct nfs4_lookup {
4185 -       struct qstr *                   lo_name;          /* request */
4186 +struct nfs4_getroot_arg {
4187 +       struct nfs_fh *                 fhandle;
4188 +       struct qstr *                   name;
4189  };
4190  
4191 -struct nfs4_open {
4192 -       struct nfs4_client *            op_client_state;  /* request */
4193 -       u32                             op_share_access;  /* request */
4194 -       u32                             op_opentype;      /* request */
4195 -       u32                             op_createmode;    /* request */
4196 -       union {                                           /* request */
4197 -               struct iattr *          attrs;    /* UNCHECKED, GUARDED */
4198 -               nfs4_verifier           verifier; /* EXCLUSIVE */
4199 -       } u;
4200 -       struct qstr *                   op_name;          /* request */
4201 -       char *                          op_stateid;       /* response */
4202 -       struct nfs4_change_info *       op_cinfo;         /* response */
4203 -       u32 *                           op_rflags;        /* response */
4204 -};
4205 -#define op_attrs     u.attrs
4206 -#define op_verifier  u.verifier
4207 -
4208 -struct nfs4_open_confirm {
4209 -       char *                          oc_stateid;       /* request */
4210 -};
4211 -
4212 -struct nfs4_putfh {
4213 -       struct nfs_fh *                 pf_fhandle;       /* request */
4214 -};
4215 -
4216 -struct nfs4_readdir {
4217 -       u64                             rd_cookie;        /* request */
4218 -       nfs4_verifier                   rd_req_verifier;  /* request */
4219 -       u32                             rd_count;         /* request */
4220 -       u32                             rd_bmval[2];      /* request */ 
4221 -       nfs4_verifier                   rd_resp_verifier; /* response */
4222 -       struct page **                  rd_pages;   /* zero-copy data */
4223 -       unsigned int                    rd_pgbase;  /* zero-copy data */
4224 +struct nfs4_link_arg {
4225 +       struct nfs_fh *                 fh;
4226 +       struct nfs_fh *                 dir_fh;
4227 +       struct qstr *                   name;
4228 +};
4229 +
4230 +struct nfs4_link_res {
4231 +       struct nfs_server *             server;
4232 +       struct nfs_fattr *              fattr;
4233 +       struct nfs_fattr *              dir_attr;
4234 +       struct nfs4_change_info *       dir_cinfo;
4235 +};
4236 +
4237 +struct nfs4_lookupargs {
4238 +       struct nfs_fh *                 dir_fh;
4239 +        struct qstr *                   name;
4240 +};
4241 +
4242 +struct nfs4_lookupres {
4243 +       struct nfs_server *             server;
4244 +       struct nfs_fattr *              dirattr;
4245 +       struct nfs_fattr *              fattr;
4246 +       struct nfs_fh *                 fhandle;
4247 +};
4248 +
4249 +struct nfs4_readdir_arg {
4250 +       struct nfs_fh *                 fh;
4251 +       u64                             cookie;        /* request */
4252 +       nfs4_verifier                   req_verifier;  /* request */
4253 +       u32                             count;         /* request */
4254 +       struct page **                  pages;   /* zero-copy data */
4255 +       unsigned int                    pgbase;  /* zero-copy data */
4256 +};
4257 +
4258 +struct nfs4_readdir_res {
4259 +       nfs4_verifier                   resp_verifier;
4260 +       unsigned int                    pgbase;
4261  };
4262  
4263  struct nfs4_readlink {
4264 -       u32                             rl_count;   /* zero-copy data */
4265 -       struct page **                  rl_pages;   /* zero-copy data */
4266 +       struct nfs_fh *                 fh;
4267 +       u32                             count;   /* zero-copy data */
4268 +       struct page **                  pages;   /* zero-copy data */
4269  };
4270  
4271 -struct nfs4_remove {
4272 -       u32                             rm_namelen;       /* request */
4273 -       const char *                    rm_name;          /* request */
4274 -       struct nfs4_change_info *       rm_cinfo;         /* response */
4275 +struct nfs4_remove_arg {
4276 +       struct nfs_fh *                 fhandle;
4277 +       struct qstr *                   name;
4278  };
4279  
4280 -struct nfs4_rename {
4281 -       u32                             rn_oldnamelen;    /* request */
4282 -       const char *                    rn_oldname;       /* request */
4283 -       u32                             rn_newnamelen;    /* request */
4284 -       const char *                    rn_newname;       /* request */
4285 -       struct nfs4_change_info *       rn_src_cinfo;     /* response */
4286 -       struct nfs4_change_info *       rn_dst_cinfo;     /* response */
4287 +struct nfs4_remove_res {
4288 +       struct nfs_server *             server;
4289 +       struct nfs4_change_info *       dir_cinfo;
4290 +       struct nfs_fattr *              dir_attr;
4291  };
4292  
4293 -struct nfs4_setattr {
4294 -       char *                          st_stateid;       /* request */
4295 -       struct iattr *                  st_iap;           /* request */
4296 +struct nfs4_rename_arg {
4297 +       struct nfs_fh *                 old_dir;
4298 +        struct nfs_fh *                 new_dir;
4299 +        struct qstr *                   old_name;
4300 +        struct qstr *                   new_name;
4301 +};
4302 +
4303 +struct nfs4_rename_res {
4304 +        struct nfs_server *             server;
4305 +       struct nfs4_change_info *       old_cinfo;
4306 +       struct nfs4_change_info *       new_cinfo;
4307 +        struct nfs_fattr *              old_fattr;
4308 +       struct nfs_fattr *              new_fattr;
4309  };
4310  
4311  struct nfs4_setclientid {
4312 @@ -606,52 +625,12 @@ struct nfs4_setclientid {
4313         struct nfs4_client *            sc_state;         /* response */
4314  };
4315  
4316 -struct nfs4_op {
4317 -       u32                             opnum;
4318 -       union {
4319 -               struct nfs4_access      access;
4320 -               struct nfs4_close       close;
4321 -               struct nfs4_create      create;
4322 -               struct nfs4_getattr     getattr;
4323 -               struct nfs4_getfh       getfh;
4324 -               struct nfs4_link        link;
4325 -               struct nfs4_lookup      lookup;
4326 -               struct nfs4_open        open;
4327 -               struct nfs4_open_confirm open_confirm;
4328 -               struct nfs4_putfh       putfh;
4329 -               struct nfs4_readdir     readdir;
4330 -               struct nfs4_readlink    readlink;
4331 -               struct nfs4_remove      remove;
4332 -               struct nfs4_rename      rename;
4333 -               struct nfs4_client *    renew;
4334 -               struct nfs4_setattr     setattr;
4335 -       } u;
4336 -};
4337 -
4338 -struct nfs4_compound {
4339 -       unsigned int            flags;   /* defined below */
4340 -       struct nfs_server *     server;
4341 -
4342 -       /* RENEW information */
4343 -       int                     renew_index;
4344 -       unsigned long           timestamp;
4345 -
4346 -       /* scratch variables for XDR encode/decode */
4347 -       int                     nops;
4348 -       u32 *                   p;
4349 -       u32 *                   end;
4350 -
4351 -       /* the individual COMPOUND operations */
4352 -       struct nfs4_op          *ops;
4353 -
4354 -       /* request */
4355 -       int                     req_nops;
4356 -       u32                     taglen;
4357 -       char *                  tag;
4358 -       
4359 -       /* response */
4360 -       int                     resp_nops;
4361 -       int                     toplevel_status;
4362 +struct nfs4_unlink {
4363 +       struct nfs_server *             server;
4364 +       struct nfs_fh *                 fh;
4365 +       struct qstr *                   name;
4366 +       struct nfs4_change_info         cinfo;  /* NOT a pointer */
4367 +       struct nfs_fattr                attrs;  /* NOT a pointer */
4368  };
4369  
4370  #endif /* CONFIG_NFS_V4 */
4371 @@ -698,9 +677,10 @@ struct nfs_rpc_ops {
4372         int     version;                /* Protocol version */
4373         struct dentry_operations *dentry_ops;
4374         struct inode_operations *dir_inode_ops;
4375 +       struct inode_operations *file_inode_ops;
4376  
4377         int     (*getroot) (struct nfs_server *, struct nfs_fh *,
4378 -                           struct nfs_fattr *);
4379 +                           struct nfs_fsinfo *);
4380         int     (*getattr) (struct inode *, struct nfs_fattr *);
4381         int     (*setattr) (struct dentry *, struct nfs_fattr *,
4382                             struct iattr *);
4383 diff -puN include/linux/sunrpc/xprt.h~CITI_NFS4_ALL include/linux/sunrpc/xprt.h
4384 --- linux-2.6.3/include/linux/sunrpc/xprt.h~CITI_NFS4_ALL       2004-02-19 16:47:03.000000000 -0500
4385 +++ linux-2.6.3-bfields/include/linux/sunrpc/xprt.h     2004-02-19 16:47:05.000000000 -0500
4386 @@ -95,14 +95,15 @@ struct rpc_rqst {
4387         struct rpc_rqst *       rq_next;        /* free list */
4388         int                     rq_cong;        /* has incremented xprt->cong */
4389         int                     rq_received;    /* receive completed */
4390 -       u32                     rq_seqno;       /* gss seq no. used on req. */
4391 +#define GSS_SEQNO_CACHE                4
4392 +       u32                     rq_seqnos[GSS_SEQNO_CACHE];
4393 +                                               /* gss seq no.s used on req. */
4394  
4395         struct list_head        rq_list;
4396  
4397         struct xdr_buf          rq_private_buf;         /* The receive buffer
4398                                                          * used in the softirq.
4399                                                          */
4400 -
4401         /*
4402          * For authentication (e.g. auth_des)
4403          */
4404 @@ -155,6 +156,11 @@ struct rpc_xprt {
4405                                 stream     : 1; /* TCP */
4406  
4407         /*
4408 +        * XID
4409 +        */
4410 +       __u32                   xid;            /* Next XID value to use */
4411 +
4412 +       /*
4413          * State of TCP reply receive stuff
4414          */
4415         u32                     tcp_recm,       /* Fragment header */
4416 @@ -164,6 +170,11 @@ struct rpc_xprt {
4417         unsigned long           tcp_copied,     /* copied to request */
4418                                 tcp_flags;
4419         /*
4420 +        * Connection of sockets
4421 +        */
4422 +       struct work_struct      sock_connect;
4423 +       unsigned short          port;
4424 +       /*
4425          * Disconnection of idle sockets
4426          */
4427         struct work_struct      task_cleanup;
4428 diff -puN net/sunrpc/xprt.c~CITI_NFS4_ALL net/sunrpc/xprt.c
4429 --- linux-2.6.3/net/sunrpc/xprt.c~CITI_NFS4_ALL 2004-02-19 16:47:03.000000000 -0500
4430 +++ linux-2.6.3-bfields/net/sunrpc/xprt.c       2004-02-19 16:47:05.000000000 -0500
4431 @@ -60,6 +60,7 @@
4432  #include <linux/sunrpc/clnt.h>
4433  #include <linux/file.h>
4434  #include <linux/workqueue.h>
4435 +#include <linux/random.h>
4436  
4437  #include <net/sock.h>
4438  #include <net/checksum.h>
4439 @@ -77,6 +78,7 @@
4440  
4441  #define XPRT_MAX_BACKOFF       (8)
4442  #define XPRT_IDLE_TIMEOUT      (5*60*HZ)
4443 +#define XPRT_MAX_RESVPORT      (800)
4444  
4445  /*
4446   * Local functions
4447 @@ -87,7 +89,7 @@ static void   xprt_disconnect(struct rpc_x
4448  static void    xprt_connect_status(struct rpc_task *task);
4449  static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap,
4450                                                 struct rpc_timeout *to);
4451 -static struct socket *xprt_create_socket(int, struct rpc_timeout *, int);
4452 +static struct socket *xprt_create_socket(struct rpc_xprt *, int, int);
4453  static void    xprt_bind_socket(struct rpc_xprt *, struct socket *);
4454  static int      __xprt_get_cong(struct rpc_xprt *, struct rpc_task *);
4455  
4456 @@ -455,6 +457,68 @@ out_abort:
4457         spin_unlock(&xprt->sock_lock);
4458  }
4459  
4460 +static void
4461 +xprt_socket_connect(void *args)
4462 +{
4463 +       struct rpc_xprt *xprt = (struct rpc_xprt *)args;
4464 +       struct socket *sock = xprt->sock;
4465 +       int status = -EIO;
4466 +
4467 +       if (xprt->shutdown) {
4468 +               rpc_wake_up_status(&xprt->pending, -EIO);
4469 +               return;
4470 +       }
4471 +       if (!xprt->addr.sin_port)
4472 +               goto out_err;
4473 +
4474 +       /*
4475 +        * Start by resetting any existing state
4476 +        */
4477 +       xprt_close(xprt);
4478 +       sock = xprt_create_socket(xprt, xprt->prot, xprt->resvport);
4479 +       if (sock == NULL) {
4480 +               /* couldn't create socket or bind to reserved port;
4481 +                * this is likely a permanent error, so cause an abort */
4482 +               goto out_err;
4483 +               return;
4484 +       }
4485 +       xprt_bind_socket(xprt, sock);
4486 +       xprt_sock_setbufsize(xprt);
4487 +
4488 +       if (!xprt->stream)
4489 +               goto out;
4490 +
4491 +       /*
4492 +        * Tell the socket layer to start connecting...
4493 +        */
4494 +       status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
4495 +                       sizeof(xprt->addr), O_NONBLOCK);
4496 +       dprintk("RPC: %p  connect status %d connected %d sock state %d\n",
4497 +                       xprt, -status, xprt_connected(xprt), sock->sk->sk_state);
4498 +       if (status >= 0)
4499 +               goto out;
4500 +       switch (status) {
4501 +               case -EINPROGRESS:
4502 +               case -EALREADY:
4503 +                       break;
4504 +               default:
4505 +                       goto out_err;
4506 +       }
4507 +out:
4508 +       spin_lock_bh(&xprt->sock_lock);
4509 +       if (xprt->snd_task)
4510 +               rpc_wake_up_task(xprt->snd_task);
4511 +       spin_unlock_bh(&xprt->sock_lock);
4512 +       return;
4513 +out_err:
4514 +       spin_lock_bh(&xprt->sock_lock);
4515 +       if (xprt->snd_task) {
4516 +               xprt->snd_task->tk_status = status;
4517 +               rpc_wake_up_task(xprt->snd_task);
4518 +       }
4519 +       spin_unlock_bh(&xprt->sock_lock);
4520 +}
4521 +
4522  /*
4523   * Attempt to connect a TCP socket.
4524   *
4525 @@ -463,9 +527,6 @@ void
4526  xprt_connect(struct rpc_task *task)
4527  {
4528         struct rpc_xprt *xprt = task->tk_xprt;
4529 -       struct socket   *sock = xprt->sock;
4530 -       struct sock     *inet;
4531 -       int             status;
4532  
4533         dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid,
4534                         xprt, (xprt_connected(xprt) ? "is" : "is not"));
4535 @@ -486,79 +547,9 @@ xprt_connect(struct rpc_task *task)
4536         if (task->tk_rqstp)
4537                 task->tk_rqstp->rq_bytes_sent = 0;
4538  
4539 -       /*
4540 -        * We're here because the xprt was marked disconnected.
4541 -        * Start by resetting any existing state.
4542 -        */
4543 -       xprt_close(xprt);
4544 -       if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout, xprt->resvport))) {
4545 -               /* couldn't create socket or bind to reserved port;
4546 -                * this is likely a permanent error, so cause an abort */
4547 -               task->tk_status = -EIO;
4548 -               goto out_write;
4549 -       }
4550 -       xprt_bind_socket(xprt, sock);
4551 -       xprt_sock_setbufsize(xprt);
4552 -
4553 -       if (!xprt->stream)
4554 -               goto out_write;
4555 -
4556 -       inet = sock->sk;
4557 -
4558 -       /*
4559 -        * Tell the socket layer to start connecting...
4560 -        */
4561 -       status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
4562 -                               sizeof(xprt->addr), O_NONBLOCK);
4563 -       dprintk("RPC: %4d  connect status %d connected %d sock state %d\n",
4564 -               task->tk_pid, -status, xprt_connected(xprt), inet->sk_state);
4565 -
4566 -       if (status >= 0)
4567 -               return;
4568 -
4569 -       switch (status) {
4570 -       case -EINPROGRESS:
4571 -       case -EALREADY:
4572 -               /* Protect against TCP socket state changes */
4573 -               lock_sock(inet);
4574 -               if (inet->sk_state != TCP_ESTABLISHED) {
4575 -                       dprintk("RPC: %4d  waiting for connection\n",
4576 -                                       task->tk_pid);
4577 -                       task->tk_timeout = RPC_CONNECT_TIMEOUT;
4578 -                       /* if the socket is already closing, delay briefly */
4579 -                       if ((1 << inet->sk_state) &
4580 -                           ~(TCPF_SYN_SENT | TCPF_SYN_RECV))
4581 -                               task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
4582 -                       rpc_sleep_on(&xprt->pending, task, xprt_connect_status,
4583 -                                                                       NULL);
4584 -               }
4585 -               release_sock(inet);
4586 -               break;
4587 -       case -ECONNREFUSED:
4588 -       case -ECONNRESET:
4589 -       case -ENOTCONN:
4590 -               if (!RPC_IS_SOFT(task)) {
4591 -                       rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
4592 -                       task->tk_status = -ENOTCONN;
4593 -                       break;
4594 -               }
4595 -       default:
4596 -               /* Report myriad other possible returns.  If this file
4597 -                * system is soft mounted, just error out, like Solaris.  */
4598 -               if (RPC_IS_SOFT(task)) {
4599 -                       printk(KERN_WARNING
4600 -                       "RPC: error %d connecting to server %s, exiting\n",
4601 -                                       -status, task->tk_client->cl_server);
4602 -                       task->tk_status = -EIO;
4603 -                       goto out_write;
4604 -               }
4605 -               printk(KERN_WARNING "RPC: error %d connecting to server %s\n",
4606 -                               -status, task->tk_client->cl_server);
4607 -               /* This will prevent anybody else from reconnecting */
4608 -               rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
4609 -               task->tk_status = status;
4610 -               break;
4611 -       }
4612 +       task->tk_timeout = RPC_CONNECT_TIMEOUT;
4613 +       rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL);
4614 +       schedule_work(&xprt->sock_connect);
4615         return;
4616   out_write:
4617         xprt_release_write(xprt, task);
4618 @@ -583,6 +574,8 @@ xprt_connect_status(struct rpc_task *tas
4619                 task->tk_status = -EIO;
4620  
4621         switch (task->tk_status) {
4622 +       case -ECONNREFUSED:
4623 +       case -ECONNRESET:
4624         case -ENOTCONN:
4625                 rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
4626                 return;
4627 @@ -1333,22 +1326,14 @@ do_xprt_reserve(struct rpc_task *task)
4628  /*
4629   * Allocate a 'unique' XID
4630   */
4631 -static u32
4632 -xprt_alloc_xid(void)
4633 +static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
4634 +{
4635 +       return xprt->xid++;
4636 +}
4637 +
4638 +static inline void xprt_init_xid(struct rpc_xprt *xprt)
4639  {
4640 -       static spinlock_t xid_lock = SPIN_LOCK_UNLOCKED;
4641 -       static int need_init = 1;
4642 -       static u32 xid;
4643 -       u32 ret;
4644 -
4645 -       spin_lock(&xid_lock);
4646 -       if (unlikely(need_init)) {
4647 -               xid = get_seconds() << 12;
4648 -               need_init = 0;
4649 -       }
4650 -       ret = xid++;
4651 -       spin_unlock(&xid_lock);
4652 -       return ret;
4653 +       get_random_bytes(&xprt->xid, sizeof(xprt->xid));
4654  }
4655  
4656  /*
4657 @@ -1362,7 +1347,8 @@ xprt_request_init(struct rpc_task *task,
4658         req->rq_timeout = xprt->timeout;
4659         req->rq_task    = task;
4660         req->rq_xprt    = xprt;
4661 -       req->rq_xid     = xprt_alloc_xid();
4662 +       req->rq_xid     = xprt_alloc_xid(xprt);
4663 +       memset(req->rq_seqnos, 0, sizeof(req->rq_seqnos));
4664         INIT_LIST_HEAD(&req->rq_list);
4665         dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid,
4666                         req, req->rq_xid);
4667 @@ -1457,11 +1443,13 @@ xprt_setup(int proto, struct sockaddr_in
4668         init_waitqueue_head(&xprt->cong_wait);
4669  
4670         INIT_LIST_HEAD(&xprt->recv);
4671 +       INIT_WORK(&xprt->sock_connect, xprt_socket_connect, xprt);
4672         INIT_WORK(&xprt->task_cleanup, xprt_socket_autoclose, xprt);
4673         init_timer(&xprt->timer);
4674         xprt->timer.function = xprt_init_autodisconnect;
4675         xprt->timer.data = (unsigned long) xprt;
4676         xprt->last_used = jiffies;
4677 +       xprt->port = XPRT_MAX_RESVPORT;
4678  
4679         /* Set timeout parameters */
4680         if (to) {
4681 @@ -1481,6 +1469,8 @@ xprt_setup(int proto, struct sockaddr_in
4682         req->rq_next = NULL;
4683         xprt->free = xprt->slot;
4684  
4685 +       xprt_init_xid(xprt);
4686 +
4687         /* Check whether we want to use a reserved port */
4688         xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
4689  
4690 @@ -1493,30 +1483,28 @@ xprt_setup(int proto, struct sockaddr_in
4691   * Bind to a reserved port
4692   */
4693  static inline int
4694 -xprt_bindresvport(struct socket *sock)
4695 +xprt_bindresvport(struct rpc_xprt *xprt, struct socket *sock)
4696  {
4697 -       struct sockaddr_in myaddr;
4698 +       struct sockaddr_in myaddr = {
4699 +               .sin_family = AF_INET,
4700 +       };
4701         int             err, port;
4702 -       kernel_cap_t saved_cap = current->cap_effective;
4703  
4704 -       /* Override capabilities.
4705 -        * They were checked in xprt_create_proto i.e. at mount time
4706 -        */
4707 -       cap_raise(current->cap_effective, CAP_NET_BIND_SERVICE);
4708 -
4709 -       memset(&myaddr, 0, sizeof(myaddr));
4710 -       myaddr.sin_family = AF_INET;
4711 -       port = 800;
4712 +       /* Were we already bound to a given port? Try to reuse it */
4713 +       port = xprt->port;
4714         do {
4715                 myaddr.sin_port = htons(port);
4716                 err = sock->ops->bind(sock, (struct sockaddr *) &myaddr,
4717                                                 sizeof(myaddr));
4718 -       } while (err == -EADDRINUSE && --port > 0);
4719 -       current->cap_effective = saved_cap;
4720 -
4721 -       if (err < 0)
4722 -               printk("RPC: Can't bind to reserved port (%d).\n", -err);
4723 +               if (err == 0) {
4724 +                       xprt->port = port;
4725 +                       return 0;
4726 +               }
4727 +               if (--port == 0)
4728 +                       port = XPRT_MAX_RESVPORT;
4729 +       } while (err == -EADDRINUSE && port != xprt->port);
4730  
4731 +       printk("RPC: Can't bind to reserved port (%d).\n", -err);
4732         return err;
4733  }
4734  
4735 @@ -1580,7 +1568,7 @@ xprt_sock_setbufsize(struct rpc_xprt *xp
4736   * and connect stream sockets.
4737   */
4738  static struct socket *
4739 -xprt_create_socket(int proto, struct rpc_timeout *to, int resvport)
4740 +xprt_create_socket(struct rpc_xprt *xprt, int proto, int resvport)
4741  {
4742         struct socket   *sock;
4743         int             type, err;
4744 @@ -1596,7 +1584,7 @@ xprt_create_socket(int proto, struct rpc
4745         }
4746  
4747         /* If the caller has the capability, bind to a reserved port */
4748 -       if (resvport && xprt_bindresvport(sock) < 0) {
4749 +       if (resvport && xprt_bindresvport(xprt, sock) < 0) {
4750                 printk("RPC: can't bind to reserved port.\n");
4751                 goto failed;
4752         }
4753 diff -puN net/sunrpc/cache.c~CITI_NFS4_ALL net/sunrpc/cache.c
4754 --- linux-2.6.3/net/sunrpc/cache.c~CITI_NFS4_ALL        2004-02-19 16:47:03.000000000 -0500
4755 +++ linux-2.6.3-bfields/net/sunrpc/cache.c      2004-02-19 16:47:03.000000000 -0500
4756 @@ -325,6 +325,7 @@ int cache_clean(void)
4757         
4758         if (current_detail && current_index < current_detail->hash_size) {
4759                 struct cache_head *ch, **cp;
4760 +               struct cache_detail *d;
4761                 
4762                 write_lock(&current_detail->hash_lock);
4763  
4764 @@ -354,12 +355,14 @@ int cache_clean(void)
4765                         rv = 1;
4766                 }
4767                 write_unlock(&current_detail->hash_lock);
4768 -               if (ch)
4769 -                       current_detail->cache_put(ch, current_detail);
4770 -               else
4771 +               d = current_detail;
4772 +               if (!ch)
4773                         current_index ++;
4774 -       }
4775 -       spin_unlock(&cache_list_lock);
4776 +               spin_unlock(&cache_list_lock);
4777 +               if (ch)
4778 +                       d->cache_put(ch, d);
4779 +       } else
4780 +               spin_unlock(&cache_list_lock);
4781  
4782         return rv;
4783  }
4784 diff -puN include/linux/sunrpc/cache.h~CITI_NFS4_ALL include/linux/sunrpc/cache.h
4785 --- linux-2.6.3/include/linux/sunrpc/cache.h~CITI_NFS4_ALL      2004-02-19 16:47:03.000000000 -0500
4786 +++ linux-2.6.3-bfields/include/linux/sunrpc/cache.h    2004-02-19 16:47:03.000000000 -0500
4787 @@ -132,12 +132,14 @@ struct cache_deferred_req {
4788   * If "set" == 0 :
4789   *    If an entry is found, it is returned
4790   *    If no entry is found, a new non-VALID entry is created.
4791 - * If "set" == 1 :
4792 + * If "set" == 1 and INPLACE == 0 :
4793   *    If no entry is found a new one is inserted with data from "template"
4794   *    If a non-CACHE_VALID entry is found, it is updated from template using UPDATE
4795   *    If a CACHE_VALID entry is found, a new entry is swapped in with data
4796   *       from "template"
4797 - * If set == 2, we UPDATE, but don't swap. i.e. update in place
4798 + * If set == 1, and INPLACE == 1 :
4799 + *    As above, except that if a CACHE_VALID entry is found, we UPDATE in place
4800 + *       instead of swapping in a new entry.
4801   *
4802   * If the passed handle has the CACHE_NEGATIVE flag set, then UPDATE is not
4803   * run but insteead CACHE_NEGATIVE is set in any new item.
4804 @@ -164,8 +166,8 @@ RTN *FNAME ARGS                                                                             \
4805         RTN *tmp, *new=NULL;                                                            \
4806         struct cache_head **hp, **head;                                                 \
4807         SETUP;                                                                          \
4808 - retry:                                                                                        \
4809         head = &(DETAIL)->hash_table[HASHFN];                                           \
4810 + retry:                                                                                        \
4811         if (set||new) write_lock(&(DETAIL)->hash_lock);                                 \
4812         else read_lock(&(DETAIL)->hash_lock);                                           \
4813         for(hp=head; *hp != NULL; hp = &tmp->MEMBER.next) {                             \
4814 @@ -175,6 +177,8 @@ RTN *FNAME ARGS                                                                             \
4815                         if (set && !INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags) && !new) \
4816                                 break;                                                  \
4817                                                                                         \
4818 +                       if (new)                                                        \
4819 +                               {INIT;}                                                 \
4820                         cache_get(&tmp->MEMBER);                                        \
4821                         if (set) {                                                      \
4822                                 if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\
4823 @@ -203,6 +207,7 @@ RTN *FNAME ARGS                                                                             \
4824         }                                                                               \
4825         /* Didn't find anything */                                                      \
4826         if (new) {                                                                      \
4827 +               INIT;                                                                   \
4828                 new->MEMBER.next = *head;                                               \
4829                 *head = &new->MEMBER;                                                   \
4830                 (DETAIL)->entries ++;                                                   \
4831 @@ -224,8 +229,6 @@ RTN *FNAME ARGS                                                                             \
4832         if (new) {                                                                      \
4833                 cache_init(&new->MEMBER);                                               \
4834                 cache_get(&new->MEMBER);                                                \
4835 -               INIT;                                                                   \
4836 -               tmp = new;                                                              \
4837                 goto retry;                                                             \
4838         }                                                                               \
4839         return NULL;                                                                    \
4840 diff -puN net/sunrpc/svcauth.c~CITI_NFS4_ALL net/sunrpc/svcauth.c
4841 --- linux-2.6.3/net/sunrpc/svcauth.c~CITI_NFS4_ALL      2004-02-19 16:47:03.000000000 -0500
4842 +++ linux-2.6.3-bfields/net/sunrpc/svcauth.c    2004-02-19 16:47:04.000000000 -0500
4843 @@ -150,7 +150,10 @@ DefineCacheLookup(struct auth_domain,
4844                   &auth_domain_cache,
4845                   auth_domain_hash(item),
4846                   auth_domain_match(tmp, item),
4847 -                 kfree(new); if(!set) return NULL;
4848 +                 kfree(new); if(!set) {
4849 +                 write_unlock(&auth_domain_cache.hash_lock);
4850 +                 return NULL;
4851 +                 }
4852                   new=item; atomic_inc(&new->h.refcnt),
4853                   /* no update */,
4854                   0 /* no inplace updates */
4855 diff -puN net/sunrpc/svcauth_unix.c~CITI_NFS4_ALL net/sunrpc/svcauth_unix.c
4856 --- linux-2.6.3/net/sunrpc/svcauth_unix.c~CITI_NFS4_ALL 2004-02-19 16:47:03.000000000 -0500
4857 +++ linux-2.6.3-bfields/net/sunrpc/svcauth_unix.c       2004-02-19 16:47:03.000000000 -0500
4858 @@ -119,7 +119,8 @@ static inline int ip_map_match(struct ip
4859  }
4860  static inline void ip_map_init(struct ip_map *new, struct ip_map *item)
4861  {
4862 -       new->m_class = strdup(item->m_class);
4863 +       new->m_class = item->m_class;
4864 +       item->m_class = NULL;
4865         new->m_addr.s_addr = item->m_addr.s_addr;
4866  }
4867  static inline void ip_map_update(struct ip_map *new, struct ip_map *item)
4868 @@ -191,7 +192,9 @@ static int ip_map_parse(struct cache_det
4869         } else
4870                 dom = NULL;
4871  
4872 -       ipm.m_class = class;
4873 +       ipm.m_class = strdup(class);
4874 +       if (ipm.m_class == NULL)
4875 +               return -ENOMEM;
4876         ipm.m_addr.s_addr =
4877                 htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
4878         ipm.h.flags = 0;
4879 @@ -207,6 +210,7 @@ static int ip_map_parse(struct cache_det
4880                 ip_map_put(&ipmp->h, &ip_map_cache);
4881         if (dom)
4882                 auth_domain_put(dom);
4883 +       if (ipm.m_class) kfree(ipm.m_class);
4884         if (!ipmp)
4885                 return -ENOMEM;
4886         cache_flush();
4887 @@ -266,7 +270,9 @@ int auth_unix_add_addr(struct in_addr ad
4888         if (dom->flavour != RPC_AUTH_UNIX)
4889                 return -EINVAL;
4890         udom = container_of(dom, struct unix_domain, h);
4891 -       ip.m_class = "nfsd";
4892 +       ip.m_class = strdup("nfsd");
4893 +       if (!ip.m_class)
4894 +               return -ENOMEM;
4895         ip.m_addr = addr;
4896         ip.m_client = udom;
4897         ip.m_add_change = udom->addr_changes+1;
4898 @@ -274,6 +280,7 @@ int auth_unix_add_addr(struct in_addr ad
4899         ip.h.expiry_time = NEVER;
4900         
4901         ipmp = ip_map_lookup(&ip, 1);
4902 +       if (ip.m_class) kfree(ip.m_class);
4903         if (ipmp) {
4904                 ip_map_put(&ipmp->h, &ip_map_cache);
4905                 return 0;
4906 diff -puN fs/nfsd/stats.c~CITI_NFS4_ALL fs/nfsd/stats.c
4907 --- linux-2.6.3/fs/nfsd/stats.c~CITI_NFS4_ALL   2004-02-19 16:47:04.000000000 -0500
4908 +++ linux-2.6.3-bfields/fs/nfsd/stats.c 2004-02-19 16:47:04.000000000 -0500
4909 @@ -26,6 +26,7 @@
4910  #include <linux/kernel.h>
4911  #include <linux/time.h>
4912  #include <linux/proc_fs.h>
4913 +#include <linux/seq_file.h>
4914  #include <linux/stat.h>
4915  #include <linux/module.h>
4916  
4917 @@ -39,14 +40,11 @@ struct svc_stat             nfsd_svcstats = {
4918         .program        = &nfsd_program,
4919  };
4920  
4921 -static int
4922 -nfsd_proc_read(char *buffer, char **start, off_t offset, int count,
4923 -                               int *eof, void *data)
4924 +static int nfsd_proc_show(struct seq_file *seq, void *v)
4925  {
4926 -       int     len;
4927 -       int     i;
4928 +       int i;
4929  
4930 -       len = sprintf(buffer, "rc %u %u %u\nfh %u %u %u %u %u\nio %u %u\n",
4931 +       seq_printf(seq, "rc %u %u %u\nfh %u %u %u %u %u\nio %u %u\n",
4932                       nfsdstats.rchits,
4933                       nfsdstats.rcmisses,
4934                       nfsdstats.rcnocache,
4935 @@ -58,57 +56,42 @@ nfsd_proc_read(char *buffer, char **star
4936                       nfsdstats.io_read,
4937                       nfsdstats.io_write);
4938         /* thread usage: */
4939 -       len += sprintf(buffer+len, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt);
4940 +       seq_printf(seq, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt);
4941         for (i=0; i<10; i++) {
4942                 unsigned int jifs = nfsdstats.th_usage[i];
4943                 unsigned int sec = jifs / HZ, msec = (jifs % HZ)*1000/HZ;
4944 -               len += sprintf(buffer+len, " %u.%03u", sec, msec);
4945 +               seq_printf(seq, " %u.%03u", sec, msec);
4946         }
4947  
4948         /* newline and ra-cache */
4949 -       len += sprintf(buffer+len, "\nra %u", nfsdstats.ra_size);
4950 +       seq_printf(seq, "\nra %u", nfsdstats.ra_size);
4951         for (i=0; i<11; i++)
4952 -               len += sprintf(buffer+len, " %u", nfsdstats.ra_depth[i]);
4953 -       len += sprintf(buffer+len, "\n");
4954 +               seq_printf(seq, " %u", nfsdstats.ra_depth[i]);
4955 +       seq_putc(seq, '\n');
4956         
4957 +       /* show my rpc info */
4958 +       svc_seq_show(seq, &nfsd_svcstats);
4959  
4960 -       /* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
4961 -       *eof = 0;
4962 -
4963 -       /*
4964 -        * Append generic nfsd RPC statistics if there's room for it.
4965 -        */
4966 -       if (len <= offset) {
4967 -               len = svc_proc_read(buffer, start, offset - len, count,
4968 -                                   eof, data);
4969 -               return len;
4970 -       }
4971 -
4972 -       if (len < count) {
4973 -               len += svc_proc_read(buffer + len, start, 0, count - len,
4974 -                                    eof, data);
4975 -       }
4976 -
4977 -       if (offset >= len) {
4978 -               *start = buffer;
4979 -               return 0;
4980 -       }
4981 +       return 0;
4982 +}
4983  
4984 -       *start = buffer + offset;
4985 -       if ((len -= offset) > count)
4986 -               return count;
4987 -       return len;
4988 +static int nfsd_proc_open(struct inode *inode, struct file *file)
4989 +{
4990 +       return single_open(file, nfsd_proc_show, NULL);
4991  }
4992  
4993 +static struct file_operations nfsd_proc_fops = {
4994 +       .owner = THIS_MODULE,
4995 +       .open = nfsd_proc_open,
4996 +       .read  = seq_read,
4997 +       .llseek = seq_lseek,
4998 +       .release = single_release,
4999 +};     
5000 +
5001  void
5002  nfsd_stat_init(void)
5003  {
5004 -       struct proc_dir_entry   *ent;
5005 -
5006 -       if ((ent = svc_proc_register(&nfsd_svcstats)) != 0) {
5007 -               ent->read_proc = nfsd_proc_read;
5008 -               ent->owner = THIS_MODULE;
5009 -       }
5010 +       svc_proc_register(&nfsd_svcstats, &nfsd_proc_fops);
5011  }
5012  
5013  void
5014 diff -puN include/linux/sunrpc/stats.h~CITI_NFS4_ALL include/linux/sunrpc/stats.h
5015 --- linux-2.6.3/include/linux/sunrpc/stats.h~CITI_NFS4_ALL      2004-02-19 16:47:04.000000000 -0500
5016 +++ linux-2.6.3-bfields/include/linux/sunrpc/stats.h    2004-02-19 16:47:04.000000000 -0500
5017 @@ -48,14 +48,13 @@ void                        rpc_modcount(struct inode *, int)
5018  #ifdef CONFIG_PROC_FS
5019  struct proc_dir_entry *        rpc_proc_register(struct rpc_stat *);
5020  void                   rpc_proc_unregister(const char *);
5021 -int                    rpc_proc_read(char *, char **, off_t, int,
5022 -                                       int *, void *);
5023  void                   rpc_proc_zero(struct rpc_program *);
5024 -struct proc_dir_entry *        svc_proc_register(struct svc_stat *);
5025 +struct proc_dir_entry *        svc_proc_register(struct svc_stat *, 
5026 +                                         struct file_operations *);
5027  void                   svc_proc_unregister(const char *);
5028 -int                    svc_proc_read(char *, char **, off_t, int,
5029 -                                       int *, void *);
5030 -void                   svc_proc_zero(struct svc_program *);
5031 +
5032 +void                   svc_seq_show(struct seq_file *, 
5033 +                                    const struct svc_stat *);
5034  
5035  extern struct proc_dir_entry   *proc_net_rpc;
5036  
5037 @@ -63,13 +62,14 @@ extern struct proc_dir_entry        *proc_net_r
5038  
5039  static inline struct proc_dir_entry *rpc_proc_register(struct rpc_stat *s) { return NULL; }
5040  static inline void rpc_proc_unregister(const char *p) {}
5041 -static inline int rpc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f) { return 0; }
5042  static inline void rpc_proc_zero(struct rpc_program *p) {}
5043  
5044 -static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s) { return NULL; }
5045 +static inline struct proc_dir_entry *svc_proc_register(struct svc_stat *s,
5046 +                                                      struct file_operations *f) { return NULL; }
5047  static inline void svc_proc_unregister(const char *p) {}
5048 -static inline int svc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f) { return 0; }
5049 -static inline void svc_proc_zero(struct svc_program *p) {}
5050 +
5051 +static inline void svc_seq_show(struct seq_file *seq, 
5052 +                               const struct svc_stat *st) {}
5053  
5054  #define proc_net_rpc NULL
5055  
5056 diff -puN net/sunrpc/stats.c~CITI_NFS4_ALL net/sunrpc/stats.c
5057 --- linux-2.6.3/net/sunrpc/stats.c~CITI_NFS4_ALL        2004-02-19 16:47:04.000000000 -0500
5058 +++ linux-2.6.3-bfields/net/sunrpc/stats.c      2004-02-19 16:47:04.000000000 -0500
5059 @@ -18,6 +18,7 @@
5060  #include <linux/kernel.h>
5061  #include <linux/sched.h>
5062  #include <linux/proc_fs.h>
5063 +#include <linux/seq_file.h>
5064  #include <linux/sunrpc/clnt.h>
5065  #include <linux/sunrpc/svcsock.h>
5066  
5067 @@ -28,70 +29,66 @@ struct proc_dir_entry       *proc_net_rpc = NU
5068  /*
5069   * Get RPC client stats
5070   */
5071 -int
5072 -rpc_proc_read(char *buffer, char **start, off_t offset, int count,
5073 -                               int *eof, void *data)
5074 -{
5075 -       struct rpc_stat *statp = (struct rpc_stat *) data;
5076 -       struct rpc_program *prog = statp->program;
5077 -       struct rpc_version *vers;
5078 -       int             len, i, j;
5079 +static int rpc_proc_show(struct seq_file *seq, void *v) {
5080 +       const struct rpc_stat   *statp = seq->private;
5081 +       const struct rpc_program *prog = statp->program;
5082 +       int             i, j;
5083  
5084 -       len = sprintf(buffer,
5085 +       seq_printf(seq, 
5086                 "net %d %d %d %d\n",
5087                         statp->netcnt,
5088                         statp->netudpcnt,
5089                         statp->nettcpcnt,
5090                         statp->nettcpconn);
5091 -       len += sprintf(buffer + len,
5092 +       seq_printf(seq, 
5093                 "rpc %d %d %d\n",
5094                         statp->rpccnt,
5095                         statp->rpcretrans,
5096                         statp->rpcauthrefresh);
5097  
5098         for (i = 0; i < prog->nrvers; i++) {
5099 -               if (!(vers = prog->version[i]))
5100 +               const struct rpc_version *vers = prog->version[i];
5101 +               if (!vers)
5102                         continue;
5103 -               len += sprintf(buffer + len, "proc%d %d",
5104 +               seq_printf(seq, "proc%d %d",
5105                                         vers->number, vers->nrprocs);
5106                 for (j = 0; j < vers->nrprocs; j++)
5107 -                       len += sprintf(buffer + len, " %d",
5108 +                       seq_printf(seq, " %d",
5109                                         vers->procs[j].p_count);
5110 -               buffer[len++] = '\n';
5111 +               seq_putc(seq, '\n');
5112         }
5113 +       return 0;
5114 +}
5115  
5116 -       if (offset >= len) {
5117 -               *start = buffer;
5118 -               *eof = 1;
5119 -               return 0;
5120 -       }
5121 -       *start = buffer + offset;
5122 -       if ((len -= offset) > count)
5123 -               return count;
5124 -       *eof = 1;
5125 -       return len;
5126 +static int rpc_proc_open(struct inode *inode, struct file *file)
5127 +{
5128 +       return single_open(file, rpc_proc_show, PDE(inode)->data);
5129  }
5130  
5131 +static struct file_operations rpc_proc_fops = {
5132 +       .owner = THIS_MODULE,
5133 +       .open = rpc_proc_open,
5134 +       .read  = seq_read,
5135 +       .llseek = seq_lseek,
5136 +       .release = single_release,
5137 +};     
5138 +
5139  /*
5140   * Get RPC server stats
5141   */
5142 -int
5143 -svc_proc_read(char *buffer, char **start, off_t offset, int count,
5144 -                               int *eof, void *data)
5145 -{
5146 -       struct svc_stat *statp  = (struct svc_stat *) data;
5147 -       struct svc_program *prog = statp->program;
5148 -       struct svc_procedure *proc;
5149 -       struct svc_version *vers;
5150 -       int             len, i, j;
5151 +void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
5152 +       const struct svc_program *prog = statp->program;
5153 +       const struct svc_procedure *proc;
5154 +       const struct svc_version *vers;
5155 +       int             i, j;
5156  
5157 -       len = sprintf(buffer,
5158 +       seq_printf(seq, 
5159                 "net %d %d %d %d\n",
5160                         statp->netcnt,
5161                         statp->netudpcnt,
5162                         statp->nettcpcnt,
5163                         statp->nettcpconn);
5164 -       len += sprintf(buffer + len,
5165 +       seq_printf(seq, 
5166                 "rpc %d %d %d %d %d\n",
5167                         statp->rpccnt,
5168                         statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
5169 @@ -102,41 +99,36 @@ svc_proc_read(char *buffer, char **start
5170         for (i = 0; i < prog->pg_nvers; i++) {
5171                 if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
5172                         continue;
5173 -               len += sprintf(buffer + len, "proc%d %d", i, vers->vs_nproc);
5174 +               seq_printf(seq, "proc%d %d", i, vers->vs_nproc);
5175                 for (j = 0; j < vers->vs_nproc; j++, proc++)
5176 -                       len += sprintf(buffer + len, " %d", proc->pc_count);
5177 -               buffer[len++] = '\n';
5178 +                       seq_printf(seq, " %d", proc->pc_count);
5179 +               seq_putc(seq, '\n');
5180         }
5181 -
5182 -       if (offset >= len) {
5183 -               *start = buffer;
5184 -               *eof = 1;
5185 -               return 0;
5186 -       }
5187 -       *start = buffer + offset;
5188 -       if ((len -= offset) > count)
5189 -               return count;
5190 -       *eof = 1;
5191 -       return len;
5192  }
5193  
5194  /*
5195   * Register/unregister RPC proc files
5196   */
5197  static inline struct proc_dir_entry *
5198 -do_register(const char *name, void *data, int issvc)
5199 +do_register(const char *name, void *data, struct file_operations *fops)
5200  {
5201 +       struct proc_dir_entry *ent;
5202 +
5203         rpc_proc_init();
5204         dprintk("RPC: registering /proc/net/rpc/%s\n", name);
5205 -       return create_proc_read_entry(name, 0, proc_net_rpc, 
5206 -                                     issvc? svc_proc_read : rpc_proc_read,
5207 -                                     data);
5208 +
5209 +       ent = create_proc_entry(name, 0, proc_net_rpc);
5210 +       if (ent) {
5211 +               ent->proc_fops = fops;
5212 +               ent->data = data;
5213 +       }
5214 +       return ent;
5215  }
5216  
5217  struct proc_dir_entry *
5218  rpc_proc_register(struct rpc_stat *statp)
5219  {
5220 -       return do_register(statp->program->name, statp, 0);
5221 +       return do_register(statp->program->name, statp, &rpc_proc_fops);
5222  }
5223  
5224  void
5225 @@ -146,9 +138,9 @@ rpc_proc_unregister(const char *name)
5226  }
5227  
5228  struct proc_dir_entry *
5229 -svc_proc_register(struct svc_stat *statp)
5230 +svc_proc_register(struct svc_stat *statp, struct file_operations *fops)
5231  {
5232 -       return do_register(statp->program->pg_name, statp, 1);
5233 +       return do_register(statp->program->pg_name, statp, fops);
5234  }
5235  
5236  void
5237 @@ -163,7 +155,7 @@ rpc_proc_init(void)
5238         dprintk("RPC: registering /proc/net/rpc\n");
5239         if (!proc_net_rpc) {
5240                 struct proc_dir_entry *ent;
5241 -               ent = proc_mkdir("net/rpc", 0);
5242 +               ent = proc_mkdir("rpc", proc_net);
5243                 if (ent) {
5244                         ent->owner = THIS_MODULE;
5245                         proc_net_rpc = ent;
5246 diff -puN net/sunrpc/sunrpc_syms.c~CITI_NFS4_ALL net/sunrpc/sunrpc_syms.c
5247 --- linux-2.6.3/net/sunrpc/sunrpc_syms.c~CITI_NFS4_ALL  2004-02-19 16:47:04.000000000 -0500
5248 +++ linux-2.6.3-bfields/net/sunrpc/sunrpc_syms.c        2004-02-19 16:47:04.000000000 -0500
5249 @@ -85,15 +85,16 @@ EXPORT_SYMBOL(svc_recv);
5250  EXPORT_SYMBOL(svc_wake_up);
5251  EXPORT_SYMBOL(svc_makesock);
5252  EXPORT_SYMBOL(svc_reserve);
5253 +EXPORT_SYMBOL(svc_auth_register);
5254 +EXPORT_SYMBOL(auth_domain_lookup);
5255  
5256  /* RPC statistics */
5257  #ifdef CONFIG_PROC_FS
5258  EXPORT_SYMBOL(rpc_proc_register);
5259  EXPORT_SYMBOL(rpc_proc_unregister);
5260 -EXPORT_SYMBOL(rpc_proc_read);
5261  EXPORT_SYMBOL(svc_proc_register);
5262  EXPORT_SYMBOL(svc_proc_unregister);
5263 -EXPORT_SYMBOL(svc_proc_read);
5264 +EXPORT_SYMBOL(svc_seq_show);
5265  #endif
5266  
5267  /* caching... */
5268 diff -puN net/sunrpc/auth_gss/gss_krb5_seal.c~CITI_NFS4_ALL net/sunrpc/auth_gss/gss_krb5_seal.c
5269 --- linux-2.6.3/net/sunrpc/auth_gss/gss_krb5_seal.c~CITI_NFS4_ALL       2004-02-19 16:47:04.000000000 -0500
5270 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/gss_krb5_seal.c     2004-02-19 16:47:07.000000000 -0500
5271 @@ -101,12 +101,12 @@ krb5_make_token(struct krb5_ctx *ctx, in
5272                         checksum_type = CKSUMTYPE_RSA_MD5;
5273                         break;
5274                 default:
5275 -                       dprintk("RPC: gss_krb5_seal: ctx->signalg %d not"
5276 +                       dprintk("RPC:      gss_krb5_seal: ctx->signalg %d not"
5277                                 " supported\n", ctx->signalg);
5278                         goto out_err;
5279         }
5280         if (ctx->sealalg != SEAL_ALG_NONE && ctx->sealalg != SEAL_ALG_DES) {
5281 -               dprintk("RPC: gss_krb5_seal: ctx->sealalg %d not supported\n",
5282 +               dprintk("RPC:      gss_krb5_seal: ctx->sealalg %d not supported\n",
5283                         ctx->sealalg);
5284                 goto out_err;
5285         }
5286 @@ -151,7 +151,7 @@ krb5_make_token(struct krb5_ctx *ctx, in
5287                        md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
5288                        KRB5_CKSUM_LENGTH);
5289  
5290 -               dprintk("make_seal_token: cksum data: \n");
5291 +               dprintk("RPC:      make_seal_token: cksum data: \n");
5292                 print_hexl((u32 *) (krb5_hdr + 16), KRB5_CKSUM_LENGTH, 0);
5293                 break;
5294         default:
5295 @@ -169,8 +169,5 @@ krb5_make_token(struct krb5_ctx *ctx, in
5296         return ((ctx->endtime < now) ? GSS_S_CONTEXT_EXPIRED : GSS_S_COMPLETE);
5297  out_err:
5298         if (md5cksum.data) kfree(md5cksum.data);
5299 -       if (token->data) kfree(token->data);
5300 -       token->data = 0;
5301 -       token->len = 0;
5302         return GSS_S_FAILURE;
5303  }
5304 diff -puN include/linux/sunrpc/auth_gss.h~CITI_NFS4_ALL include/linux/sunrpc/auth_gss.h
5305 --- linux-2.6.3/include/linux/sunrpc/auth_gss.h~CITI_NFS4_ALL   2004-02-19 16:47:04.000000000 -0500
5306 +++ linux-2.6.3-bfields/include/linux/sunrpc/auth_gss.h 2004-02-19 16:47:04.000000000 -0500
5307 @@ -62,8 +62,6 @@ struct rpc_gss_init_res {
5308         struct xdr_netobj       gr_token;       /* token */
5309  };
5310  
5311 -#define GSS_SEQ_WIN    5
5312 -
5313  /* The gss_cl_ctx struct holds all the information the rpcsec_gss client
5314   * code needs to know about a single security context.  In particular,
5315   * gc_gss_ctx is the context handle that is used to do gss-api calls, while
5316 diff -puN include/linux/sunrpc/gss_api.h~CITI_NFS4_ALL include/linux/sunrpc/gss_api.h
5317 --- linux-2.6.3/include/linux/sunrpc/gss_api.h~CITI_NFS4_ALL    2004-02-19 16:47:04.000000000 -0500
5318 +++ linux-2.6.3-bfields/include/linux/sunrpc/gss_api.h  2004-02-19 16:47:04.000000000 -0500
5319 @@ -120,6 +120,9 @@ int gss_mech_unregister_all(void);
5320   * reference count. */
5321  struct gss_api_mech * gss_mech_get_by_OID(struct xdr_netobj *);
5322  
5323 +/* Similar, but get by name like "krb5", "spkm", etc., instead of OID. */
5324 +struct gss_api_mech *gss_mech_get_by_name(char *);
5325 +
5326  /* Just increments the mechanism's reference count and returns its input: */
5327  struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
5328  
5329 diff -puN /dev/null include/linux/sunrpc/svcauth_gss.h
5330 --- /dev/null   2004-01-26 19:20:21.000000000 -0500
5331 +++ linux-2.6.3-bfields/include/linux/sunrpc/svcauth_gss.h      2004-02-19 16:47:04.000000000 -0500
5332 @@ -0,0 +1,35 @@
5333 +/*
5334 + * linux/include/linux/svcauth_gss.h
5335 + *
5336 + * Bruce Fields <bfields@umich.edu>
5337 + * Copyright (c) 2002 The Regents of the Unviersity of Michigan
5338 + *
5339 + * Id: linux-2.6.3-CITI_NFS4_ALL.patch,v 1.2.4.1 2004/03/17 23:55:23 adilger Exp $
5340 + *
5341 + */
5342 +
5343 +#ifndef _LINUX_SUNRPC_SVCAUTH_GSS_H
5344 +#define _LINUX_SUNRPC_SVCAUTH_GSS_H
5345 +
5346 +#ifdef __KERNEL__
5347 +#include <linux/sched.h>
5348 +#include <linux/sunrpc/types.h>
5349 +#include <linux/sunrpc/xdr.h>
5350 +#include <linux/sunrpc/svcauth.h>
5351 +#include <linux/sunrpc/svcsock.h>
5352 +#include <linux/sunrpc/auth_gss.h>
5353 +
5354 +int gss_svc_init(void);
5355 +int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
5356 +
5357 +
5358 +struct gss_svc_data {
5359 +       /* decoded gss client cred: */
5360 +       struct rpc_gss_wire_cred        clcred;
5361 +       /* pointer to the beginning of the procedure-specific results, which
5362 +        * may be encrypted/checksummed in svcauth_gss_release: */
5363 +       u32                             *body_start;
5364 +};
5365 +
5366 +#endif /* __KERNEL__ */
5367 +#endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */
5368 diff -puN include/linux/sunrpc/svcauth.h~CITI_NFS4_ALL include/linux/sunrpc/svcauth.h
5369 --- linux-2.6.3/include/linux/sunrpc/svcauth.h~CITI_NFS4_ALL    2004-02-19 16:47:04.000000000 -0500
5370 +++ linux-2.6.3-bfields/include/linux/sunrpc/svcauth.h  2004-02-19 16:47:04.000000000 -0500
5371 @@ -65,6 +65,10 @@ struct auth_domain {
5372   *      GARBAGE - rpc garbage_args error
5373   *      SYSERR - rpc system_err error
5374   *      DENIED - authp holds reason for denial.
5375 + *      COMPLETE - the reply is encoded already and ready to be sent; no
5376 + *             further processing is necessary.  (This is used for processing
5377 + *             null procedure calls which are used to set up encryption
5378 + *             contexts.)
5379   *
5380   *   accept is passed the proc number so that it can accept NULL rpc requests
5381   *   even if it cannot authenticate the client (as is sometimes appropriate).
5382 @@ -97,6 +101,7 @@ extern struct auth_ops       *authtab[RPC_AUTH
5383  #define        SVC_DROP        6
5384  #define        SVC_DENIED      7
5385  #define        SVC_PENDING     8
5386 +#define        SVC_COMPLETE    9
5387  
5388  
5389  extern int     svc_authenticate(struct svc_rqst *rqstp, u32 *authp);
5390 diff -puN include/linux/sunrpc/svc.h~CITI_NFS4_ALL include/linux/sunrpc/svc.h
5391 --- linux-2.6.3/include/linux/sunrpc/svc.h~CITI_NFS4_ALL        2004-02-19 16:47:04.000000000 -0500
5392 +++ linux-2.6.3-bfields/include/linux/sunrpc/svc.h      2004-02-19 16:47:04.000000000 -0500
5393 @@ -135,6 +135,7 @@ struct svc_rqst {
5394  
5395         void *                  rq_argp;        /* decoded arguments */
5396         void *                  rq_resp;        /* xdr'd results */
5397 +       void *                  rq_auth_data;   /* flavor-specific data */
5398  
5399         int                     rq_reserved;    /* space on socket outq
5400                                                  * reserved for this request
5401 diff -puN net/sunrpc/auth_gss/auth_gss.c~CITI_NFS4_ALL net/sunrpc/auth_gss/auth_gss.c
5402 --- linux-2.6.3/net/sunrpc/auth_gss/auth_gss.c~CITI_NFS4_ALL    2004-02-19 16:47:04.000000000 -0500
5403 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/auth_gss.c  2004-02-19 16:47:07.000000000 -0500
5404 @@ -48,6 +48,7 @@
5405  #include <linux/sunrpc/clnt.h>
5406  #include <linux/sunrpc/auth.h>
5407  #include <linux/sunrpc/auth_gss.h>
5408 +#include <linux/sunrpc/svcauth_gss.h>
5409  #include <linux/sunrpc/gss_err.h>
5410  #include <linux/workqueue.h>
5411  #include <linux/sunrpc/rpc_pipe_fs.h>
5412 @@ -279,7 +280,7 @@ err_free_ctx:
5413         kfree(ctx);
5414  err:
5415         *gc = NULL;
5416 -       dprintk("RPC: gss_parse_init_downcall returning %d\n", err);
5417 +       dprintk("RPC:      gss_parse_init_downcall returning %d\n", err);
5418         return err;
5419  }
5420  
5421 @@ -310,8 +311,10 @@ __gss_find_upcall(struct gss_auth *gss_a
5422                 if (pos->uid != uid)
5423                         continue;
5424                 atomic_inc(&pos->count);
5425 +               dprintk("RPC:      gss_find_upcall found msg %p\n", pos);
5426                 return pos;
5427         }
5428 +       dprintk("RPC:      gss_find_upcall found nothing\n");
5429         return NULL;
5430  }
5431  
5432 @@ -349,6 +352,8 @@ gss_upcall(struct rpc_clnt *clnt, struct
5433         uid_t uid = cred->cr_uid;
5434         int res = 0;
5435  
5436 +       dprintk("RPC: %4u gss_upcall for uid %u\n", task->tk_pid, uid);
5437 +
5438  retry:
5439         spin_lock(&gss_auth->lock);
5440         gss_msg = __gss_find_upcall(gss_auth, uid);
5441 @@ -357,8 +362,10 @@ retry:
5442         if (gss_new == NULL) {
5443                 spin_unlock(&gss_auth->lock);
5444                 gss_new = kmalloc(sizeof(*gss_new), GFP_KERNEL);
5445 -               if (!gss_new)
5446 +               if (!gss_new) {
5447 +                       dprintk("RPC: %4u gss_upcall -ENOMEM\n", task->tk_pid);
5448                         return -ENOMEM;
5449 +               }
5450                 goto retry;
5451         }
5452         gss_msg = gss_new;
5453 @@ -388,10 +395,12 @@ retry:
5454                 spin_unlock(&gss_auth->lock);
5455         }
5456         gss_release_msg(gss_msg);
5457 +       dprintk("RPC: %4u gss_upcall for uid %u result %d", task->tk_pid,
5458 +                       uid, res);
5459         return res;
5460  out_sleep:
5461 -       /* Sleep forever */
5462 -       task->tk_timeout = 0;
5463 +       dprintk("RPC: %4u gss_upcall  sleeping\n", task->tk_pid);
5464 +       task->tk_timeout = 0;           /* Sleep forever */
5465         rpc_sleep_on(&gss_msg->waitq, task, NULL, NULL);
5466         spin_unlock(&gss_auth->lock);
5467         if (gss_new)
5468 @@ -476,12 +485,13 @@ gss_pipe_downcall(struct file *filp, con
5469         } else
5470                 spin_unlock(&gss_auth->lock);
5471         rpc_release_client(clnt);
5472 +       dprintk("RPC:      gss_pipe_downcall returning length %u\n", mlen);
5473         return mlen;
5474  err:
5475         if (ctx)
5476                 gss_destroy_ctx(ctx);
5477         rpc_release_client(clnt);
5478 -       dprintk("RPC: gss_pipe_downcall returning %d\n", err);
5479 +       dprintk("RPC:      gss_pipe_downcall returning %d\n", err);
5480         return err;
5481  }
5482  
5483 @@ -519,6 +529,8 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg
5484         static unsigned long ratelimit;
5485  
5486         if (msg->errno < 0) {
5487 +               dprintk("RPC:      gss_pipe_destroy_msg releasing msg %p\n",
5488 +                               gss_msg);
5489                 atomic_inc(&gss_msg->count);
5490                 gss_unhash_msg(gss_msg);
5491                 if (msg->errno == -ETIMEDOUT || msg->errno == -EPIPE) {
5492 @@ -543,7 +555,8 @@ gss_create(struct rpc_clnt *clnt, rpc_au
5493         struct gss_auth *gss_auth;
5494         struct rpc_auth * auth;
5495  
5496 -       dprintk("RPC: creating GSS authenticator for client %p\n",clnt);
5497 +       dprintk("RPC:      creating GSS authenticator for client %p\n",clnt);
5498 +
5499         if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL)))
5500                 goto out_dec;
5501         gss_auth->mech = gss_pseudoflavor_to_mech(flavor);
5502 @@ -581,7 +594,8 @@ static void
5503  gss_destroy(struct rpc_auth *auth)
5504  {
5505         struct gss_auth *gss_auth;
5506 -       dprintk("RPC: destroying GSS authenticator %p flavor %d\n",
5507 +
5508 +       dprintk("RPC:      destroying GSS authenticator %p flavor %d\n",
5509                 auth, auth->au_flavor);
5510  
5511         gss_auth = container_of(auth, struct gss_auth, rpc_auth);
5512 @@ -596,8 +610,7 @@ gss_destroy(struct rpc_auth *auth)
5513  static void
5514  gss_destroy_ctx(struct gss_cl_ctx *ctx)
5515  {
5516 -
5517 -       dprintk("RPC: gss_destroy_ctx\n");
5518 +       dprintk("RPC:      gss_destroy_ctx\n");
5519  
5520         if (ctx->gc_gss_ctx)
5521                 gss_delete_sec_context(&ctx->gc_gss_ctx);
5522 @@ -616,7 +629,7 @@ gss_destroy_cred(struct rpc_cred *rc)
5523  {
5524         struct gss_cred *cred = (struct gss_cred *)rc;
5525  
5526 -       dprintk("RPC: gss_destroy_cred \n");
5527 +       dprintk("RPC:      gss_destroy_cred \n");
5528  
5529         if (cred->gc_ctx)
5530                 gss_put_ctx(cred->gc_ctx);
5531 @@ -628,7 +641,7 @@ gss_create_cred(struct rpc_auth *auth, s
5532  {
5533         struct gss_cred *cred = NULL;
5534  
5535 -       dprintk("RPC: gss_create_cred for uid %d, flavor %d\n",
5536 +       dprintk("RPC:      gss_create_cred for uid %d, flavor %d\n",
5537                 acred->uid, auth->au_flavor);
5538  
5539         if (!(cred = kmalloc(sizeof(*cred), GFP_KERNEL)))
5540 @@ -648,7 +661,7 @@ gss_create_cred(struct rpc_auth *auth, s
5541         return (struct rpc_cred *) cred;
5542  
5543  out_err:
5544 -       dprintk("RPC: gss_create_cred failed\n");
5545 +       dprintk("RPC:      gss_create_cred failed\n");
5546         if (cred) gss_destroy_cred((struct rpc_cred *)cred);
5547         return NULL;
5548  }
5549 @@ -659,6 +672,15 @@ gss_match(struct auth_cred *acred, struc
5550         return (rc->cr_uid == acred->uid);
5551  }
5552  
5553 +static void
5554 +shift_seqnos(u32 *seqnos)
5555 +{
5556 +       int i;
5557 +
5558 +       for (i=1; i < GSS_SEQNO_CACHE; i++)
5559 +               seqnos[i] = seqnos[i-1];
5560 +}
5561 +
5562  /*
5563  * Marshal credentials.
5564  * Maybe we should keep a cached credential for performance reasons.
5565 @@ -678,24 +700,25 @@ gss_marshal(struct rpc_task *task, u32 *
5566         struct xdr_buf  verf_buf;
5567         u32             service;
5568  
5569 -       dprintk("RPC: gss_marshal\n");
5570 +       dprintk("RPC: %4u gss_marshal\n", task->tk_pid);
5571  
5572         *p++ = htonl(RPC_AUTH_GSS);
5573         cred_len = p++;
5574  
5575         service = gss_pseudoflavor_to_service(gss_cred->gc_flavor);
5576         if (service == 0) {
5577 -               dprintk("Bad pseudoflavor %d in gss_marshal\n",
5578 -                       gss_cred->gc_flavor);
5579 +               dprintk("RPC: %4u Bad pseudoflavor %d in gss_marshal\n",
5580 +                       task->tk_pid, gss_cred->gc_flavor);
5581                 goto out_put_ctx;
5582         }
5583 +       shift_seqnos(req->rq_seqnos);
5584         spin_lock(&ctx->gc_seq_lock);
5585 -       req->rq_seqno = ctx->gc_seq++;
5586 +       req->rq_seqnos[0] = ctx->gc_seq++;
5587         spin_unlock(&ctx->gc_seq_lock);
5588  
5589         *p++ = htonl((u32) RPC_GSS_VERSION);
5590         *p++ = htonl((u32) ctx->gc_proc);
5591 -       *p++ = htonl((u32) req->rq_seqno);
5592 +       *p++ = htonl((u32) req->rq_seqnos[0]);
5593         *p++ = htonl((u32) service);
5594         p = xdr_encode_netobj(p, &ctx->gc_wire_ctx);
5595         *cred_len = htonl((p - (cred_len + 1)) << 2);
5596 @@ -745,6 +768,32 @@ gss_refresh(struct rpc_task *task)
5597         return 0;
5598  }
5599  
5600 +static int
5601 +verify_checksum(struct gss_ctx *ctx, struct xdr_netobj *mic, u32 *seqnos)
5602 +{
5603 +       u32             seq, qop_state;
5604 +       struct xdr_buf  verf_buf;
5605 +       struct iovec    iov;
5606 +       int             i;
5607 +
5608 +       for (i=0; i < GSS_SEQNO_CACHE; i++) {
5609 +               if (i && !seqnos[i])
5610 +                       goto fail;
5611 +               seq = htonl(seqnos[i]);
5612 +               iov.iov_base = &seq;
5613 +               iov.iov_len = sizeof(seq);
5614 +               xdr_buf_from_iov(&iov, &verf_buf);
5615 +               if (!gss_verify_mic(ctx, &verf_buf, mic, &qop_state))
5616 +                       goto success;
5617 +       }
5618 +fail:
5619 +       return -1;
5620 +success:
5621 +       /* So unwrap knows which seqno we used: */
5622 +       seqnos[0] = seqnos[i];
5623 +       return 0;
5624 +}
5625 +
5626  static u32 *
5627  gss_validate(struct rpc_task *task, u32 *p)
5628  {
5629 @@ -752,28 +801,21 @@ gss_validate(struct rpc_task *task, u32 
5630         struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
5631                                                 gc_base);
5632         struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
5633 -       u32             seq, qop_state;
5634 -       struct iovec    iov;
5635 -       struct xdr_buf  verf_buf;
5636         struct xdr_netobj mic;
5637         u32             flav,len;
5638         u32             service;
5639  
5640 -       dprintk("RPC: gss_validate\n");
5641 +       dprintk("RPC: %4u gss_validate\n", task->tk_pid);
5642  
5643         flav = ntohl(*p++);
5644         if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE)
5645                  goto out_bad;
5646         if (flav != RPC_AUTH_GSS)
5647                 goto out_bad;
5648 -       seq = htonl(task->tk_rqstp->rq_seqno);
5649 -       iov.iov_base = &seq;
5650 -       iov.iov_len = sizeof(seq);
5651 -       xdr_buf_from_iov(&iov, &verf_buf);
5652 +
5653         mic.data = (u8 *)p;
5654         mic.len = len;
5655 -
5656 -       if (gss_verify_mic(ctx->gc_gss_ctx, &verf_buf, &mic, &qop_state))
5657 +       if (verify_checksum(ctx->gc_gss_ctx, &mic, task->tk_rqstp->rq_seqnos))
5658                 goto out_bad;
5659         service = gss_pseudoflavor_to_service(gss_cred->gc_flavor);
5660         switch (service) {
5661 @@ -789,9 +831,12 @@ gss_validate(struct rpc_task *task, u32 
5662                goto out_bad;
5663         }
5664         gss_put_ctx(ctx);
5665 +       dprintk("RPC: %4u GSS gss_validate: gss_verify_mic succeeded.\n",
5666 +                       task->tk_pid);
5667         return p + XDR_QUADLEN(len);
5668  out_bad:
5669         gss_put_ctx(ctx);
5670 +       dprintk("RPC: %4u gss_validate failed.\n", task->tk_pid);
5671         return NULL;
5672  }
5673  
5674 @@ -814,7 +859,7 @@ gss_wrap_req(struct rpc_task *task,
5675         u32             offset, *q;
5676         struct iovec    *iov;
5677  
5678 -       dprintk("RPC: gss_wrap_body\n");
5679 +       dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid);
5680         BUG_ON(!ctx);
5681         if (ctx->gc_proc != RPC_GSS_PROC_DATA) {
5682                 /* The spec seems a little ambiguous here, but I think that not
5683 @@ -832,7 +877,7 @@ gss_wrap_req(struct rpc_task *task,
5684  
5685                         integ_len = p++;
5686                         offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
5687 -                       *p++ = htonl(req->rq_seqno);
5688 +                       *p++ = htonl(req->rq_seqnos[0]);
5689  
5690                         status = encode(rqstp, p, obj);
5691                         if (status)
5692 @@ -871,7 +916,7 @@ gss_wrap_req(struct rpc_task *task,
5693         status = 0;
5694  out:
5695         gss_put_ctx(ctx);
5696 -       dprintk("RPC: gss_wrap_req returning %d\n", status);
5697 +       dprintk("RPC: %4u gss_wrap_req returning %d\n", task->tk_pid, status);
5698         return status;
5699  }
5700  
5701 @@ -909,7 +954,7 @@ gss_unwrap_resp(struct rpc_task *task,
5702                         mic_offset = integ_len + data_offset;
5703                         if (mic_offset > rcv_buf->len)
5704                                 goto out;
5705 -                       if (ntohl(*p++) != req->rq_seqno)
5706 +                       if (ntohl(*p++) != req->rq_seqnos[0])
5707                                 goto out;
5708  
5709                         if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset,
5710 @@ -932,7 +977,8 @@ out_decode:
5711         status = decode(rqstp, p, obj);
5712  out:
5713         gss_put_ctx(ctx);
5714 -       dprintk("RPC: gss_unwrap_resp returning %d\n", status);
5715 +       dprintk("RPC: %4u gss_unwrap_resp returning %d\n", task->tk_pid,
5716 +                       status);
5717         return status;
5718  }
5719    
5720 @@ -972,6 +1018,15 @@ static int __init init_rpcsec_gss(void)
5721         int err = 0;
5722  
5723         err = rpcauth_register(&authgss_ops);
5724 +       if (err)
5725 +               goto out;
5726 +       err = gss_svc_init();
5727 +       if (err)
5728 +               goto out_unregister;
5729 +       return 0;
5730 +out_unregister:
5731 +       rpcauth_unregister(&authgss_ops);
5732 +out:
5733         return err;
5734  }
5735  
5736 diff -puN net/sunrpc/auth_gss/gss_krb5_mech.c~CITI_NFS4_ALL net/sunrpc/auth_gss/gss_krb5_mech.c
5737 --- linux-2.6.3/net/sunrpc/auth_gss/gss_krb5_mech.c~CITI_NFS4_ALL       2004-02-19 16:47:04.000000000 -0500
5738 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/gss_krb5_mech.c     2004-02-19 16:47:15.000000000 -0500
5739 @@ -39,6 +39,8 @@
5740  #include <linux/types.h>
5741  #include <linux/slab.h>
5742  #include <linux/sunrpc/auth.h>
5743 +#include <linux/in.h>
5744 +#include <linux/sunrpc/svcauth_gss.h>
5745  #include <linux/sunrpc/gss_krb5.h>
5746  #include <linux/sunrpc/xdr.h>
5747  #include <linux/crypto.h>
5748 @@ -98,7 +100,7 @@ get_key(char **p, char *end, struct cryp
5749                         alg_mode = CRYPTO_TFM_MODE_CBC;
5750                         break;
5751                 default:
5752 -                       dprintk("RPC: get_key: unsupported algorithm %d\n", alg);
5753 +                       dprintk("RPC:      get_key: unsupported algorithm %d\n", alg);
5754                         goto out_err_free_key;
5755         }
5756         if (!(*res = crypto_alloc_tfm(alg_name, alg_mode)))
5757 @@ -153,7 +155,7 @@ gss_import_sec_context_kerberos(struct x
5758                 goto out_err_free_key2;
5759  
5760         ctx_id->internal_ctx_id = ctx;
5761 -       dprintk("Succesfully imported new context.\n");
5762 +       dprintk("RPC:      Succesfully imported new context.\n");
5763         return 0;
5764  
5765  out_err_free_key2:
5766 @@ -195,7 +197,7 @@ gss_verify_mic_kerberos(struct gss_ctx              
5767         if (!maj_stat && qop_state)
5768             *qstate = qop_state;
5769  
5770 -       dprintk("RPC: gss_verify_mic_kerberos returning %d\n", maj_stat);
5771 +       dprintk("RPC:      gss_verify_mic_kerberos returning %d\n", maj_stat);
5772         return maj_stat;
5773  }
5774  
5775 @@ -209,7 +211,7 @@ gss_get_mic_kerberos(struct gss_ctx *ctx
5776  
5777         err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG);
5778  
5779 -       dprintk("RPC: gss_get_mic_kerberos returning %d\n",err);
5780 +       dprintk("RPC:      gss_get_mic_kerberos returning %d\n",err);
5781  
5782         return err;
5783  }
5784 @@ -232,6 +234,10 @@ static int __init init_kerberos_module(v
5785         gm = gss_mech_get_by_OID(&gss_mech_krb5_oid);
5786         gss_register_triple(RPC_AUTH_GSS_KRB5 , gm, 0, RPC_GSS_SVC_NONE);
5787         gss_register_triple(RPC_AUTH_GSS_KRB5I, gm, 0, RPC_GSS_SVC_INTEGRITY);
5788 +       if (svcauth_gss_register_pseudoflavor(RPC_AUTH_GSS_KRB5, "krb5"))
5789 +               printk("Failed to register %s with server!\n", "krb5");
5790 +       if (svcauth_gss_register_pseudoflavor(RPC_AUTH_GSS_KRB5I, "krb5i"))
5791 +               printk("Failed to register %s with server!\n", "krb5i");
5792         gss_mech_put(gm);
5793         return 0;
5794  }
5795 diff -puN net/sunrpc/auth_gss/gss_mech_switch.c~CITI_NFS4_ALL net/sunrpc/auth_gss/gss_mech_switch.c
5796 --- linux-2.6.3/net/sunrpc/auth_gss/gss_mech_switch.c~CITI_NFS4_ALL     2004-02-19 16:47:04.000000000 -0500
5797 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/gss_mech_switch.c   2004-02-19 16:47:07.000000000 -0500
5798 @@ -43,7 +43,6 @@
5799  #include <linux/sunrpc/sched.h>
5800  #include <linux/sunrpc/gss_api.h>
5801  #include <linux/sunrpc/clnt.h>
5802 -#include <linux/sunrpc/name_lookup.h>
5803  
5804  #ifdef RPC_DEBUG
5805  # define RPCDBG_FACILITY        RPCDBG_AUTH
5806 @@ -82,7 +81,7 @@ gss_mech_register(struct xdr_netobj * me
5807         spin_lock(&registered_mechs_lock);
5808         list_add(&gm->gm_list, &registered_mechs);
5809         spin_unlock(&registered_mechs_lock);
5810 -       dprintk("RPC: gss_mech_register: registered mechanism with oid:\n");
5811 +       dprintk("RPC:      gss_mech_register: registered mechanism with oid:\n");
5812         print_hexl((u32 *)mech_type->data, mech_type->len, 0);
5813         return 0;
5814  }
5815 @@ -94,11 +93,10 @@ do_gss_mech_unregister(struct gss_api_me
5816  
5817         list_del(&gm->gm_list);
5818  
5819 -       dprintk("RPC: unregistered mechanism with oid:\n");
5820 +       dprintk("RPC:      unregistered mechanism with oid:\n");
5821         print_hexl((u32 *)gm->gm_oid.data, gm->gm_oid.len, 0);
5822         if (!gss_mech_put(gm)) {
5823 -               dprintk("RPC: We just unregistered a gss_mechanism which"
5824 -                               " someone is still using.\n");
5825 +               dprintk("RPC:      We just unregistered a gss_mechanism which someone is still using.\n");
5826                 return -1;
5827         } else {
5828                 return 0;
5829 @@ -146,7 +144,7 @@ gss_mech_get_by_OID(struct xdr_netobj *m
5830  {
5831         struct gss_api_mech     *pos, *gm = NULL;
5832  
5833 -       dprintk("RPC: gss_mech_get_by_OID searching for mechanism with OID:\n");
5834 +       dprintk("RPC:      gss_mech_get_by_OID searching for mechanism with OID:\n");
5835         print_hexl((u32 *)mech_type->data, mech_type->len, 0);
5836         spin_lock(&registered_mechs_lock);
5837         list_for_each_entry(pos, &registered_mechs, gm_list) {
5838 @@ -158,10 +156,27 @@ gss_mech_get_by_OID(struct xdr_netobj *m
5839                 }
5840         }
5841         spin_unlock(&registered_mechs_lock);
5842 -       dprintk("RPC: gss_mech_get_by_OID %s it\n", gm ? "found" : "didn't find");
5843 +       dprintk("RPC:      gss_mech_get_by_OID %s it\n", gm ? "found" : "didn't find");
5844         return gm;
5845  }
5846  
5847 +struct gss_api_mech *
5848 +gss_mech_get_by_name(char *name)
5849 +{
5850 +       struct gss_api_mech     *pos, *gm = NULL;
5851 +
5852 +       spin_lock(&registered_mechs_lock);
5853 +       list_for_each_entry(pos, &registered_mechs, gm_list) {
5854 +               if (0 == strcmp(name, pos->gm_ops->name)) {
5855 +                       gm = gss_mech_get(pos);
5856 +                       break;
5857 +               }
5858 +       }
5859 +       spin_unlock(&registered_mechs_lock);
5860 +       return gm;
5861 +
5862 +}
5863 +
5864  int
5865  gss_mech_put(struct gss_api_mech * gm)
5866  {
5867 @@ -228,7 +243,8 @@ gss_verify_mic(struct gss_ctx               *context_
5868  u32
5869  gss_delete_sec_context(struct gss_ctx  **context_handle)
5870  {
5871 -       dprintk("gss_delete_sec_context deleting %p\n",*context_handle);
5872 +       dprintk("RPC:      gss_delete_sec_context deleting %p\n",
5873 +                       *context_handle);
5874  
5875         if (!*context_handle)
5876                 return(GSS_S_NO_CONTEXT);
5877 diff -puN net/sunrpc/auth_gss/Makefile~CITI_NFS4_ALL net/sunrpc/auth_gss/Makefile
5878 --- linux-2.6.3/net/sunrpc/auth_gss/Makefile~CITI_NFS4_ALL      2004-02-19 16:47:04.000000000 -0500
5879 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/Makefile    2004-02-19 16:47:04.000000000 -0500
5880 @@ -5,7 +5,7 @@
5881  obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o
5882  
5883  auth_rpcgss-objs := auth_gss.o gss_pseudoflavors.o gss_generic_token.o \
5884 -       sunrpcgss_syms.o gss_mech_switch.o
5885 +       sunrpcgss_syms.o gss_mech_switch.o svcauth_gss.o
5886  
5887  obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
5888  
5889 diff -puN net/sunrpc/auth_gss/sunrpcgss_syms.c~CITI_NFS4_ALL net/sunrpc/auth_gss/sunrpcgss_syms.c
5890 --- linux-2.6.3/net/sunrpc/auth_gss/sunrpcgss_syms.c~CITI_NFS4_ALL      2004-02-19 16:47:04.000000000 -0500
5891 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/sunrpcgss_syms.c    2004-02-19 16:47:04.000000000 -0500
5892 @@ -8,6 +8,7 @@
5893  #include <linux/unistd.h>
5894  
5895  #include <linux/sunrpc/auth_gss.h>
5896 +#include <linux/sunrpc/svcauth_gss.h>
5897  #include <linux/sunrpc/gss_asn1.h>
5898  
5899  /* sec_triples: */
5900 @@ -17,6 +18,7 @@ EXPORT_SYMBOL(gss_cmp_triples);
5901  EXPORT_SYMBOL(gss_pseudoflavor_to_mechOID);
5902  EXPORT_SYMBOL(gss_pseudoflavor_supported);
5903  EXPORT_SYMBOL(gss_pseudoflavor_to_service);
5904 +EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor);
5905  
5906  /* registering gss mechanisms to the mech switching code: */
5907  EXPORT_SYMBOL(gss_mech_register);
5908 diff -puN /dev/null net/sunrpc/auth_gss/svcauth_gss.c
5909 --- /dev/null   2004-01-26 19:20:21.000000000 -0500
5910 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/svcauth_gss.c       2004-02-19 16:47:15.000000000 -0500
5911 @@ -0,0 +1,1018 @@
5912 +/*
5913 + * Neil Brown <neilb@cse.unsw.edu.au>
5914 + * J. Bruce Fields <bfields@umich.edu>
5915 + * Andy Adamson <andros@umich.edu>
5916 + * Dug Song <dugsong@monkey.org>
5917 + * 
5918 + * RPCSEC_GSS server authentication.
5919 + * This implements RPCSEC_GSS as defined in rfc2203 (rpcsec_gss) and rfc2078
5920 + * (gssapi)
5921 + * 
5922 + * The RPCSEC_GSS involves three stages:
5923 + *  1/ context creation
5924 + *  2/ data exchange
5925 + *  3/ context destruction
5926 + *
5927 + * Context creation is handled largely by upcalls to user-space.
5928 + *  In particular, GSS_Accept_sec_context is handled by an upcall
5929 + * Data exchange is handled entirely within the kernel
5930 + *  In particular, GSS_GetMIC, GSS_VerifyMIC, GSS_Seal, GSS_Unseal are in-kernel.
5931 + * Context destruction is handled in-kernel
5932 + *  GSS_Delete_sec_context is in-kernel
5933 + *
5934 + * Context creation is initiated by a RPCSEC_GSS_INIT request arriving.
5935 + * The context handle and gss_token are used as a key into the rpcsec_init cache.
5936 + * The content of this cache includes some of the outputs of GSS_Accept_sec_context,
5937 + * being major_status, minor_status, context_handle, reply_token.
5938 + * These are sent back to the client.
5939 + * Sequence window management is handled by the kernel.  The window size if currently
5940 + * a compile time constant.
5941 + *
5942 + * When user-space is happy that a context is established, it places an entry
5943 + * in the rpcsec_context cache. The key for this cache is the context_handle.
5944 + * The content includes:
5945 + *   uid/gidlist - for determining access rights
5946 + *   mechanism type
5947 + *   mechanism specific information, such as a key
5948 + *
5949 + */
5950 +
5951 +#include <linux/types.h>
5952 +#include <linux/module.h>
5953 +#include <linux/pagemap.h>
5954 +
5955 +#include <linux/sunrpc/auth_gss.h>
5956 +#include <linux/sunrpc/svcauth.h>
5957 +#include <linux/sunrpc/gss_err.h>
5958 +#include <linux/sunrpc/svcauth.h>
5959 +#include <linux/sunrpc/svcauth_gss.h>
5960 +#include <linux/sunrpc/cache.h>
5961 +
5962 +#ifdef RPC_DEBUG
5963 +# define RPCDBG_FACILITY       RPCDBG_AUTH
5964 +#endif
5965 +
5966 +/* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests
5967 + * into replies.
5968 + *
5969 + * Key is context handle (\x if empty) and gss_token.
5970 + * Content is major_status minor_status (integers) context_handle, reply_token.
5971 + *
5972 + */
5973 +
5974 +static int netobj_equal(struct xdr_netobj *a, struct xdr_netobj *b)
5975 +{
5976 +       return a->len == b->len && 0 == memcmp(a->data, b->data, a->len);
5977 +}
5978 +
5979 +#define        RSI_HASHBITS    6
5980 +#define        RSI_HASHMAX     (1<<RSI_HASHBITS)
5981 +#define        RSI_HASHMASK    (RSI_HASHMAX-1)
5982 +
5983 +struct rsi {
5984 +       struct cache_head       h;
5985 +       struct xdr_netobj       in_handle, in_token;
5986 +       struct xdr_netobj       out_handle, out_token;
5987 +       int                     major_status, minor_status;
5988 +};
5989 +
5990 +static struct cache_head *rsi_table[RSI_HASHMAX];
5991 +static struct cache_detail rsi_cache;
5992 +static struct rsi *rsi_lookup(struct rsi *item, int set);
5993 +
5994 +static void rsi_free(struct rsi *rsii)
5995 +{
5996 +       kfree(rsii->in_handle.data);
5997 +       kfree(rsii->in_token.data);
5998 +       kfree(rsii->out_handle.data);
5999 +       kfree(rsii->out_token.data);
6000 +}
6001 +
6002 +static void rsi_put(struct cache_head *item, struct cache_detail *cd)
6003 +{
6004 +       struct rsi *rsii = container_of(item, struct rsi, h);
6005 +       if (cache_put(item, cd)) {
6006 +               rsi_free(rsii);
6007 +               kfree(rsii);
6008 +       }
6009 +}
6010 +
6011 +static inline int rsi_hash(struct rsi *item)
6012 +{
6013 +       return hash_mem(item->in_handle.data, item->in_handle.len, RSI_HASHBITS)
6014 +            ^ hash_mem(item->in_token.data, item->in_token.len, RSI_HASHBITS);
6015 +}
6016 +
6017 +static inline int rsi_match(struct rsi *item, struct rsi *tmp)
6018 +{
6019 +       return netobj_equal(&item->in_handle, &tmp->in_handle)
6020 +               && netobj_equal(&item->in_token, &tmp->in_token);
6021 +}
6022 +
6023 +static int dup_to_netobj(struct xdr_netobj *dst, char *src, int len)
6024 +{
6025 +       dst->len = len;
6026 +       dst->data = (len ? kmalloc(len, GFP_KERNEL) : NULL);
6027 +       if (dst->data)
6028 +               memcpy(dst->data, src, len);
6029 +       if (len && !dst->data)
6030 +               return -ENOMEM;
6031 +       return 0;
6032 +}
6033 +
6034 +static inline int dup_netobj(struct xdr_netobj *dst, struct xdr_netobj *src)
6035 +{
6036 +       return dup_to_netobj(dst, src->data, src->len);
6037 +}
6038 +
6039 +static inline void rsi_init(struct rsi *new, struct rsi *item)
6040 +{
6041 +       new->out_handle.data = NULL;
6042 +       new->out_handle.len = 0;
6043 +       new->out_token.data = NULL;
6044 +       new->out_token.len = 0;
6045 +       new->in_handle.len = item->in_handle.len;
6046 +       new->in_handle.data = item->in_handle.data;
6047 +       item->in_handle.len = 0;
6048 +       item->in_handle.data = NULL;
6049 +       new->in_token.len = item->in_token.len;
6050 +       new->in_token.data = item->in_token.data;
6051 +       item->in_token.len = 0;
6052 +       item->in_token.data = NULL;
6053 +       return;
6054 +}
6055 +
6056 +static inline void rsi_update(struct rsi *new, struct rsi *item)
6057 +{
6058 +       BUG_ON(new->out_handle.data || new->out_token.data);
6059 +       new->out_handle.len = item->out_handle.len;
6060 +       item->out_handle.len = 0;
6061 +       new->out_token.len = item->out_token.len;
6062 +       item->out_token.len = 0;
6063 +       new->out_handle.data = item->out_handle.data;
6064 +       item->out_handle.data = NULL;
6065 +       new->out_token.data = item->out_token.data;
6066 +       item->out_token.data = NULL;
6067 +
6068 +       new->major_status = item->major_status;
6069 +       new->minor_status = item->minor_status;
6070 +}
6071 +
6072 +static void rsi_request(struct cache_detail *cd,
6073 +                       struct cache_head *h,
6074 +                       char **bpp, int *blen)
6075 +{
6076 +       struct rsi *rsii = container_of(h, struct rsi, h);
6077 +
6078 +       qword_addhex(bpp, blen, rsii->in_handle.data, rsii->in_handle.len);
6079 +       qword_addhex(bpp, blen, rsii->in_token.data, rsii->in_token.len);
6080 +       (*bpp)[-1] = '\n';
6081 +}
6082 +
6083 +
6084 +static int rsi_parse(struct cache_detail *cd,
6085 +                    char *mesg, int mlen)
6086 +{
6087 +       /* context token expiry major minor context token */
6088 +       char *buf = mesg;
6089 +       char *ep;
6090 +       int len;
6091 +       struct rsi rsii, *rsip = NULL;
6092 +       time_t expiry;
6093 +       int status = -EINVAL;
6094 +
6095 +       memset(&rsii, 0, sizeof(rsii));
6096 +       /* handle */
6097 +       len = qword_get(&mesg, buf, mlen);
6098 +       if (len < 0)
6099 +               goto out;
6100 +       status = -ENOMEM;
6101 +       if (dup_to_netobj(&rsii.in_handle, buf, len))
6102 +               goto out;
6103 +
6104 +       /* token */
6105 +       len = qword_get(&mesg, buf, mlen);
6106 +       status = -EINVAL;
6107 +       if (len < 0)
6108 +               goto out;;
6109 +       status = -ENOMEM;
6110 +       if (dup_to_netobj(&rsii.in_token, buf, len))
6111 +               goto out;
6112 +
6113 +       rsii.h.flags = 0;
6114 +       /* expiry */
6115 +       expiry = get_expiry(&mesg);
6116 +       status = -EINVAL;
6117 +       if (expiry == 0)
6118 +               goto out;
6119 +
6120 +       /* major/minor */
6121 +       len = qword_get(&mesg, buf, mlen);
6122 +       if (len < 0)
6123 +               goto out;
6124 +       if (len == 0) {
6125 +               goto out;
6126 +       } else {
6127 +               rsii.major_status = simple_strtoul(buf, &ep, 10);
6128 +               if (*ep)
6129 +                       goto out;
6130 +               len = qword_get(&mesg, buf, mlen);
6131 +               if (len <= 0)
6132 +                       goto out;
6133 +               rsii.minor_status = simple_strtoul(buf, &ep, 10);
6134 +               if (*ep)
6135 +                       goto out;
6136 +
6137 +               /* out_handle */
6138 +               len = qword_get(&mesg, buf, mlen);
6139 +               if (len < 0)
6140 +                       goto out;
6141 +               status = -ENOMEM;
6142 +               if (dup_to_netobj(&rsii.out_handle, buf, len))
6143 +                       goto out;
6144 +
6145 +               /* out_token */
6146 +               len = qword_get(&mesg, buf, mlen);
6147 +               status = -EINVAL;
6148 +               if (len < 0)
6149 +                       goto out;
6150 +               status = -ENOMEM;
6151 +               if (dup_to_netobj(&rsii.out_token, buf, len))
6152 +                       goto out;
6153 +       }
6154 +       rsii.h.expiry_time = expiry;
6155 +       rsip = rsi_lookup(&rsii, 1);
6156 +       status = 0;
6157 +out:
6158 +       rsi_free(&rsii);
6159 +       if (rsip)
6160 +               rsi_put(&rsip->h, &rsi_cache);
6161 +       return status;
6162 +}
6163 +
6164 +static struct cache_detail rsi_cache = {
6165 +       .hash_size      = RSI_HASHMAX,
6166 +       .hash_table     = rsi_table,
6167 +       .name           = "auth.rpcsec.init",
6168 +       .cache_put      = rsi_put,
6169 +       .cache_request  = rsi_request,
6170 +       .cache_parse    = rsi_parse,
6171 +};
6172 +
6173 +static DefineSimpleCacheLookup(rsi, 0)
6174 +
6175 +/*
6176 + * The rpcsec_context cache is used to store a context that is
6177 + * used in data exchange.
6178 + * The key is a context handle. The content is:
6179 + *  uid, gidlist, mechanism, service-set, mech-specific-data
6180 + */
6181 +
6182 +#define        RSC_HASHBITS    10
6183 +#define        RSC_HASHMAX     (1<<RSC_HASHBITS)
6184 +#define        RSC_HASHMASK    (RSC_HASHMAX-1)
6185 +
6186 +#define GSS_SEQ_WIN    128
6187 +
6188 +struct gss_svc_seq_data {
6189 +       /* highest seq number seen so far: */
6190 +       int                     sd_max;
6191 +       /* for i such that sd_max-GSS_SEQ_WIN < i <= sd_max, the i-th bit of
6192 +        * sd_win is nonzero iff sequence number i has been seen already: */
6193 +       unsigned long           sd_win[GSS_SEQ_WIN/BITS_PER_LONG];
6194 +       spinlock_t              sd_lock;
6195 +};
6196 +
6197 +struct rsc {
6198 +       struct cache_head       h;
6199 +       struct xdr_netobj       handle;
6200 +       struct svc_cred         cred;
6201 +       struct gss_svc_seq_data seqdata;
6202 +       struct gss_ctx          *mechctx;
6203 +};
6204 +
6205 +static struct cache_head *rsc_table[RSC_HASHMAX];
6206 +static struct cache_detail rsc_cache;
6207 +static struct rsc *rsc_lookup(struct rsc *item, int set);
6208 +
6209 +static void rsc_free(struct rsc *rsci)
6210 +{
6211 +       kfree(rsci->handle.data);
6212 +       if (rsci->mechctx)
6213 +               gss_delete_sec_context(&rsci->mechctx);
6214 +}
6215 +
6216 +static void rsc_put(struct cache_head *item, struct cache_detail *cd)
6217 +{
6218 +       struct rsc *rsci = container_of(item, struct rsc, h);
6219 +
6220 +       if (cache_put(item, cd)) {
6221 +               rsc_free(rsci);
6222 +               kfree(rsci);
6223 +       }
6224 +}
6225 +
6226 +static inline int
6227 +rsc_hash(struct rsc *rsci)
6228 +{
6229 +       return hash_mem(rsci->handle.data, rsci->handle.len, RSC_HASHBITS);
6230 +}
6231 +
6232 +static inline int
6233 +rsc_match(struct rsc *new, struct rsc *tmp)
6234 +{
6235 +       return netobj_equal(&new->handle, &tmp->handle);
6236 +}
6237 +
6238 +static inline void
6239 +rsc_init(struct rsc *new, struct rsc *tmp)
6240 +{
6241 +       new->mechctx = NULL;
6242 +       new->handle.len = tmp->handle.len;
6243 +       new->handle.data = tmp->handle.data;
6244 +       tmp->handle.len = 0;
6245 +       tmp->handle.data = NULL;
6246 +}
6247 +
6248 +static inline void
6249 +rsc_update(struct rsc *new, struct rsc *tmp)
6250 +{
6251 +       new->mechctx = tmp->mechctx;
6252 +       tmp->mechctx = NULL;
6253 +       memset(&new->seqdata, 0, sizeof(new->seqdata));
6254 +       spin_lock_init(&new->seqdata.sd_lock);
6255 +       new->cred = tmp->cred;
6256 +}
6257 +
6258 +static int rsc_parse(struct cache_detail *cd,
6259 +                    char *mesg, int mlen)
6260 +{
6261 +       /* contexthandle expiry [ uid gid N <n gids> mechname ...mechdata... ] */
6262 +       char *buf = mesg;
6263 +       int len, rv;
6264 +       struct rsc rsci, *rscp = NULL;
6265 +       time_t expiry;
6266 +       int status = -EINVAL;
6267 +
6268 +       memset(&rsci, 0, sizeof(rsci));
6269 +       /* context handle */
6270 +       len = qword_get(&mesg, buf, mlen);
6271 +       if (len < 0) goto out;
6272 +       status = -ENOMEM;
6273 +       if (dup_to_netobj(&rsci.handle, buf, len))
6274 +               goto out;
6275 +
6276 +       rsci.h.flags = 0;
6277 +       /* expiry */
6278 +       expiry = get_expiry(&mesg);
6279 +       status = -EINVAL;
6280 +       if (expiry == 0)
6281 +               goto out;
6282 +
6283 +       /* uid, or NEGATIVE */
6284 +       rv = get_int(&mesg, &rsci.cred.cr_uid);
6285 +       if (rv == -EINVAL)
6286 +               goto out;
6287 +       if (rv == -ENOENT)
6288 +               set_bit(CACHE_NEGATIVE, &rsci.h.flags);
6289 +       else {
6290 +               int N, i;
6291 +               struct gss_api_mech *gm;
6292 +               struct xdr_netobj tmp_buf;
6293 +
6294 +               /* gid */
6295 +               if (get_int(&mesg, &rsci.cred.cr_gid))
6296 +                       goto out;
6297 +
6298 +               /* number of additional gid's */
6299 +               if (get_int(&mesg, &N))
6300 +                       goto out;
6301 +               if (N > NGROUPS)
6302 +                       goto out;
6303 +
6304 +               /* gid's */
6305 +               for (i=0; i<N; i++) {
6306 +                       if (get_int(&mesg, &rsci.cred.cr_groups[i]))
6307 +                               goto out;
6308 +               }
6309 +               if (N < NGROUPS)
6310 +                       rsci.cred.cr_groups[N] = NOGROUP;
6311 +
6312 +               /* mech name */
6313 +               len = qword_get(&mesg, buf, mlen);
6314 +               if (len < 0)
6315 +                       goto out;
6316 +               gm = gss_mech_get_by_name(buf);
6317 +               status = -EOPNOTSUPP;
6318 +               if (!gm)
6319 +                       goto out;
6320 +
6321 +               status = -EINVAL;
6322 +               /* mech-specific data: */
6323 +               len = qword_get(&mesg, buf, mlen);
6324 +               if (len < 0) {
6325 +                       gss_mech_put(gm);
6326 +                       goto out;
6327 +               }
6328 +               tmp_buf.len = len;
6329 +               tmp_buf.data = buf;
6330 +               if (gss_import_sec_context(&tmp_buf, gm, &rsci.mechctx)) {
6331 +                       gss_mech_put(gm);
6332 +                       goto out;
6333 +               }
6334 +               gss_mech_put(gm);
6335 +       }
6336 +       rsci.h.expiry_time = expiry;
6337 +       rscp = rsc_lookup(&rsci, 1);
6338 +       status = 0;
6339 +out:
6340 +       rsc_free(&rsci);
6341 +       if (rscp)
6342 +               rsc_put(&rscp->h, &rsc_cache);
6343 +       return status;
6344 +}
6345 +
6346 +static struct cache_detail rsc_cache = {
6347 +       .hash_size      = RSC_HASHMAX,
6348 +       .hash_table     = rsc_table,
6349 +       .name           = "auth.rpcsec.context",
6350 +       .cache_put      = rsc_put,
6351 +       .cache_parse    = rsc_parse,
6352 +};
6353 +
6354 +static DefineSimpleCacheLookup(rsc, 0);
6355 +
6356 +struct rsc *
6357 +gss_svc_searchbyctx(struct xdr_netobj *handle)
6358 +{
6359 +       struct rsc rsci;
6360 +       struct rsc *found;
6361 +
6362 +       rsci.handle = *handle;
6363 +       found = rsc_lookup(&rsci, 0);
6364 +       if (!found)
6365 +               return NULL;
6366 +       if (cache_check(&rsc_cache, &found->h, NULL))
6367 +               return NULL;
6368 +       return found;
6369 +}
6370 +
6371 +/* Implements sequence number algorithm as specified in RFC 2203. */
6372 +static int
6373 +gss_check_seq_num(struct rsc *rsci, int seq_num)
6374 +{
6375 +       struct gss_svc_seq_data *sd = &rsci->seqdata;
6376 +
6377 +       spin_lock(&sd->sd_lock);
6378 +       if (seq_num > sd->sd_max) {
6379 +               if (seq_num >= sd->sd_max + GSS_SEQ_WIN) {
6380 +                       memset(sd->sd_win,0,sizeof(sd->sd_win));
6381 +                       sd->sd_max = seq_num;
6382 +               } else while (sd->sd_max < seq_num) {
6383 +                       sd->sd_max++;
6384 +                       __clear_bit(sd->sd_max % GSS_SEQ_WIN, sd->sd_win);
6385 +               }
6386 +               __set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win);
6387 +               goto ok;
6388 +       } else if (seq_num <= sd->sd_max - GSS_SEQ_WIN) {
6389 +               goto drop;
6390 +       }
6391 +       /* sd_max - GSS_SEQ_WIN < seq_num <= sd_max */
6392 +       if (__test_and_set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win))
6393 +               goto drop;
6394 +ok:
6395 +       spin_unlock(&sd->sd_lock);
6396 +       return 1;
6397 +drop:
6398 +       spin_unlock(&sd->sd_lock);
6399 +       return 0;
6400 +}
6401 +
6402 +static inline u32 round_up_to_quad(u32 i)
6403 +{
6404 +       return (i + 3 ) & ~3;
6405 +}
6406 +
6407 +static inline int
6408 +svc_safe_getnetobj(struct iovec *argv, struct xdr_netobj *o)
6409 +{
6410 +       int l;
6411 +
6412 +       if (argv->iov_len < 4)
6413 +               return -1;
6414 +       o->len = ntohl(svc_getu32(argv));
6415 +       l = round_up_to_quad(o->len);
6416 +       if (argv->iov_len < l)
6417 +               return -1;
6418 +       o->data = argv->iov_base;
6419 +       argv->iov_base += l;
6420 +       argv->iov_len -= l;
6421 +       return 0;
6422 +}
6423 +
6424 +static inline int
6425 +svc_safe_putnetobj(struct iovec *resv, struct xdr_netobj *o)
6426 +{
6427 +       u32 *p;
6428 +
6429 +       if (resv->iov_len + 4 > PAGE_SIZE)
6430 +               return -1;
6431 +       svc_putu32(resv, htonl(o->len));
6432 +       p = resv->iov_base + resv->iov_len;
6433 +       resv->iov_len += round_up_to_quad(o->len);
6434 +       if (resv->iov_len > PAGE_SIZE)
6435 +               return -1;
6436 +       memcpy(p, o->data, o->len);
6437 +       memset((u8 *)p + o->len, 0, round_up_to_quad(o->len) - o->len);
6438 +       return 0;
6439 +}
6440 +
6441 +/* Verify the checksum on the header and return SVC_OK on success.
6442 + * Otherwise, return SVC_DROP (in the case of a bad sequence number)
6443 + * or return SVC_DENIED and indicate error in authp.
6444 + */
6445 +static int
6446 +gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
6447 +                 u32 *rpcstart, struct rpc_gss_wire_cred *gc, u32 *authp)
6448 +{
6449 +       struct gss_ctx          *ctx_id = rsci->mechctx;
6450 +       struct xdr_buf          rpchdr;
6451 +       struct xdr_netobj       checksum;
6452 +       u32                     flavor = 0;
6453 +       struct iovec            *argv = &rqstp->rq_arg.head[0];
6454 +       struct iovec            iov;
6455 +
6456 +       /* data to compute the checksum over: */
6457 +       iov.iov_base = rpcstart;
6458 +       iov.iov_len = (u8 *)argv->iov_base - (u8 *)rpcstart;
6459 +       xdr_buf_from_iov(&iov, &rpchdr);
6460 +
6461 +       *authp = rpc_autherr_badverf;
6462 +       if (argv->iov_len < 4)
6463 +               return SVC_DENIED;
6464 +       flavor = ntohl(svc_getu32(argv));
6465 +       if (flavor != RPC_AUTH_GSS)
6466 +               return SVC_DENIED;
6467 +       if (svc_safe_getnetobj(argv, &checksum))
6468 +               return SVC_DENIED;
6469 +
6470 +       if (rqstp->rq_deferred) /* skip verification of revisited request */
6471 +               return SVC_OK;
6472 +       if (gss_verify_mic(ctx_id, &rpchdr, &checksum, NULL)
6473 +                                                       != GSS_S_COMPLETE) {
6474 +               *authp = rpcsec_gsserr_credproblem;
6475 +               return SVC_DENIED;
6476 +       }
6477 +
6478 +       if (gc->gc_seq > MAXSEQ) {
6479 +               dprintk("RPC:      svcauth_gss: discarding request with large sequence number %d\n",
6480 +                               gc->gc_seq);
6481 +               *authp = rpcsec_gsserr_ctxproblem;
6482 +               return SVC_DENIED;
6483 +       }
6484 +       if (!gss_check_seq_num(rsci, gc->gc_seq)) {
6485 +               dprintk("RPC:      svcauth_gss: discarding request with old sequence number %d\n",
6486 +                               gc->gc_seq);
6487 +               return SVC_DROP;
6488 +       }
6489 +       return SVC_OK;
6490 +}
6491 +
6492 +static int
6493 +gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
6494 +{
6495 +       u32                     xdr_seq;
6496 +       u32                     maj_stat;
6497 +       struct xdr_buf          verf_data;
6498 +       struct xdr_netobj       mic;
6499 +       u32                     *p;
6500 +       struct iovec            iov;
6501 +
6502 +       svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_GSS));
6503 +       xdr_seq = htonl(seq);
6504 +
6505 +       iov.iov_base = &xdr_seq;
6506 +       iov.iov_len = sizeof(xdr_seq);
6507 +       xdr_buf_from_iov(&iov, &verf_data);
6508 +       p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
6509 +       mic.data = (u8 *)(p + 1);
6510 +       maj_stat = gss_get_mic(ctx_id, 0, &verf_data, &mic);
6511 +       if (maj_stat != GSS_S_COMPLETE)
6512 +               return -1;
6513 +       *p++ = htonl(mic.len);
6514 +       memset((u8 *)p + mic.len, 0, round_up_to_quad(mic.len) - mic.len);
6515 +       p += XDR_QUADLEN(mic.len);
6516 +       if (!xdr_ressize_check(rqstp, p))
6517 +               return -1;
6518 +       return 0;
6519 +}
6520 +
6521 +struct gss_domain {
6522 +       struct auth_domain      h;
6523 +       u32                     pseudoflavor;
6524 +};
6525 +
6526 +/* XXX this should be done in gss_pseudoflavors, and shouldn't be hardcoded: */
6527 +static struct auth_domain *
6528 +find_gss_auth_domain(struct gss_ctx *ctx, u32 svc)
6529 +{
6530 +       switch(gss_get_pseudoflavor(ctx, 0, svc)) {
6531 +               case RPC_AUTH_GSS_KRB5:
6532 +                       return auth_domain_find("gss/krb5");
6533 +               case RPC_AUTH_GSS_KRB5I:
6534 +                       return auth_domain_find("gss/krb5i");
6535 +               case RPC_AUTH_GSS_KRB5P:
6536 +                       return auth_domain_find("gss/krb5p");
6537 +       }
6538 +       return NULL;
6539 +}
6540 +
6541 +int
6542 +svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
6543 +{
6544 +       struct gss_domain       *new;
6545 +       struct auth_domain      *test;
6546 +       static char             *prefix = "gss/";
6547 +       int                     stat = -1;
6548 +
6549 +       new = kmalloc(sizeof(*new), GFP_KERNEL);
6550 +       if (!new)
6551 +               goto out;
6552 +       cache_init(&new->h.h);
6553 +       atomic_inc(&new->h.h.refcnt);
6554 +       new->h.name = kmalloc(strlen(name) + strlen(prefix) + 1, GFP_KERNEL);
6555 +       if (!new->h.name)
6556 +               goto out_free_dom;
6557 +       strcpy(new->h.name, prefix);
6558 +       strcat(new->h.name, name);
6559 +       new->h.flavour = RPC_AUTH_GSS;
6560 +       new->pseudoflavor = pseudoflavor;
6561 +       new->h.h.expiry_time = NEVER;
6562 +       new->h.h.flags = 0;
6563 +
6564 +       test = auth_domain_lookup(&new->h, 1);
6565 +       if (test == &new->h) {
6566 +               BUG_ON(atomic_dec_and_test(&new->h.h.refcnt));
6567 +       } else { /* XXX Duplicate registration? */
6568 +               auth_domain_put(&new->h);
6569 +               goto out;
6570 +       }
6571 +       return 0;
6572 +
6573 +out_free_dom:
6574 +       kfree(new);
6575 +out:
6576 +       return stat;
6577 +}
6578 +
6579 +/* It would be nice if this bit of code could be shared with the client.
6580 + * Obstacles:
6581 + *     The client shouldn't malloc(), would have to pass in own memory.
6582 + *     The server uses base of head iovec as read pointer, while the
6583 + *     client uses separate pointer. */
6584 +static int
6585 +unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
6586 +{
6587 +       /* XXX audit u32/int uses, sign/overflow issues */
6588 +       int stat = -EINVAL;
6589 +       u32 integ_len, maj_stat;
6590 +       struct xdr_netobj mic;
6591 +       struct xdr_buf integ_buf;
6592 +
6593 +       integ_len = ntohl(svc_getu32(&buf->head[0]));
6594 +       if (integ_len & 3)
6595 +               goto out;
6596 +       if (integ_len > buf->len)
6597 +               goto out;
6598 +       if (xdr_buf_subsegment(buf, &integ_buf, 0, integ_len))
6599 +               goto out;
6600 +       /* copy out mic... */
6601 +       if (read_u32_from_xdr_buf(buf, integ_len, &mic.len))
6602 +               goto out;
6603 +       if (mic.len > 256) /* XXX: maximum mic length? */
6604 +               goto out;
6605 +       mic.data = kmalloc(mic.len, GFP_KERNEL);
6606 +       if (read_bytes_from_xdr_buf(buf, integ_len + 4, mic.data, mic.len))
6607 +               goto out;
6608 +       maj_stat = gss_verify_mic(ctx, &integ_buf, &mic, NULL);
6609 +       if (maj_stat != GSS_S_COMPLETE)
6610 +               goto out;
6611 +       if (ntohl(svc_getu32(&buf->head[0])) != seq)
6612 +               goto out;
6613 +       stat = 0;
6614 +out:
6615 +       return stat;
6616 +}
6617 +
6618 +/*
6619 + * Accept an rpcsec packet.
6620 + * If context establishment, punt to user space
6621 + * If data exchange, verify/decrypt
6622 + * If context destruction, handle here
6623 + * In the context establishment and destruction case we encode
6624 + * response here and return SVC_COMPLETE.
6625 + */
6626 +static int
6627 +svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
6628 +{
6629 +       struct iovec    *argv = &rqstp->rq_arg.head[0];
6630 +       struct iovec    *resv = &rqstp->rq_res.head[0];
6631 +       u32             crlen;
6632 +       struct xdr_netobj tmpobj;
6633 +       struct gss_svc_data *svcdata = rqstp->rq_auth_data;
6634 +       struct rpc_gss_wire_cred *gc;
6635 +       struct rsc      *rsci = NULL;
6636 +       struct rsi      *rsip, rsikey;
6637 +       u32             *rpcstart;
6638 +       u32             *reject_stat = resv->iov_base;
6639 +       int             ret;
6640 +
6641 +       dprintk("RPC:      svcauth_gss: argv->iov_len = %d\n", argv->iov_len);
6642 +
6643 +       *authp = rpc_autherr_badcred;
6644 +       if (!svcdata)
6645 +               svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL);
6646 +       if (!svcdata)
6647 +               goto auth_err;
6648 +       rqstp->rq_auth_data = svcdata;
6649 +       gc = &svcdata->clcred;
6650 +       
6651 +       /* start of rpc packet is 7 u32's back from here:
6652 +        * xid direction rpcversion prog vers proc flavour
6653 +        */
6654 +       rpcstart = argv->iov_base;
6655 +       rpcstart -= 7;
6656 +
6657 +       /* credential is:
6658 +        *   version(==1), proc(0,1,2,3), seq, service (1,2,3), handle
6659 +        * at least 5 u32s, and is preceeded by length, so that makes 6.
6660 +        */
6661 +
6662 +       if (argv->iov_len < 5 * 4)
6663 +               goto auth_err;
6664 +       crlen = ntohl(svc_getu32(argv));
6665 +       if (ntohl(svc_getu32(argv)) != RPC_GSS_VERSION)
6666 +               goto auth_err;
6667 +       gc->gc_proc = ntohl(svc_getu32(argv));
6668 +       gc->gc_seq = ntohl(svc_getu32(argv));
6669 +       gc->gc_svc = ntohl(svc_getu32(argv));
6670 +       if (svc_safe_getnetobj(argv, &gc->gc_ctx))
6671 +               goto auth_err;
6672 +       if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)
6673 +               goto auth_err;
6674 +
6675 +       if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0))
6676 +               goto auth_err;
6677 +
6678 +       /*
6679 +        * We've successfully parsed the credential. Let's check out the
6680 +        * verifier.  An AUTH_NULL verifier is allowed (and required) for
6681 +        * INIT and CONTINUE_INIT requests. AUTH_RPCSEC_GSS is required for
6682 +        * PROC_DATA and PROC_DESTROY.
6683 +        *
6684 +        * AUTH_NULL verifier is 0 (AUTH_NULL), 0 (length).
6685 +        * AUTH_RPCSEC_GSS verifier is:
6686 +        *   6 (AUTH_RPCSEC_GSS), length, checksum.
6687 +        * checksum is calculated over rpcheader from xid up to here.
6688 +        */
6689 +       *authp = rpc_autherr_badverf;
6690 +       switch (gc->gc_proc) {
6691 +       case RPC_GSS_PROC_INIT:
6692 +       case RPC_GSS_PROC_CONTINUE_INIT:
6693 +               if (argv->iov_len < 2 * 4)
6694 +                       goto auth_err;
6695 +               if (ntohl(svc_getu32(argv)) != RPC_AUTH_NULL)
6696 +                       goto auth_err;
6697 +               if (ntohl(svc_getu32(argv)) != 0)
6698 +                       goto auth_err;
6699 +               break;
6700 +       case RPC_GSS_PROC_DATA:
6701 +       case RPC_GSS_PROC_DESTROY:
6702 +               *authp = rpcsec_gsserr_credproblem;
6703 +               rsci = gss_svc_searchbyctx(&gc->gc_ctx);
6704 +               if (!rsci)
6705 +                       goto auth_err;
6706 +               switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) {
6707 +               case SVC_OK:
6708 +                       break;
6709 +               case SVC_DENIED:
6710 +                       goto auth_err;
6711 +               case SVC_DROP:
6712 +                       goto drop;
6713 +               }
6714 +               break;
6715 +       default:
6716 +               *authp = rpc_autherr_rejectedcred;
6717 +               goto auth_err;
6718 +       }
6719 +
6720 +       /* now act upon the command: */
6721 +       switch (gc->gc_proc) {
6722 +       case RPC_GSS_PROC_INIT:
6723 +       case RPC_GSS_PROC_CONTINUE_INIT:
6724 +               *authp = rpc_autherr_badcred;
6725 +               if (gc->gc_proc == RPC_GSS_PROC_INIT && gc->gc_ctx.len != 0)
6726 +                       goto auth_err;
6727 +               memset(&rsikey, 0, sizeof(rsikey));
6728 +               if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
6729 +                       goto drop;
6730 +               *authp = rpc_autherr_badverf;
6731 +               if (svc_safe_getnetobj(argv, &tmpobj)) {
6732 +                       kfree(rsikey.in_handle.data);
6733 +                       goto auth_err;
6734 +               }
6735 +               if (dup_netobj(&rsikey.in_token, &tmpobj)) {
6736 +                       kfree(rsikey.in_handle.data);
6737 +                       goto drop;
6738 +               }
6739 +
6740 +               rsip = rsi_lookup(&rsikey, 0);
6741 +               rsi_free(&rsikey);
6742 +               if (!rsip) {
6743 +                       goto drop;
6744 +               }
6745 +               switch(cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
6746 +               case -EAGAIN:
6747 +                       goto drop;
6748 +               case -ENOENT:
6749 +                       goto drop;
6750 +               case 0:
6751 +                       rsci = gss_svc_searchbyctx(&rsip->out_handle);
6752 +                       if (!rsci) {
6753 +                               goto drop;
6754 +                       }
6755 +                       if (gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN))
6756 +                               goto drop;
6757 +                       if (resv->iov_len + 4 > PAGE_SIZE)
6758 +                               goto drop;
6759 +                       svc_putu32(resv, rpc_success);
6760 +                       if (svc_safe_putnetobj(resv, &rsip->out_handle))
6761 +                               goto drop;
6762 +                       if (resv->iov_len + 3 * 4 > PAGE_SIZE)
6763 +                               goto drop;
6764 +                       svc_putu32(resv, htonl(rsip->major_status));
6765 +                       svc_putu32(resv, htonl(rsip->minor_status));
6766 +                       svc_putu32(resv, htonl(GSS_SEQ_WIN));
6767 +                       if (svc_safe_putnetobj(resv, &rsip->out_token))
6768 +                               goto drop;
6769 +                       rqstp->rq_client = NULL;
6770 +               }
6771 +               goto complete;
6772 +       case RPC_GSS_PROC_DESTROY:
6773 +               set_bit(CACHE_NEGATIVE, &rsci->h.flags);
6774 +               if (resv->iov_len + 4 > PAGE_SIZE)
6775 +                       goto drop;
6776 +               svc_putu32(resv, rpc_success);
6777 +               goto complete;
6778 +       case RPC_GSS_PROC_DATA:
6779 +               rqstp->rq_client =
6780 +                       find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
6781 +               if (rqstp->rq_client == NULL)
6782 +                       goto auth_err;
6783 +               *authp = rpcsec_gsserr_ctxproblem;
6784 +               if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
6785 +                       goto auth_err;
6786 +
6787 +               rqstp->rq_cred = rsci->cred;
6788 +
6789 +               *authp = rpc_autherr_badcred;
6790 +               switch (gc->gc_svc) {
6791 +               case RPC_GSS_SVC_NONE:
6792 +                       break;
6793 +               case RPC_GSS_SVC_INTEGRITY:
6794 +                       if (unwrap_integ_data(&rqstp->rq_arg,
6795 +                                       gc->gc_seq, rsci->mechctx))
6796 +                               goto auth_err;
6797 +                       /* placeholders for length and seq. number: */
6798 +                       svcdata->body_start = resv->iov_base + resv->iov_len;
6799 +                       svc_putu32(resv, 0);
6800 +                       svc_putu32(resv, 0);
6801 +                       break;
6802 +               case RPC_GSS_SVC_PRIVACY:
6803 +                       /* currently unsupported */
6804 +               default:
6805 +                       goto auth_err;
6806 +               }
6807 +               ret = SVC_OK;
6808 +               goto out;
6809 +       }
6810 +auth_err:
6811 +       /* Restore write pointer to original value: */
6812 +       xdr_ressize_check(rqstp, reject_stat);
6813 +       ret = SVC_DENIED;
6814 +       goto out;
6815 +complete:
6816 +       ret = SVC_COMPLETE;
6817 +       goto out;
6818 +drop:
6819 +       ret = SVC_DROP;
6820 +out:
6821 +       if (rsci)
6822 +               rsc_put(&rsci->h, &rsc_cache);
6823 +       return ret;
6824 +}
6825 +
6826 +static int
6827 +svcauth_gss_release(struct svc_rqst *rqstp)
6828 +{
6829 +       struct gss_svc_data *gsd = (struct gss_svc_data *)rqstp->rq_auth_data;
6830 +       struct rpc_gss_wire_cred *gc = &gsd->clcred;
6831 +       struct xdr_buf *resbuf = &rqstp->rq_res;
6832 +       struct xdr_buf integ_buf;
6833 +       struct xdr_netobj mic;
6834 +       struct iovec *resv;
6835 +       u32 *p;
6836 +       int integ_offset, integ_len;
6837 +       struct rsc *rsci;
6838 +       int stat = -EINVAL;
6839 +
6840 +       /* normally not set till svc_send, but we need it here: */
6841 +       resbuf->len = resbuf->head[0].iov_len
6842 +               + resbuf->page_len + resbuf->tail[0].iov_len;
6843 +       switch (gc->gc_svc) {
6844 +       case RPC_GSS_SVC_NONE:
6845 +               break;
6846 +       case RPC_GSS_SVC_INTEGRITY:
6847 +               p = gsd->body_start;
6848 +               /* move accept_stat to right place: */
6849 +               memcpy(p, p + 2, 4);
6850 +               p++;
6851 +               integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
6852 +               integ_len = resbuf->len - integ_offset;
6853 +               BUG_ON(integ_len % 4);
6854 +               *p++ = htonl(integ_len);
6855 +               *p++ = htonl(gc->gc_seq);
6856 +               if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
6857 +                                       integ_len))
6858 +                       goto out;
6859 +               if (resbuf->page_len == 0) {
6860 +                       BUG_ON(resbuf->tail[0].iov_len);
6861 +                       /* Use head for everything */
6862 +                       resv = &resbuf->head[0];
6863 +               } else if (resbuf->tail[0].iov_base == NULL) {
6864 +                       /* copied from nfsd4_encode_read */
6865 +                       svc_take_page(rqstp);
6866 +                       resbuf->tail[0].iov_base = page_address(rqstp
6867 +                                       ->rq_respages[rqstp->rq_resused-1]);
6868 +                       rqstp->rq_restailpage = rqstp->rq_resused-1;
6869 +                       resbuf->tail[0].iov_len = 0;
6870 +                       resv = &resbuf->tail[0];
6871 +               } else {
6872 +                       resv = &resbuf->tail[0];
6873 +               }
6874 +               /* XXX bounds checking!: */
6875 +               mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
6876 +               rsci = gss_svc_searchbyctx(&gc->gc_ctx);
6877 +               /* Better error return? Hold count on ctx through
6878 +                * processing instead of looking up again? */
6879 +               if (!rsci)
6880 +                       goto out;
6881 +               /* XXX Whoops, we might overflow here: */
6882 +               if (gss_get_mic(rsci->mechctx, 0, &integ_buf, &mic))
6883 +                       goto out;
6884 +               svc_putu32(resv, htonl(mic.len));
6885 +               resv->iov_len += mic.len;
6886 +               resbuf->len += mic.len; /* not strictly necessary */
6887 +               /* XXX too late, alas: */
6888 +               if (resbuf->len > PAGE_SIZE)
6889 +                       goto out;
6890 +               break;
6891 +       case RPC_GSS_SVC_PRIVACY:
6892 +       default:
6893 +               goto out;
6894 +       }
6895 +
6896 +       stat = 0;
6897 +out:
6898 +       if (rqstp->rq_client)
6899 +               auth_domain_put(rqstp->rq_client);
6900 +       rqstp->rq_client = NULL;
6901 +
6902 +       return stat;
6903 +}
6904 +
6905 +static void
6906 +svcauth_gss_domain_release(struct auth_domain *dom)
6907 +{
6908 +       struct gss_domain *gd = container_of(dom, struct gss_domain, h);
6909 +
6910 +       kfree(dom->name);
6911 +       kfree(gd);
6912 +}
6913 +
6914 +struct auth_ops svcauthops_gss = {
6915 +       .name           = "rpcsec_gss",
6916 +       .flavour        = RPC_AUTH_GSS,
6917 +       .accept         = svcauth_gss_accept,
6918 +       .release        = svcauth_gss_release,
6919 +       .domain_release = svcauth_gss_domain_release,
6920 +};
6921 +
6922 +int
6923 +gss_svc_init(void)
6924 +{
6925 +       cache_register(&rsc_cache);
6926 +       cache_register(&rsi_cache);
6927 +       svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
6928 +       return 0;
6929 +}
6930 diff -puN net/sunrpc/svc.c~CITI_NFS4_ALL net/sunrpc/svc.c
6931 --- linux-2.6.3/net/sunrpc/svc.c~CITI_NFS4_ALL  2004-02-19 16:47:04.000000000 -0500
6932 +++ linux-2.6.3-bfields/net/sunrpc/svc.c        2004-02-19 16:47:04.000000000 -0500
6933 @@ -200,6 +200,8 @@ svc_exit_thread(struct svc_rqst *rqstp)
6934                 kfree(rqstp->rq_resp);
6935         if (rqstp->rq_argp)
6936                 kfree(rqstp->rq_argp);
6937 +       if (rqstp->rq_auth_data)
6938 +               kfree(rqstp->rq_auth_data);
6939         kfree(rqstp);
6940  
6941         /* Release the server */
6942 @@ -322,6 +324,8 @@ svc_process(struct svc_serv *serv, struc
6943                 goto err_bad_auth;
6944         case SVC_DROP:
6945                 goto dropit;
6946 +       case SVC_COMPLETE:
6947 +               goto sendit;
6948         }
6949                 
6950         progp = serv->sv_program;
6951 diff -puN net/sunrpc/Makefile~CITI_NFS4_ALL net/sunrpc/Makefile
6952 --- linux-2.6.3/net/sunrpc/Makefile~CITI_NFS4_ALL       2004-02-19 16:47:05.000000000 -0500
6953 +++ linux-2.6.3-bfields/net/sunrpc/Makefile     2004-02-19 16:47:05.000000000 -0500
6954 @@ -2,9 +2,9 @@
6955  # Makefile for Linux kernel SUN RPC
6956  #
6957  
6958 -obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
6959  
6960  obj-$(CONFIG_SUNRPC) += sunrpc.o
6961 +obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
6962  
6963  sunrpc-y := clnt.o xprt.o sched.o \
6964             auth.o auth_null.o auth_unix.o \
6965 diff -puN fs/nfsd/nfs4proc.c~CITI_NFS4_ALL fs/nfsd/nfs4proc.c
6966 --- linux-2.6.3/fs/nfsd/nfs4proc.c~CITI_NFS4_ALL        2004-02-19 16:47:05.000000000 -0500
6967 +++ linux-2.6.3-bfields/fs/nfsd/nfs4proc.c      2004-02-19 16:47:15.000000000 -0500
6968 @@ -52,15 +52,22 @@
6969  #include <linux/nfs4.h>
6970  #include <linux/nfsd/state.h>
6971  #include <linux/nfsd/xdr4.h>
6972 +#ifdef CONFIG_NFS_V4_ACL
6973 +#include <linux/nfs4_acl.h>
6974 +#endif
6975  
6976  #define NFSDDBG_FACILITY               NFSDDBG_PROC
6977  
6978 -/* Note: The organization of the OPEN code seems a little strange; it
6979 - * has been superfluously split into three routines, one of which is named
6980 - * nfsd4_process_open2() even though there is no nfsd4_process_open1()!
6981 - * This is because the code has been organized in anticipation of a
6982 - * subsequent patch which will implement more of the NFSv4 state model.
6983 - */
6984 +static inline void
6985 +fh_dup2(struct svc_fh *dst, struct svc_fh *src)
6986 +{
6987 +       fh_put(dst);
6988 +       dget(src->fh_dentry);
6989 +       if (src->fh_export)
6990 +               cache_get(&src->fh_export->h);
6991 +       *dst = *src;
6992 +}
6993 +
6994  static int
6995  do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
6996  {
6997 @@ -89,12 +96,19 @@ do_open_lookup(struct svc_rqst *rqstp, s
6998         if (!status) {
6999                 set_change_info(&open->op_cinfo, current_fh);
7000                 fh_dup2(current_fh, &resfh);
7001 +               /* XXXJBF: keep a saved svc_fh struct instead?? */
7002 +               open->op_stateowner->so_replay.rp_openfh_len =
7003 +                       resfh.fh_handle.fh_size;
7004 +               memcpy(open->op_stateowner->so_replay.rp_openfh,
7005 +                               &resfh.fh_handle.fh_base,
7006 +                               resfh.fh_handle.fh_size);
7007  
7008                 accmode = MAY_NOP;
7009                 if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
7010                         accmode = MAY_READ;
7011                 if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE)
7012                         accmode |= (MAY_WRITE | MAY_TRUNC);
7013 +               accmode |= MAY_OWNER_OVERRIDE;
7014                 status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
7015         }
7016  
7017 @@ -102,19 +116,39 @@ do_open_lookup(struct svc_rqst *rqstp, s
7018         return status;
7019  }
7020  
7021 +/*
7022 + * nfs4_unlock_state() called in encode
7023 + */
7024  static inline int
7025  nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
7026  {
7027         int status;
7028 -       dprintk("NFSD: nfsd4_open filename %.*s\n",
7029 -               (int)open->op_fname.len, open->op_fname.data);
7030 +       dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
7031 +               (int)open->op_fname.len, open->op_fname.data,
7032 +               open->op_stateowner);
7033  
7034         /* This check required by spec. */
7035         if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
7036                 return nfserr_inval;
7037  
7038 +       open->op_stateowner = NULL;
7039 +       nfs4_lock_state();
7040 +
7041         /* check seqid for replay. set nfs4_owner */
7042         status = nfsd4_process_open1(open);
7043 +       if (status == NFSERR_REPLAY_ME) {
7044 +               struct nfs4_replay *rp = &open->op_stateowner->so_replay;
7045 +               fh_put(current_fh);
7046 +               current_fh->fh_handle.fh_size = rp->rp_openfh_len;
7047 +               memcpy(&current_fh->fh_handle.fh_base, rp->rp_openfh,
7048 +                               rp->rp_openfh_len);
7049 +               status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
7050 +               if (status)
7051 +                       dprintk("nfsd4_open: replay failed"
7052 +                               " restoring previous filehandle\n");
7053 +               else
7054 +                       status = NFSERR_REPLAY_ME;
7055 +       }
7056         if (status)
7057                 return status;
7058         /*
7059 @@ -172,7 +206,7 @@ static inline int
7060  nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
7061  {
7062         if (!save_fh->fh_dentry)
7063 -               return nfserr_nofilehandle;
7064 +               return nfserr_restorefh;
7065  
7066         fh_dup2(current_fh, save_fh);
7067         return nfs_ok;
7068 @@ -204,11 +238,16 @@ nfsd4_access(struct svc_rqst *rqstp, str
7069  static inline int
7070  nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit)
7071  {
7072 +       int status;
7073 +
7074         u32 *p = (u32 *)commit->co_verf.data;
7075         *p++ = nfssvc_boot.tv_sec;
7076         *p++ = nfssvc_boot.tv_usec;
7077  
7078 -       return nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count);
7079 +       status = nfsd_commit(rqstp, current_fh, commit->co_offset, commit->co_count);
7080 +       if (status == nfserr_symlink)
7081 +               status = nfserr_inval;
7082 +       return status;
7083  }
7084  
7085  static inline int
7086 @@ -221,6 +260,8 @@ nfsd4_create(struct svc_rqst *rqstp, str
7087         fh_init(&resfh, NFS4_FHSIZE);
7088  
7089         status = fh_verify(rqstp, current_fh, S_IFDIR, MAY_CREATE);
7090 +       if (status == nfserr_symlink)
7091 +               status = nfserr_notdir;
7092         if (status)
7093                 return status;
7094  
7095 @@ -316,8 +357,10 @@ static inline int
7096  nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh,
7097            struct svc_fh *save_fh, struct nfsd4_link *link)
7098  {
7099 -       int status;
7100 +       int status = nfserr_nofilehandle;
7101  
7102 +       if (!save_fh->fh_dentry)
7103 +               return status;
7104         status = nfsd_link(rqstp, current_fh, link->li_name, link->li_namelen, save_fh);
7105         if (!status)
7106                 set_change_info(&link->li_cinfo, current_fh);
7107 @@ -327,14 +370,18 @@ nfsd4_link(struct svc_rqst *rqstp, struc
7108  static inline int
7109  nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
7110  {
7111 -       /*
7112 -        * XXX: We currently violate the spec in one small respect
7113 -        * here.  If LOOKUPP is done at the root of the pseudofs,
7114 -        * the spec requires us to return NFSERR_NOENT.  Personally,
7115 -        * I think that leaving the filehandle unchanged is more
7116 -        * logical, but this is an academic question anyway, since
7117 -        * no clients actually use LOOKUPP.
7118 -        */
7119 +       struct svc_fh tmp_fh;
7120 +       int ret;
7121 +
7122 +       fh_init(&tmp_fh, NFS4_FHSIZE);
7123 +       if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh,
7124 +                             &rqstp->rq_chandle)) != 0)
7125 +               return ret;
7126 +       if (tmp_fh.fh_dentry == current_fh->fh_dentry) {
7127 +               fh_put(&tmp_fh);
7128 +               return nfserr_noent;
7129 +       }
7130 +       fh_put(&tmp_fh);
7131         return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh);
7132  }
7133  
7134 @@ -345,6 +392,20 @@ nfsd4_lookup(struct svc_rqst *rqstp, str
7135  }
7136  
7137  static inline int
7138 +access_bits_permit_read(unsigned long access_bmap)
7139 +{
7140 +       return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) ||
7141 +               test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
7142 +}
7143 +
7144 +static inline int
7145 +access_bits_permit_write(unsigned long access_bmap)
7146 +{
7147 +       return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) ||
7148 +               test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
7149 +}
7150 +
7151 +static inline int
7152  nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
7153  {
7154         struct nfs4_stateid *stp;
7155 @@ -382,7 +443,7 @@ nfsd4_read(struct svc_rqst *rqstp, struc
7156                 goto out;
7157         }
7158         status = nfserr_openmode;
7159 -       if (!(stp->st_share_access & NFS4_SHARE_ACCESS_READ)) {
7160 +       if (!access_bits_permit_read(stp->st_access_bmap)) {
7161                 dprintk("NFSD: nfsd4_read: file not opened for read!\n");
7162                 goto out;
7163         }
7164 @@ -397,6 +458,11 @@ out:
7165  static inline int
7166  nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir)
7167  {
7168 +       u64 cookie = readdir->rd_cookie;
7169 +       static const nfs4_verifier zeroverf = {
7170 +               .data[0] = 0,
7171 +       };
7172 +
7173         /* no need to check permission - this will be done in nfsd_readdir() */
7174  
7175         if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
7176 @@ -405,7 +471,8 @@ nfsd4_readdir(struct svc_rqst *rqstp, st
7177         readdir->rd_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
7178         readdir->rd_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;
7179  
7180 -       if (readdir->rd_cookie > ~(u32)0)
7181 +       if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
7182 +           (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
7183                 return nfserr_bad_cookie;
7184  
7185         readdir->rd_rqstp = rqstp;
7186 @@ -427,6 +494,8 @@ nfsd4_remove(struct svc_rqst *rqstp, str
7187         int status;
7188  
7189         status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen);
7190 +       if (status == nfserr_symlink)
7191 +               return nfserr_notdir;
7192         if (!status) {
7193                 fh_unlock(current_fh);
7194                 set_change_info(&remove->rm_cinfo, current_fh);
7195 @@ -438,11 +507,25 @@ static inline int
7196  nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
7197              struct svc_fh *save_fh, struct nfsd4_rename *rename)
7198  {
7199 -       int status;
7200 +       int status = nfserr_nofilehandle;
7201  
7202 +       if (!save_fh->fh_dentry)
7203 +               return status;
7204         status = nfsd_rename(rqstp, save_fh, rename->rn_sname,
7205                              rename->rn_snamelen, current_fh,
7206                              rename->rn_tname, rename->rn_tnamelen);
7207 +
7208 +       /* the underlying filesystem returns different error's than required
7209 +        * by NFSv4. both save_fh and current_fh have been verified.. */
7210 +       if (status == nfserr_isdir) 
7211 +               status = nfserr_exist;
7212 +       else if ((status == nfserr_notdir) && 
7213 +                  (S_ISDIR(save_fh->fh_dentry->d_inode->i_mode) && 
7214 +                   S_ISDIR(current_fh->fh_dentry->d_inode->i_mode)))
7215 +               status = nfserr_exist;
7216 +       else if (status == nfserr_symlink)
7217 +               status = nfserr_notdir;
7218 +
7219         if (!status) {
7220                 set_change_info(&rename->rn_sinfo, current_fh);
7221                 set_change_info(&rename->rn_tinfo, save_fh);
7222 @@ -454,14 +537,18 @@ static inline int
7223  nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
7224  {
7225         struct nfs4_stateid *stp;
7226 -       int status = nfs_ok;
7227 +       int status = nfserr_nofilehandle;
7228 +
7229 +       if (!current_fh->fh_dentry)
7230 +               goto out;
7231  
7232 +       status = nfs_ok;
7233         if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
7234  
7235                 status = nfserr_bad_stateid;
7236                 if (ZERO_STATEID(&setattr->sa_stateid) || ONE_STATEID(&setattr->sa_stateid)) {
7237                         dprintk("NFSD: nfsd4_setattr: magic stateid!\n");
7238 -                       return status;
7239 +                       goto out;
7240                 }
7241  
7242                 nfs4_lock_state();
7243 @@ -469,17 +556,27 @@ nfsd4_setattr(struct svc_rqst *rqstp, st
7244                                                 &setattr->sa_stateid, 
7245                                                 CHECK_FH | RDWR_STATE, &stp))) {
7246                         dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
7247 -                       goto out;
7248 +                       goto out_unlock;
7249                 }
7250                 status = nfserr_openmode;
7251 -               if (!(stp->st_share_access & NFS4_SHARE_ACCESS_WRITE)) {
7252 +               if (!access_bits_permit_write(stp->st_access_bmap)) {
7253                         dprintk("NFSD: nfsd4_setattr: not opened for write!\n");
7254 -                       goto out;
7255 +                       goto out_unlock;
7256                 }
7257                 nfs4_unlock_state();
7258         }
7259 -       return (nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 0, (time_t)0));
7260 +#ifdef CONFIG_NFS_V4_ACL
7261 +       status = nfs_ok;
7262 +       if (setattr->sa_acl != NULL)
7263 +               status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl);
7264 +       if (status)
7265 +               goto out;
7266 +#endif /* CONFIG_NFS_V4_ACL */
7267 +       status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr,
7268 +                               0, (time_t)0);
7269  out:
7270 +       return status;
7271 +out_unlock:
7272         nfs4_unlock_state();
7273         return status;
7274  }
7275 @@ -513,7 +610,7 @@ nfsd4_write(struct svc_rqst *rqstp, stru
7276         }
7277  
7278         status = nfserr_openmode;
7279 -       if (!(stp->st_share_access & NFS4_SHARE_ACCESS_WRITE)) {
7280 +       if (!access_bits_permit_write(stp->st_access_bmap)) {
7281                 dprintk("NFSD: nfsd4_write: file not open for write!\n");
7282                 goto out;
7283         }
7284 @@ -526,9 +623,12 @@ zero_stateid:
7285         *p++ = nfssvc_boot.tv_sec;
7286         *p++ = nfssvc_boot.tv_usec;
7287  
7288 -       return (nfsd_write(rqstp, current_fh, write->wr_offset,
7289 +       status =  nfsd_write(rqstp, current_fh, write->wr_offset,
7290                           write->wr_vec, write->wr_vlen, write->wr_buflen,
7291 -                         &write->wr_how_written));
7292 +                         &write->wr_how_written);
7293 +       if (status == nfserr_symlink)
7294 +               status = nfserr_inval;
7295 +       return status;
7296  out:
7297         nfs4_unlock_state();
7298         return status;
7299 @@ -552,8 +652,9 @@ nfsd4_verify(struct svc_rqst *rqstp, str
7300  
7301         if ((verify->ve_bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0)
7302             || (verify->ve_bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
7303 -               return nfserr_notsupp;
7304 -       if (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
7305 +               return nfserr_attrnotsupp;
7306 +       if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
7307 +           || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
7308                 return nfserr_inval;
7309         if (verify->ve_attrlen & 3)
7310                 return nfserr_inval;
7311 @@ -568,7 +669,8 @@ nfsd4_verify(struct svc_rqst *rqstp, str
7312  
7313         status = nfsd4_encode_fattr(current_fh, current_fh->fh_export,
7314                                     current_fh->fh_dentry, buf,
7315 -                                   &count, verify->ve_bmval);
7316 +                                   &count, verify->ve_bmval,
7317 +                                   rqstp);
7318  
7319         /* this means that nfsd4_encode_fattr() ran out of space */
7320         if (status == nfserr_resource && count == 0)
7321 @@ -658,13 +760,32 @@ nfsd4_proc_compound(struct svc_rqst *rqs
7322                         goto encode_op;
7323                 }
7324  
7325 +               /* All operations except RENEW, SETCLIENTID, RESTOREFH
7326 +               * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH 
7327 +               * require a valid current filehandle 
7328 +               *
7329 +               * SETATTR NOFILEHANDLE error handled in nfsd4_setattr
7330 +               * due to required returned bitmap argument
7331 +               */ 
7332 +               if ((!current_fh.fh_dentry) && 
7333 +                  !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
7334 +                  (op->opnum == OP_SETCLIENTID) ||
7335 +                  (op->opnum == OP_SETCLIENTID_CONFIRM) ||
7336 +                  (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) ||
7337 +                  (op->opnum == OP_RELEASE_LOCKOWNER) || 
7338 +                  (op->opnum == OP_SETATTR))) {
7339 +                       op->status = nfserr_nofilehandle;
7340 +                       goto encode_op;
7341 +               }
7342                 switch (op->opnum) {
7343                 case OP_ACCESS:
7344                         op->status = nfsd4_access(rqstp, &current_fh, &op->u.access);
7345                         break;
7346                 case OP_CLOSE:
7347                         op->status = nfsd4_close(rqstp, &current_fh, &op->u.close);
7348 -                       op->replay = &op->u.close.cl_stateowner->so_replay;
7349 +                       if (op->u.close.cl_stateowner)
7350 +                               op->replay = 
7351 +                                       &op->u.close.cl_stateowner->so_replay;
7352                         break;
7353                 case OP_COMMIT:
7354                         op->status = nfsd4_commit(rqstp, &current_fh, &op->u.commit);
7355 @@ -683,12 +804,18 @@ nfsd4_proc_compound(struct svc_rqst *rqs
7356                         break;
7357                 case OP_LOCK:
7358                         op->status = nfsd4_lock(rqstp, &current_fh, &op->u.lock);
7359 +                       if (op->u.lock.lk_stateowner)
7360 +                               op->replay = 
7361 +                                       &op->u.lock.lk_stateowner->so_replay;
7362                         break;
7363                 case OP_LOCKT:
7364                         op->status = nfsd4_lockt(rqstp, &current_fh, &op->u.lockt);
7365                         break;
7366                 case OP_LOCKU:
7367                         op->status = nfsd4_locku(rqstp, &current_fh, &op->u.locku);
7368 +                       if (op->u.locku.lu_stateowner)
7369 +                               op->replay = 
7370 +                                       &op->u.locku.lu_stateowner->so_replay;
7371                         break;
7372                 case OP_LOOKUP:
7373                         op->status = nfsd4_lookup(rqstp, &current_fh, &op->u.lookup);
7374 @@ -703,15 +830,21 @@ nfsd4_proc_compound(struct svc_rqst *rqs
7375                         break;
7376                 case OP_OPEN:
7377                         op->status = nfsd4_open(rqstp, &current_fh, &op->u.open);
7378 -                       op->replay = &op->u.open.op_stateowner->so_replay;
7379 +                       if (op->u.open.op_stateowner)
7380 +                               op->replay = 
7381 +                                       &op->u.open.op_stateowner->so_replay;
7382                         break;
7383                 case OP_OPEN_CONFIRM:
7384                         op->status = nfsd4_open_confirm(rqstp, &current_fh, &op->u.open_confirm);
7385 -                       op->replay = &op->u.open_confirm.oc_stateowner->so_replay;
7386 +                       if (op->u.open_confirm.oc_stateowner)
7387 +                               op->replay = 
7388 +                                       &op->u.open_confirm.oc_stateowner->so_replay;
7389                         break;
7390                 case OP_OPEN_DOWNGRADE:
7391                         op->status = nfsd4_open_downgrade(rqstp, &current_fh, &op->u.open_downgrade);
7392 -                       op->replay = &op->u.open_downgrade.od_stateowner->so_replay;
7393 +                       if (op->u.open_downgrade.od_stateowner)
7394 +                               op->replay = 
7395 +                                       &op->u.open_downgrade.od_stateowner->so_replay;
7396                         break;
7397                 case OP_PUTFH:
7398                         op->status = nfsd4_putfh(rqstp, &current_fh, &op->u.putfh);
7399 @@ -760,6 +893,9 @@ nfsd4_proc_compound(struct svc_rqst *rqs
7400                 case OP_WRITE:
7401                         op->status = nfsd4_write(rqstp, &current_fh, &op->u.write);
7402                         break;
7403 +               case OP_RELEASE_LOCKOWNER:
7404 +                       op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner);
7405 +                       break;
7406                 default:
7407                         BUG_ON(op->status == nfs_ok);
7408                         break;
7409 @@ -768,7 +904,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
7410  encode_op:
7411                 if (op->status == NFSERR_REPLAY_ME) {
7412                         nfsd4_encode_replay(resp, op);
7413 -                       status = op->status = NFS_OK;
7414 +                       status = op->status = op->replay->rp_status;
7415                 } else {
7416                         nfsd4_encode_operation(resp, op);
7417                         status = op->status;
7418 @@ -776,20 +912,7 @@ encode_op:
7419         }
7420  
7421  out:
7422 -       if (args->ops != args->iops) {
7423 -               kfree(args->ops);
7424 -               args->ops = args->iops;
7425 -       }
7426 -       if (args->tmpp) {
7427 -               kfree(args->tmpp);
7428 -               args->tmpp = NULL;
7429 -       }
7430 -       while (args->to_free) {
7431 -               struct tmpbuf *tb = args->to_free;
7432 -               args->to_free = tb->next;
7433 -               kfree(tb->buf);
7434 -               kfree(tb);
7435 -       }
7436 +       nfsd4_release_compoundargs(args);
7437         fh_put(&current_fh);
7438         fh_put(&save_fh);
7439         return status;
7440 diff -puN fs/nfsd/nfs4xdr.c~CITI_NFS4_ALL fs/nfsd/nfs4xdr.c
7441 --- linux-2.6.3/fs/nfsd/nfs4xdr.c~CITI_NFS4_ALL 2004-02-19 16:47:05.000000000 -0500
7442 +++ linux-2.6.3-bfields/fs/nfsd/nfs4xdr.c       2004-02-19 16:47:15.000000000 -0500
7443 @@ -51,100 +51,103 @@
7444  #include <linux/sunrpc/xdr.h>
7445  #include <linux/sunrpc/svc.h>
7446  #include <linux/sunrpc/clnt.h>
7447 -#include <linux/sunrpc/name_lookup.h>
7448  #include <linux/nfsd/nfsd.h>
7449  #include <linux/nfsd/state.h>
7450  #include <linux/nfsd/xdr4.h>
7451 +#include <linux/nfsd_idmap.h>
7452 +#include <linux/nfs4.h>
7453 +#include <linux/nfs4_acl.h>
7454  
7455  #define NFSDDBG_FACILITY               NFSDDBG_XDR
7456  
7457 -/*
7458 - * From Peter Astrand <peter@cendio.se>: The following routines check
7459 - * whether a filename supplied by the client is valid.
7460 - */
7461 -static const char trailing_bytes_for_utf8[256] = {
7462 -       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7463 -       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7464 -       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7465 -       0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7466 +static const char utf8_byte_len[256] = {
7467 +       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
7468 +       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
7469 +       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
7470 +       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
7471         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7472         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
7473 -       1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
7474 -       2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
7475 +       0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
7476 +       3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0,0
7477  };
7478  
7479  static inline int
7480 -is_legal_iso_utf8_sequence(unsigned char *source, int length)
7481 +is_legal_utf8_sequence(unsigned char *source, int length)
7482  {
7483 -       unsigned char a;
7484 -       unsigned char *srcptr;
7485 +       unsigned char *ptr;
7486 +       unsigned char c;
7487  
7488 -       srcptr = source + length;
7489 +       if (length==1) return 1;
7490  
7491 -       switch (length) {
7492 -               /* Everything else falls through when "1"... */
7493 +       /* Check for overlong sequence, and check second byte */
7494 +       c = *(source + 1);
7495 +       switch (*source) {
7496 +       case 0xE0: /* 3 bytes */
7497 +               if ( c < 0xA0 ) return 0;
7498 +               break;
7499 +       case 0xF0: /* 4 bytes */
7500 +               if ( c < 0x90 ) return 0;
7501 +               break;
7502 +       case 0xF8: /* 5 bytes */
7503 +               if ( c < 0xC8 ) return 0;
7504 +               break;
7505 +       case 0xFC: /* 6 bytes */
7506 +               if ( c < 0x84 ) return 0;
7507 +               break;
7508         default:
7509 -               /* Sequences with more than 6 bytes are invalid */
7510 -               return 0;
7511 +               if ( (c & 0xC0) != 0x80) return 0;
7512 +       }
7513  
7514 -               /*
7515 -                  Byte 3-6 must be 80..BF
7516 -               */
7517 -       case 6:
7518 -               if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
7519 -       case 5:
7520 -               if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
7521 -       case 4:
7522 -               if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
7523 -       case 3:
7524 -               if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
7525 -
7526 -       case 2:
7527 -               a = *--srcptr;
7528 -
7529 -               /* Upper limit */
7530 -               if (a > 0xBF)
7531 -                       /* 2nd byte may never be > 0xBF */
7532 -                       return 0;
7533 +       /* Check that trailing bytes look like 10xxxxxx */
7534 +       for (ptr = source++ + length - 1; ptr>source; ptr--)
7535 +               if ( ((*ptr) & 0xC0) != 0x80 ) return 0;
7536 +       return 1;
7537 +}
7538  
7539 -               /*
7540 -                  Lower limits checks, to detect non-shortest forms.
7541 -                  No fall-through in this inner switch.
7542 -               */
7543 -               switch (*source) {
7544 -               case 0xE0: /* 3 bytes */
7545 -                       if (a < 0xA0) return 0;
7546 -                       break;
7547 -               case 0xF0: /* 4 bytes */
7548 -                       if (a < 0x90) return 0;
7549 -                       break;
7550 -               case 0xF8: /* 5 bytes */
7551 -                       if (a < 0xC8) return 0;
7552 -                       break;
7553 -               case 0xFC: /* 6 bytes */
7554 -                       if (a < 0x84) return 0;
7555 -                       break;
7556 -               default:
7557 -                       /* In all cases, 2nd byte must be >= 0x80 (because leading
7558 -                          10...) */
7559 -                       if (a < 0x80) return 0;
7560 -               }
7561 +/* This does some screening on disallowed unicode characters.  It is NOT
7562 + * comprehensive.
7563 + */
7564 +static int
7565 +is_allowed_utf8_char(unsigned char *source, int length)
7566 +{
7567 +       /* We assume length and source point to a valid utf8 sequence */
7568 +       unsigned char c;
7569  
7570 -       case 1:
7571 -               /* Invalid ranges */
7572 -               if (*source >= 0x80 && *source < 0xC2)
7573 -                       /* Multibyte char with value < 0xC2, non-shortest */
7574 -                       return 0;
7575 -               if (*source > 0xFD)
7576 -                       /* Leading byte starting with 11111110 is illegal */
7577 -                       return 0;
7578 -               if (!*source)
7579 -                       return 0;
7580 +       /* Disallow F0000 and up (in utf8, F3B08080) */
7581 +       if (*source > 0xF3 ) return 0;
7582 +       c = *(source + 1);
7583 +       switch (*source) {
7584 +       case 0xF3:
7585 +               if (c >= 0xB0) return 0;
7586 +               break;
7587 +       /* Disallow D800-F8FF (in utf8, EDA080-EFA3BF */
7588 +       case 0xED:
7589 +               if (c >= 0xA0) return 0;
7590 +               break;
7591 +       case 0xEE:
7592 +               return 0;
7593 +               break;
7594 +       case 0xEF:
7595 +               if (c <= 0xA3) return 0;
7596 +       /* Disallow FFF9-FFFF (EFBFB9-EFBFBF) */
7597 +               if (c==0xBF)
7598 +                       /* Don't need to check <=0xBF, since valid utf8 */
7599 +                       if ( *(source+2) >= 0xB9) return 0;
7600 +               break;
7601         }
7602 -
7603         return 1;
7604  }
7605  
7606 +/* This routine should really check to see that the proper stringprep
7607 + * mappings have been applied.  Instead, we do a simple screen of some
7608 + * of the more obvious illegal values by calling is_allowed_utf8_char.
7609 + * This will allow many illegal strings through, but if a client behaves,
7610 + * it will get full functionality.  The other option (apart from full
7611 + * stringprep checking) is to limit everything to an easily handled subset,
7612 + * such as 7-bit ascii.
7613 + *
7614 + * Note - currently calling routines ignore return value except as boolean.
7615 + */
7616  static int
7617  check_utf8(char *str, int len)
7618  {
7619 @@ -155,11 +158,17 @@ check_utf8(char *str, int len)
7620         sourceend = str + len;
7621  
7622         while (chunk < sourceend) {
7623 -               chunklen = trailing_bytes_for_utf8[*chunk]+1;
7624 +               chunklen = utf8_byte_len[*chunk];
7625 +               if (!chunklen)
7626 +                       return nfserr_inval;
7627                 if (chunk + chunklen > sourceend)
7628                         return nfserr_inval;
7629 -               if (!is_legal_iso_utf8_sequence(chunk, chunklen))
7630 +               if (!is_legal_utf8_sequence(chunk, chunklen))
7631 +                       return nfserr_inval;
7632 +               if (!is_allowed_utf8_char(chunk, chunklen))
7633                         return nfserr_inval;
7634 +               if ( (chunklen==1) && (!*chunk) )
7635 +                       return nfserr_inval; /* Disallow embedded nulls */
7636                 chunk += chunklen;
7637         }
7638  
7639 @@ -280,27 +289,40 @@ u32 *read_buf(struct nfsd4_compoundargs 
7640         return p;
7641  }
7642  
7643 -char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
7644 +static int
7645 +defer_free(struct nfsd4_compoundargs *argp,
7646 +               void (*release)(const void *), void *p)
7647  {
7648         struct tmpbuf *tb;
7649 +
7650 +       tb = kmalloc(sizeof(*tb), GFP_KERNEL);
7651 +       if (!tb)
7652 +               return -ENOMEM;
7653 +       tb->buf = p;
7654 +       tb->release = release;
7655 +       tb->next = argp->to_free;
7656 +       argp->to_free = tb;
7657 +       return 0;
7658 +}
7659 +
7660 +char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
7661 +{
7662 +       void *new = NULL;
7663         if (p == argp->tmp) {
7664 -               p = kmalloc(nbytes, GFP_KERNEL);
7665 -               if (!p) return NULL;
7666 +               new = kmalloc(nbytes, GFP_KERNEL);
7667 +               if (!new) return NULL;
7668 +               p = new;
7669                 memcpy(p, argp->tmp, nbytes);
7670         } else {
7671                 if (p != argp->tmpp)
7672                         BUG();
7673                 argp->tmpp = NULL;
7674         }
7675 -       tb = kmalloc(sizeof(*tb), GFP_KERNEL);
7676 -       if (!tb) {
7677 -               kfree(p);
7678 +       if (defer_free(argp, kfree, p)) {
7679 +               kfree(new);
7680                 return NULL;
7681 -       }
7682 -       tb->buf = p;
7683 -       tb->next = argp->to_free;
7684 -       argp->to_free = tb;
7685 -       return (char*)p;
7686 +       } else
7687 +               return (char *)p;
7688  }
7689  
7690  
7691 @@ -328,7 +350,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoun
7692  }
7693  
7694  static int
7695 -nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr)
7696 +nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr,
7697 +    struct nfs4_acl **acl)
7698  {
7699         int expected_len, len = 0;
7700         u32 dummy32;
7701 @@ -344,7 +367,7 @@ nfsd4_decode_fattr(struct nfsd4_compound
7702          * read-only attributes return ERR_INVAL.
7703          */
7704         if ((bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0) || (bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
7705 -               return nfserr_notsupp;
7706 +               return nfserr_attrnotsupp;
7707         if ((bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0) || (bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1))
7708                 return nfserr_inval;
7709  
7710 @@ -357,6 +380,39 @@ nfsd4_decode_fattr(struct nfsd4_compound
7711                 READ64(iattr->ia_size);
7712                 iattr->ia_valid |= ATTR_SIZE;
7713         }
7714 +#ifdef CONFIG_NFS_V4_ACL
7715 +       if (bmval[0] & FATTR4_WORD0_ACL) {
7716 +               int nace, i;
7717 +               struct nfs4_ace ace;
7718 +
7719 +               READ_BUF(4); len += 4;
7720 +               READ32(nace);
7721 +
7722 +               *acl = nfs4_acl_new();
7723 +               if (*acl == NULL) {
7724 +                       status = -ENOMEM;
7725 +                       goto out_nfserr;
7726 +               }
7727 +               defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl);
7728 +
7729 +               for (i = 0; i < nace; i++) {
7730 +                       READ_BUF(16); len += 16;
7731 +                       READ32(ace.type);
7732 +                       READ32(ace.flag);
7733 +                       READ32(ace.access_mask);
7734 +                       READ32(ace.wholen);
7735 +                       READ_BUF(ace.wholen);
7736 +                       len += XDR_QUADLEN(ace.wholen) << 2;
7737 +                       if (nfs4_acl_add_ace(*acl, ace.type, ace.flag,
7738 +                                ace.access_mask, (char *)p, ace.wholen) < 0) {
7739 +                               status = -ENOMEM;
7740 +                               goto out_nfserr;
7741 +                       }
7742 +                       p += XDR_QUADLEN(ace.wholen);
7743 +               }
7744 +       } else
7745 +               *acl = NULL;
7746 +#endif /* CONFIG_NFS_V4_ACL */
7747         if (bmval[1] & FATTR4_WORD1_MODE) {
7748                 READ_BUF(4);
7749                 len += 4;
7750 @@ -373,7 +429,7 @@ nfsd4_decode_fattr(struct nfsd4_compound
7751                 READMEM(buf, dummy32);
7752                 if (check_utf8(buf, dummy32))
7753                         return nfserr_inval;
7754 -               if ((status = name_get_uid(buf, dummy32, &iattr->ia_uid)))
7755 +               if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
7756                         goto out_nfserr;
7757                 iattr->ia_valid |= ATTR_UID;
7758         }
7759 @@ -386,7 +442,7 @@ nfsd4_decode_fattr(struct nfsd4_compound
7760                 READMEM(buf, dummy32);
7761                 if (check_utf8(buf, dummy32))
7762                         return nfserr_inval;
7763 -               if ((status = name_get_gid(buf, dummy32, &iattr->ia_gid)))
7764 +               if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
7765                         goto out_nfserr;
7766                 iattr->ia_valid |= ATTR_GID;
7767         }
7768 @@ -482,6 +538,7 @@ nfsd4_decode_close(struct nfsd4_compound
7769  {
7770         DECODE_HEAD;
7771  
7772 +       (int)close->cl_stateowner = -1;
7773         READ_BUF(4 + sizeof(stateid_t));
7774         READ32(close->cl_seqid);
7775         READ32(close->cl_stateid.si_generation);
7776 @@ -540,7 +597,7 @@ nfsd4_decode_create(struct nfsd4_compoun
7777         if ((status = check_filename(create->cr_name, create->cr_namelen, nfserr_inval)))
7778                 return status;
7779  
7780 -       if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr)))
7781 +       if ((status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, &create->cr_acl)))
7782                 goto out;
7783  
7784         DECODE_TAIL;
7785 @@ -572,6 +629,7 @@ nfsd4_decode_lock(struct nfsd4_compounda
7786  {
7787         DECODE_HEAD;
7788  
7789 +       (int)lock->lk_stateowner = -1;
7790         /*
7791         * type, reclaim(boolean), offset, length, new_lock_owner(boolean)
7792         */
7793 @@ -629,6 +687,7 @@ nfsd4_decode_locku(struct nfsd4_compound
7794  {
7795         DECODE_HEAD;
7796  
7797 +       (int)locku->lu_stateowner = -1;
7798         READ_BUF(24 + sizeof(stateid_t));
7799         READ32(locku->lu_type);
7800         if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT))
7801 @@ -664,6 +723,7 @@ nfsd4_decode_open(struct nfsd4_compounda
7802  
7803         memset(open->op_bmval, 0, sizeof(open->op_bmval));
7804         open->op_iattr.ia_valid = 0;
7805 +       (int)open->op_stateowner = -1;
7806  
7807         /* seqid, share_access, share_deny, clientid, ownerlen */
7808         READ_BUF(16 + sizeof(clientid_t));
7809 @@ -686,7 +746,7 @@ nfsd4_decode_open(struct nfsd4_compounda
7810                 switch (open->op_createmode) {
7811                 case NFS4_CREATE_UNCHECKED:
7812                 case NFS4_CREATE_GUARDED:
7813 -                       if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr)))
7814 +                       if ((status = nfsd4_decode_fattr(argp, open->op_bmval, &open->op_iattr, &open->op_acl)))
7815                                 goto out;
7816                         break;
7817                 case NFS4_CREATE_EXCLUSIVE:
7818 @@ -739,6 +799,7 @@ nfsd4_decode_open_confirm(struct nfsd4_c
7819  {
7820         DECODE_HEAD;
7821                     
7822 +       (int)open_conf->oc_stateowner = -1;
7823         READ_BUF(4 + sizeof(stateid_t));
7824         READ32(open_conf->oc_req_stateid.si_generation);
7825         COPYMEM(&open_conf->oc_req_stateid.si_opaque, sizeof(stateid_opaque_t));
7826 @@ -752,6 +813,7 @@ nfsd4_decode_open_downgrade(struct nfsd4
7827  {
7828         DECODE_HEAD;
7829                     
7830 +       (int)open_down->od_stateowner = -1;
7831         READ_BUF(4 + sizeof(stateid_t));
7832         READ32(open_down->od_stateid.si_generation);
7833         COPYMEM(&open_down->od_stateid.si_opaque, sizeof(stateid_opaque_t));
7834 @@ -861,7 +923,7 @@ nfsd4_decode_setattr(struct nfsd4_compou
7835         READ_BUF(sizeof(stateid_t));
7836         READ32(setattr->sa_stateid.si_generation);
7837         COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
7838 -       if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr)))
7839 +       if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, &setattr->sa_acl)))
7840                 goto out;
7841  
7842         DECODE_TAIL;
7843 @@ -928,7 +990,7 @@ nfsd4_decode_write(struct nfsd4_compound
7844         int len;
7845         DECODE_HEAD;
7846  
7847 -       READ_BUF(sizeof(stateid_t) + 16);
7848 +       READ_BUF(sizeof(stateid_opaque_t) + 20);
7849         READ32(write->wr_stateid.si_generation);
7850         COPYMEM(&write->wr_stateid.si_opaque, sizeof(stateid_opaque_t));
7851         READ64(write->wr_offset);
7852 @@ -972,6 +1034,20 @@ nfsd4_decode_write(struct nfsd4_compound
7853  }
7854  
7855  static int
7856 +nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
7857 +{
7858 +       DECODE_HEAD;
7859 +
7860 +       READ_BUF(12);   
7861 +       COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t));
7862 +       READ32(rlockowner->rl_owner.len);
7863 +       READ_BUF(rlockowner->rl_owner.len);
7864 +       READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len);
7865 +       
7866 +       DECODE_TAIL;
7867 +}
7868 +
7869 +static int
7870  nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
7871  {
7872         DECODE_HEAD;
7873 @@ -1043,6 +1119,13 @@ nfsd4_decode_compound(struct nfsd4_compo
7874                 op->opnum = ntohl(*argp->p++);
7875  
7876                 switch (op->opnum) {
7877 +               case 2: /* Reserved operation */
7878 +                       op->opnum = OP_ILLEGAL;
7879 +                       if (argp->minorversion == 0)
7880 +                               op->status = nfserr_op_illegal;
7881 +                       else 
7882 +                               op->status = nfserr_minor_vers_mismatch;
7883 +                       break;
7884                 case OP_ACCESS:
7885                         op->status = nfsd4_decode_access(argp, &op->u.access);
7886                         break;
7887 @@ -1136,14 +1219,12 @@ nfsd4_decode_compound(struct nfsd4_compo
7888                 case OP_WRITE:
7889                         op->status = nfsd4_decode_write(argp, &op->u.write);
7890                         break;
7891 +               case OP_RELEASE_LOCKOWNER:
7892 +                       op->status = nfsd4_decode_release_lockowner(argp, &op->u.release_lockowner);
7893 +                       break;
7894                 default:
7895 -                       /*
7896 -                        * According to spec, anything greater than OP_WRITE
7897 -                        * is treated as OP_WRITE+1 in the response.
7898 -                        */
7899 -                       if (op->opnum > OP_WRITE)
7900 -                       op->opnum = OP_WRITE + 1;
7901 -                       op->status = nfserr_notsupp;
7902 +                       op->opnum = OP_ILLEGAL;
7903 +                       op->status = nfserr_op_illegal;
7904                         break;
7905                 }
7906  
7907 @@ -1183,10 +1264,10 @@ nfsd4_decode_compound(struct nfsd4_compo
7908  } while (0)
7909  #define WRITECINFO(c)          do {                            \
7910         *p++ = htonl(c.atomic);                                 \
7911 -       *p++ = htonl(c.before_size);                            \
7912 -       *p++ = htonl(c.before_ctime);                           \
7913 -       *p++ = htonl(c.after_size);                             \
7914 -       *p++ = htonl(c.after_ctime);                            \
7915 +       *p++ = htonl(c.before_ctime_sec);                               \
7916 +       *p++ = htonl(c.before_ctime_nsec);                              \
7917 +       *p++ = htonl(c.after_ctime_sec);                                \
7918 +       *p++ = htonl(c.after_ctime_nsec);                               \
7919  } while (0)
7920  
7921  #define RESERVE_SPACE(nbytes)  do {                            \
7922 @@ -1209,10 +1290,13 @@ nfsd4_decode_compound(struct nfsd4_compo
7923   * "seqid-mutating" NFSv4 operation.  This is
7924   * where seqids are incremented, and the
7925   * replay cache is filled.
7926 + * 
7927 + * if stateowner != -1 then called with nfs4_lock_state() held
7928   */
7929  
7930  #define ENCODE_SEQID_OP_TAIL(stateowner) do {                  \
7931 -       if (seqid_mutating_err(nfserr) && stateowner) {         \
7932 +       if (seqid_mutating_err(nfserr) && stateowner            \
7933 +           && ((int)stateowner != -1)) {                       \
7934                 if (stateowner->so_confirmed)                   \
7935                         stateowner->so_seqid++;                 \
7936                 stateowner->so_replay.rp_status = nfserr;       \
7937 @@ -1220,7 +1304,8 @@ nfsd4_decode_compound(struct nfsd4_compo
7938                           (((char *)(resp)->p - (char *)save)); \
7939                 memcpy(stateowner->so_replay.rp_buf, save,      \
7940                         stateowner->so_replay.rp_buflen);       \
7941 -       } } while(0)
7942 +       } } while(0);                                           \
7943 +       if ((int)stateowner != -1) nfs4_unlock_state();
7944  
7945  
7946  static u32 nfs4_ftypes[16] = {
7947 @@ -1239,13 +1324,16 @@ static u32 nfs4_ftypes[16] = {
7948   */
7949  int
7950  nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
7951 -                  struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval)
7952 +               struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval,
7953 +               struct svc_rqst *rqstp)
7954  {
7955         u32 bmval0 = bmval[0];
7956         u32 bmval1 = bmval[1];
7957         struct kstat stat;
7958 -       struct name_ent *owner = NULL;
7959 -       struct name_ent *group = NULL;
7960 +       char owner[IDMAP_NAMESZ];
7961 +       u32 ownerlen = 0;
7962 +       char group[IDMAP_NAMESZ];
7963 +       u32 grouplen = 0;
7964         struct svc_fh tempfh;
7965         struct kstatfs statfs;
7966         int buflen = *countp << 2;
7967 @@ -1254,6 +1342,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
7968         u64 dummy64;
7969         u32 *p = buffer;
7970         int status;
7971 +       struct nfs4_acl *acl = NULL;
7972  
7973         BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1);
7974         BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
7975 @@ -1277,15 +1366,30 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
7976                 fhp = &tempfh;
7977         }
7978         if (bmval1 & FATTR4_WORD1_OWNER) {
7979 -               status = name_get_user(stat.uid, &owner);
7980 -               if (status)
7981 +               int temp = nfsd_map_uid_to_name(rqstp, stat.uid, owner);
7982 +               if (temp < 0) {
7983 +                       status = temp;
7984                         goto out_nfserr;
7985 +               }
7986 +               ownerlen = (unsigned) temp;
7987         }
7988         if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
7989 -               status = name_get_group(stat.gid, &group);
7990 -               if (status)
7991 +               int temp = nfsd_map_gid_to_name(rqstp, stat.gid, group);
7992 +               if (temp < 0) {
7993 +                       status = temp;
7994 +                       goto out_nfserr;
7995 +               }
7996 +               grouplen = (unsigned) temp;
7997 +       }
7998 +#ifdef CONFIG_NFS_V4_ACL
7999 +       if (bmval0 & FATTR4_WORD0_ACL) {
8000 +               status = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
8001 +               if (status == -EOPNOTSUPP)
8002 +                       bmval0 &= ~FATTR4_WORD0_ACL;
8003 +               else if (status < 0)
8004                         goto out_nfserr;
8005         }
8006 +#endif /* CONFIG_NFS_V4_ACL */
8007  
8008         if ((buflen -= 16) < 0)
8009                 goto out_resource;
8010 @@ -1317,32 +1421,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
8011         }
8012         if (bmval0 & FATTR4_WORD0_CHANGE) {
8013                 /*
8014 -                * XXX: We currently use the inode ctime as the nfsv4 "changeid"
8015 -                * attribute.  This violates the spec, which says
8016 -                *
8017 -                *    The server may return the object's time_modify attribute
8018 -                *    for this attribute, but only if the file system object
8019 -                *    can not be updated more frequently than the resolution
8020 -                *    of time_modify.
8021 -                *
8022 -                * Since we only have 1-second ctime resolution, this is a pretty
8023 -                * serious violation.  Indeed, 1-second ctime resolution is known
8024 -                * to be a problem in practice in the NFSv3 world.
8025 -                *
8026 -                * The real solution to this problem is probably to work on
8027 -                * adding high-resolution mtimes to the VFS layer.
8028 -                *
8029 -                * Note: Started using i_size for the high 32 bits of the changeid.
8030 -                *
8031 -                * Note 2: This _must_ be consistent with the scheme for writing
8032 +                * Note: This _must_ be consistent with the scheme for writing
8033                  * change_info, so any changes made here must be reflected there
8034                  * as well.  (See xdr4.h:set_change_info() and the WRITECINFO()
8035                  * macro above.)
8036                  */
8037                 if ((buflen -= 8) < 0)
8038                         goto out_resource;
8039 -               WRITE32(stat.size);
8040 -               WRITE32(stat.mtime.tv_sec); /* AK: nsec dropped? */
8041 +               WRITE32(stat.ctime.tv_sec);
8042 +               WRITE32(stat.ctime.tv_nsec); /* AK: nsec dropped? */
8043         }
8044         if (bmval0 & FATTR4_WORD0_SIZE) {
8045                 if ((buflen -= 8) < 0)
8046 @@ -1387,10 +1474,48 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
8047                         goto out_resource;
8048                 WRITE32(0);
8049         }
8050 +#ifdef CONFIG_NFS_V4_ACL
8051 +       if (bmval0 & FATTR4_WORD0_ACL) {
8052 +               struct nfs4_ace *ace;
8053 +               struct list_head *h;
8054 +               int alen;
8055 +
8056 +               if (acl == NULL) {
8057 +                       if ((buflen -= 4) < 0)
8058 +                               goto out_resource;
8059 +
8060 +                       WRITE32(0);
8061 +                       goto out_acl;
8062 +               }
8063 +
8064 +               alen = acl->naces * 16 + 4;
8065 +
8066 +               list_for_each(h, &acl->ace_head) {
8067 +                       ace = list_entry(h, struct nfs4_ace, l_ace);
8068 +                       alen += XDR_QUADLEN(ace->wholen) << 2;
8069 +               }
8070 +
8071 +               if ((buflen -= alen) < 0)
8072 +                       goto out_resource;
8073 +
8074 +               WRITE32(acl->naces);
8075 +
8076 +               list_for_each(h, &acl->ace_head) {
8077 +                       ace = list_entry(h, struct nfs4_ace, l_ace);
8078 +
8079 +                       WRITE32(ace->type);
8080 +                       WRITE32(ace->flag);
8081 +                       WRITE32(ace->access_mask);
8082 +                       WRITE32(ace->wholen);
8083 +                       WRITEMEM(ace->who, ace->wholen);
8084 +               }
8085 +       }
8086 +out_acl:
8087 +#endif /* CONFIG_NFS_V4_ACL */
8088         if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
8089                 if ((buflen -= 4) < 0)
8090                         goto out_resource;
8091 -               WRITE32(0);
8092 +               WRITE32(1);
8093         }
8094         if (bmval0 & FATTR4_WORD0_CANSETTIME) {
8095                 if ((buflen -= 4) < 0)
8096 @@ -1485,20 +1610,18 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
8097                 WRITE32(stat.nlink);
8098         }
8099         if (bmval1 & FATTR4_WORD1_OWNER) {
8100 -               int namelen  = strlen(owner->name);
8101 -               buflen -= (XDR_QUADLEN(namelen) << 2) + 4;
8102 +               buflen -= (XDR_QUADLEN(ownerlen) << 2) + 4;
8103                 if (buflen < 0)
8104                         goto out_resource;
8105 -               WRITE32(namelen);
8106 -               WRITEMEM(owner->name, namelen);
8107 +               WRITE32(ownerlen);
8108 +               WRITEMEM(owner, ownerlen);
8109         }
8110         if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
8111 -               int namelen = strlen(group->name);
8112 -               buflen -= (XDR_QUADLEN(namelen) << 2) + 4;
8113 +               buflen -= (XDR_QUADLEN(grouplen) << 2) + 4;
8114                 if (buflen < 0)
8115                         goto out_resource;
8116 -               WRITE32(namelen);
8117 -               WRITEMEM(group->name, namelen);
8118 +               WRITE32(grouplen);
8119 +               WRITEMEM(group, grouplen);
8120         }
8121         if (bmval1 & FATTR4_WORD1_RAWDEV) {
8122                 if ((buflen -= 8) < 0)
8123 @@ -1564,12 +1687,11 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
8124         status = nfs_ok;
8125  
8126  out:
8127 +#ifdef CONFIG_NFS_V4_ACL
8128 +       nfs4_acl_free(acl);
8129 +#endif
8130         if (fhp == &tempfh)
8131                 fh_put(&tempfh);
8132 -       if (owner)
8133 -               name_put(owner);
8134 -       if (group)
8135 -               name_put(group);
8136         return status;
8137  out_nfserr:
8138         status = nfserrno(status);
8139 @@ -1648,7 +1770,8 @@ nfsd4_encode_dirent(struct readdir_cd *c
8140                 }
8141  
8142                 nfserr = nfsd4_encode_fattr(NULL, exp,
8143 -                               dentry, p, &buflen, cd->rd_bmval);
8144 +                               dentry, p, &buflen, cd->rd_bmval,
8145 +                               cd->rd_rqstp);
8146                 if (!nfserr) {
8147                         p += buflen;
8148                         goto out;
8149 @@ -1701,7 +1824,7 @@ out:
8150         return 0;
8151  
8152  nospc:
8153 -       cd->common.err = nfserr_readdir_nospc;
8154 +       cd->common.err = nfserr_toosmall;
8155         return -EINVAL;
8156  }
8157  
8158 @@ -1771,7 +1894,8 @@ nfsd4_encode_getattr(struct nfsd4_compou
8159  
8160         buflen = resp->end - resp->p - (COMPOUND_ERR_SLACK_SPACE >> 2);
8161         nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
8162 -                                   resp->p, &buflen, getattr->ga_bmval);
8163 +                                   resp->p, &buflen, getattr->ga_bmval,
8164 +                                   resp->rqstp);
8165  
8166         if (!nfserr)
8167                 resp->p += buflen;
8168 @@ -1871,7 +1995,7 @@ nfsd4_encode_open(struct nfsd4_compoundr
8169         ENCODE_SEQID_OP_HEAD;
8170  
8171         if (nfserr)
8172 -               return;
8173 +               goto out;
8174  
8175         RESERVE_SPACE(36 + sizeof(stateid_t));
8176         WRITE32(open->op_stateid.si_generation);
8177 @@ -1925,7 +2049,8 @@ nfsd4_encode_open(struct nfsd4_compoundr
8178         default:
8179                 BUG();
8180         }
8181 -
8182 +       /* XXX save filehandle here */
8183 +out:
8184         ENCODE_SEQID_OP_TAIL(open->op_stateowner);
8185  }
8186  
8187 @@ -1995,6 +2120,8 @@ nfsd4_encode_read(struct nfsd4_compoundr
8188                            read->rd_offset,
8189                            read->rd_iov, read->rd_vlen,
8190                            &maxcount);
8191 +       if (nfserr == nfserr_symlink)
8192 +               nfserr = nfserr_inval;
8193         if (nfserr)
8194                 return nfserr;
8195         eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size);
8196 @@ -2052,6 +2179,8 @@ nfsd4_encode_readlink(struct nfsd4_compo
8197          * assume that truncation occurred, and return NFS4ERR_RESOURCE.
8198          */
8199         nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, page, &maxcount);
8200 +       if (nfserr == nfserr_isdir)
8201 +               return nfserr_inval;
8202         if (nfserr)
8203                 return nfserr;
8204  
8205 @@ -2081,7 +2210,7 @@ nfsd4_encode_readdir(struct nfsd4_compou
8206  {
8207         int maxcount;
8208         loff_t offset;
8209 -       u32 *page;
8210 +       u32 *page, *savep;
8211         ENCODE_HEAD;
8212  
8213         if (nfserr)
8214 @@ -2090,6 +2219,7 @@ nfsd4_encode_readdir(struct nfsd4_compou
8215                 return nfserr_resource;
8216  
8217         RESERVE_SPACE(8);  /* verifier */
8218 +       savep = p;
8219  
8220         /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
8221         WRITE32(0);
8222 @@ -2107,8 +2237,10 @@ nfsd4_encode_readdir(struct nfsd4_compou
8223          * pointer and eof field.
8224          */
8225         maxcount = (maxcount >> 2) - 4;
8226 -       if (maxcount < 0)
8227 -               return nfserr_readdir_nospc;
8228 +       if (maxcount < 0) {
8229 +               nfserr =  nfserr_toosmall;
8230 +               goto err_no_verf;
8231 +       }
8232  
8233         svc_take_page(resp->rqstp);
8234         page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
8235 @@ -2122,11 +2254,13 @@ nfsd4_encode_readdir(struct nfsd4_compou
8236                               &offset,
8237                               &readdir->common, nfsd4_encode_dirent);
8238         if (nfserr == nfs_ok &&
8239 -           readdir->common.err == nfserr_readdir_nospc &&
8240 +           readdir->common.err == nfserr_toosmall &&
8241             readdir->buffer == page) 
8242 -               nfserr = nfserr_readdir_nospc;
8243 +               nfserr = nfserr_toosmall;
8244 +       if (nfserr == nfserr_symlink)
8245 +               nfserr = nfserr_notdir;
8246         if (nfserr)
8247 -               return nfserr;
8248 +               goto err_no_verf;
8249  
8250         if (readdir->offset)
8251                 xdr_encode_hyper(readdir->offset, offset);
8252 @@ -2146,6 +2280,10 @@ nfsd4_encode_readdir(struct nfsd4_compou
8253         resp->end = resp->p + PAGE_SIZE/4;
8254  
8255         return 0;
8256 +err_no_verf:
8257 +       p = savep;
8258 +       ADJUST_ARGS();
8259 +       return nfserr;
8260  }
8261  
8262  static void
8263 @@ -2237,7 +2375,7 @@ nfsd4_encode_operation(struct nfsd4_comp
8264  
8265         RESERVE_SPACE(8);
8266         WRITE32(op->opnum);
8267 -       statp = p++;                  /* to be backfilled at the end */
8268 +       statp = p++;        /* to be backfilled at the end */
8269         ADJUST_ARGS();
8270  
8271         switch (op->opnum) {
8272 @@ -2324,6 +2462,8 @@ nfsd4_encode_operation(struct nfsd4_comp
8273         case OP_WRITE:
8274                 nfsd4_encode_write(resp, op->status, &op->u.write);
8275                 break;
8276 +       case OP_RELEASE_LOCKOWNER:
8277 +               break;
8278         default:
8279                 break;
8280         }
8281 @@ -2340,6 +2480,8 @@ nfsd4_encode_operation(struct nfsd4_comp
8282   * 
8283   * XDR note: do not encode rp->rp_buflen: the buffer contains the
8284   * previously sent already encoded operation.
8285 + *
8286 + * called with nfs4_lock_state() held
8287   */
8288  void
8289  nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
8290 @@ -2351,12 +2493,13 @@ nfsd4_encode_replay(struct nfsd4_compoun
8291  
8292         RESERVE_SPACE(8);
8293         WRITE32(op->opnum);
8294 -       WRITE32(NFS_OK);
8295 +       *p++ = rp->rp_status;  /* already xdr'ed */
8296         ADJUST_ARGS();
8297  
8298         RESERVE_SPACE(rp->rp_buflen);
8299         WRITEMEM(rp->rp_buf, rp->rp_buflen);
8300         ADJUST_ARGS();
8301 +       nfs4_unlock_state();
8302  }
8303  
8304  /*
8305 @@ -2369,6 +2512,24 @@ nfs4svc_encode_voidres(struct svc_rqst *
8306          return xdr_ressize_check(rqstp, p);
8307  }
8308  
8309 +void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args)
8310 +{
8311 +       if (args->ops != args->iops) {
8312 +               kfree(args->ops);
8313 +               args->ops = args->iops;
8314 +       }
8315 +       if (args->tmpp) {
8316 +               kfree(args->tmpp);
8317 +               args->tmpp = NULL;
8318 +       }
8319 +       while (args->to_free) {
8320 +               struct tmpbuf *tb = args->to_free;
8321 +               args->to_free = tb->next;
8322 +               tb->release(tb->buf);
8323 +               kfree(tb);
8324 +       }
8325 +}
8326 +
8327  int
8328  nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args)
8329  {
8330 @@ -2381,23 +2542,11 @@ nfs4svc_decode_compoundargs(struct svc_r
8331         args->tmpp = NULL;
8332         args->to_free = NULL;
8333         args->ops = args->iops;
8334 +       args->rqstp = rqstp;
8335  
8336         status = nfsd4_decode_compound(args);
8337         if (status) {
8338 -               if (args->ops != args->iops) {
8339 -                       kfree(args->ops);
8340 -                       args->ops = args->iops;
8341 -               }
8342 -               if (args->tmpp) {
8343 -                       kfree(args->tmpp);
8344 -                       args->tmpp = NULL;
8345 -               }
8346 -               while (args->to_free) {
8347 -                       struct tmpbuf *tb = args->to_free;
8348 -                       args->to_free = tb->next;
8349 -                       kfree(tb->buf);
8350 -                       kfree(tb);
8351 -               }
8352 +               nfsd4_release_compoundargs(args);
8353         }
8354         return !status;
8355  }
8356 diff -puN include/linux/nfsd/state.h~CITI_NFS4_ALL include/linux/nfsd/state.h
8357 --- linux-2.6.3/include/linux/nfsd/state.h~CITI_NFS4_ALL        2004-02-19 16:47:05.000000000 -0500
8358 +++ linux-2.6.3-bfields/include/linux/nfsd/state.h      2004-02-19 16:47:15.000000000 -0500
8359 @@ -113,6 +113,8 @@ struct nfs4_replay {
8360         unsigned int            rp_buflen;
8361         char                    *rp_buf;
8362         unsigned                intrp_allocated;
8363 +       int                     rp_openfh_len;
8364 +       char                    rp_openfh[NFS4_FHSIZE];
8365         char                    rp_ibuf[NFSD4_REPLAY_ISIZE];
8366  };
8367  
8368 @@ -128,12 +130,20 @@ struct nfs4_replay {
8369  *    so_perfilestate: heads the list of nfs4_stateid (either open or lock) 
8370  *         and is used to ensure no dangling nfs4_stateid references when we 
8371  *         release a stateowner.
8372 +*    so_perlockowner: (open) nfs4_stateid->st_perlockowner entry - used when 
8373 +*         close is called to reap associated byte-range locks
8374 +*    so_close_lru: (open) stateowner is placed on this list instead of being
8375 +*         reaped (when so_perfilestate is empty) to hold the last close replay.
8376 +*         reaped by laundramat thread after lease period.
8377  */
8378  struct nfs4_stateowner {
8379         struct list_head        so_idhash;   /* hash by so_id */
8380         struct list_head        so_strhash;   /* hash by op_name */
8381         struct list_head        so_perclient; /* nfs4_client->cl_perclient */
8382         struct list_head        so_perfilestate; /* list: nfs4_stateid */
8383 +       struct list_head        so_perlockowner; /* nfs4_stateid->st_perlockowner */
8384 +       struct list_head        so_close_lru; /* tail queue */
8385 +       time_t                  so_time; /* time of placement on so_close_lru */
8386         int                     so_is_open_owner; /* 1=openowner,0=lockowner */
8387         u32                     so_id;
8388         struct nfs4_client *    so_client;
8389 @@ -164,21 +174,23 @@ struct nfs4_file {
8390  *      st_hash: stateid_hashtbl[] entry or lockstateid_hashtbl entry
8391  *      st_perfile: file_hashtbl[] entry.
8392  *      st_perfile_state: nfs4_stateowner->so_perfilestate
8393 -*      st_share_access: used only for open stateid
8394 -*      st_share_deny: used only for open stateid
8395 +*       st_perlockowner: (open stateid) list of lock nfs4_stateowners
8396 +*      st_access_bmap: used only for open stateid
8397 +*      st_deny_bmap: used only for open stateid
8398  */
8399  
8400  struct nfs4_stateid {
8401         struct list_head              st_hash; 
8402         struct list_head              st_perfile;
8403         struct list_head              st_perfilestate; 
8404 +       struct list_head              st_perlockowner;
8405         struct nfs4_stateowner      * st_stateowner;
8406         struct nfs4_file            * st_file;
8407         stateid_t                     st_stateid;
8408         struct file                   st_vfs_file;
8409         int                           st_vfs_set;
8410 -       unsigned int                  st_share_access;
8411 -       unsigned int                  st_share_deny;
8412 +       unsigned long                 st_access_bmap;
8413 +       unsigned long                 st_deny_bmap;
8414  };
8415  
8416  /* flags for preprocess_seqid_op() */
8417 @@ -187,6 +199,7 @@ struct nfs4_stateid {
8418  #define OPEN_STATE              0x00000004
8419  #define LOCK_STATE              0x00000008
8420  #define RDWR_STATE              0x00000010
8421 +#define CLOSE_STATE             0x00000020
8422  
8423  #define seqid_mutating_err(err)                       \
8424         (((err) != nfserr_stale_clientid) &&    \
8425 diff -puN fs/nfsd/Makefile~CITI_NFS4_ALL fs/nfsd/Makefile
8426 --- linux-2.6.3/fs/nfsd/Makefile~CITI_NFS4_ALL  2004-02-19 16:47:06.000000000 -0500
8427 +++ linux-2.6.3-bfields/fs/nfsd/Makefile        2004-02-19 16:47:06.000000000 -0500
8428 @@ -7,5 +7,5 @@ obj-$(CONFIG_NFSD)      += nfsd.o
8429  nfsd-y                         := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
8430                            export.o auth.o lockd.o nfscache.o nfsxdr.o stats.o
8431  nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
8432 -nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o
8433 +nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o
8434  nfsd-objs              := $(nfsd-y)
8435 diff -puN /dev/null fs/nfsd/nfs4idmap.c
8436 --- /dev/null   2004-01-26 19:20:21.000000000 -0500
8437 +++ linux-2.6.3-bfields/fs/nfsd/nfs4idmap.c     2004-02-19 16:47:06.000000000 -0500
8438 @@ -0,0 +1,569 @@
8439 +/*
8440 + *  fs/nfsd/nfs4idmap.c
8441 + *
8442 + *  Mapping of UID/GIDs to name and vice versa.
8443 + *
8444 + *  Copyright (c) 2002, 2003 The Regents of the University of
8445 + *  Michigan.  All rights reserved.
8446 + *
8447 + *  Marius Aamodt Eriksen <marius@umich.edu>
8448 + *
8449 + *  Redistribution and use in source and binary forms, with or without
8450 + *  modification, are permitted provided that the following conditions
8451 + *  are met:
8452 + *
8453 + *  1. Redistributions of source code must retain the above copyright
8454 + *     notice, this list of conditions and the following disclaimer.
8455 + *  2. Redistributions in binary form must reproduce the above copyright
8456 + *     notice, this list of conditions and the following disclaimer in the
8457 + *     documentation and/or other materials provided with the distribution.
8458 + *  3. Neither the name of the University nor the names of its
8459 + *     contributors may be used to endorse or promote products derived
8460 + *     from this software without specific prior written permission.
8461 + *
8462 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
8463 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
8464 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
8465 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
8466 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
8467 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
8468 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
8469 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
8470 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
8471 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
8472 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
8473 + */
8474 +
8475 +#include <linux/config.h>
8476 +#include <linux/module.h>
8477 +#include <linux/init.h>
8478 +
8479 +#include <linux/mm.h>
8480 +#include <linux/utsname.h>
8481 +#include <linux/errno.h>
8482 +#include <linux/string.h>
8483 +#include <linux/sunrpc/clnt.h>
8484 +#include <linux/nfs.h>
8485 +#include <linux/nfs4.h>
8486 +#include <linux/nfs_fs.h>
8487 +#include <linux/nfs_page.h>
8488 +#include <linux/smp_lock.h>
8489 +#include <linux/sunrpc/cache.h>
8490 +#include <linux/nfsd_idmap.h>
8491 +#include <linux/list.h>
8492 +#include <linux/sched.h>
8493 +#include <linux/time.h>
8494 +#include <linux/seq_file.h>
8495 +#include <linux/sunrpc/svcauth.h>
8496 +
8497 +/*
8498 + * Cache entry
8499 + */
8500 +
8501 +/*
8502 + * XXX we know that IDMAP_NAMESZ < PAGE_SIZE, but it's ugly to rely on
8503 + * that.
8504 + */
8505 +
8506 +#define IDMAP_TYPE_USER  0
8507 +#define IDMAP_TYPE_GROUP 1
8508 +
8509 +struct ent {
8510 +       struct cache_head h;
8511 +       int               type;                /* User / Group */
8512 +       uid_t             id;
8513 +       char              name[IDMAP_NAMESZ];
8514 +       char              authname[IDMAP_NAMESZ];
8515 +};
8516 +
8517 +#define DefineSimpleCacheLookupMap(STRUCT, FUNC)                       \
8518 +        DefineCacheLookup(struct STRUCT, h, FUNC##_lookup,             \
8519 +        (struct STRUCT *item, int set), /*no setup */,                 \
8520 +       & FUNC##_cache, FUNC##_hash(item), FUNC##_match(item, tmp),     \
8521 +       STRUCT##_init(new, item), STRUCT##_update(tmp, item), 0)
8522 +
8523 +/* Common entry handling */
8524 +
8525 +#define ENT_HASHBITS          8
8526 +#define ENT_HASHMAX           (1 << ENT_HASHBITS)
8527 +#define ENT_HASHMASK          (ENT_HASHMAX - 1)
8528 +
8529 +static inline void
8530 +ent_init(struct ent *new, struct ent *itm)
8531 +{
8532 +       new->id = itm->id;
8533 +       new->type = itm->type;
8534 +
8535 +       strlcpy(new->name, itm->name, sizeof(new->name));
8536 +       strlcpy(new->authname, itm->authname, sizeof(new->name));
8537 +}
8538 +
8539 +static inline void
8540 +ent_update(struct ent *new, struct ent *itm)
8541 +{
8542 +       ent_init(new, itm);
8543 +}
8544 +
8545 +void
8546 +ent_put(struct cache_head *ch, struct cache_detail *cd)
8547 +{
8548 +       if (cache_put(ch, cd)) {
8549 +               struct ent *map = container_of(ch, struct ent, h);
8550 +               kfree(map);
8551 +       }
8552 +}
8553 +
8554 +/*
8555 + * ID -> Name cache
8556 + */
8557 +
8558 +static struct cache_head *idtoname_table[ENT_HASHMAX];
8559 +
8560 +static uint32_t
8561 +idtoname_hash(struct ent *ent)
8562 +{
8563 +       uint32_t hash;
8564 +
8565 +       hash = hash_str(ent->authname, ENT_HASHBITS);
8566 +       hash = hash_long(hash ^ ent->id, ENT_HASHBITS);
8567 +
8568 +       /* Flip LSB for user/group */
8569 +       if (ent->type == IDMAP_TYPE_GROUP)
8570 +               hash ^= 1;
8571 +
8572 +       return hash;
8573 +}
8574 +
8575 +static void
8576 +idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
8577 +    int *blen)
8578 +{
8579 +       struct ent *ent = container_of(ch, struct ent, h);
8580 +       char idstr[11];
8581 +
8582 +       qword_add(bpp, blen, ent->authname);
8583 +       snprintf(idstr, sizeof(idstr), "%d", ent->id);
8584 +       qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user");
8585 +       qword_add(bpp, blen, idstr);
8586 +
8587 +       (*bpp)[-1] = '\n';
8588 +}
8589 +
8590 +static inline int
8591 +idtoname_match(struct ent *a, struct ent *b)
8592 +{
8593 +       return (a->id == b->id && a->type == b->type &&
8594 +           strcmp(a->authname, b->authname) == 0);
8595 +}
8596 +
8597 +static int
8598 +idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
8599 +{
8600 +       struct ent *ent;
8601 +
8602 +       if (h == NULL) {
8603 +               seq_puts(m, "#domain type id [name]\n");
8604 +               return 0;
8605 +       }
8606 +       ent = container_of(h, struct ent, h);
8607 +       seq_printf(m, "%s %s %d", ent->authname,
8608 +                       ent->type == IDMAP_TYPE_GROUP ? "group" : "user",
8609 +                       ent->id);
8610 +       if (test_bit(CACHE_VALID, &h->flags))
8611 +               seq_printf(m, " %s", ent->name);
8612 +       seq_printf(m, "\n");
8613 +       return 0;
8614 +}
8615 +
8616 +static int         idtoname_parse(struct cache_detail *, char *, int);
8617 +static struct ent *idtoname_lookup(struct ent *, int);
8618 +
8619 +struct cache_detail idtoname_cache = {
8620 +       .hash_size      = ENT_HASHMAX,
8621 +       .hash_table     = idtoname_table,
8622 +       .name           = "nfs4.idtoname",
8623 +       .cache_put      = ent_put,
8624 +       .cache_request  = idtoname_request,
8625 +       .cache_parse    = idtoname_parse,
8626 +       .cache_show     = idtoname_show,
8627 +};
8628 +
8629 +int
8630 +idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
8631 +{
8632 +       struct ent ent, *res;
8633 +       char *buf1, *bp;
8634 +       int error = -EINVAL;
8635 +
8636 +       if (buf[buflen - 1] != '\n')
8637 +               return (-EINVAL);
8638 +       buf[buflen - 1]= '\0';
8639 +
8640 +       buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL);
8641 +       if (buf1 == NULL)
8642 +               return (-ENOMEM);
8643 +
8644 +       memset(&ent, 0, sizeof(ent));
8645 +
8646 +       /* Authentication name */
8647 +       if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8648 +               goto out;
8649 +       memcpy(ent.authname, buf1, sizeof(ent.authname));
8650 +
8651 +       /* Type */
8652 +       if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8653 +               goto out;
8654 +       ent.type = strcmp(buf1, "user") == 0 ?
8655 +               IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
8656 +
8657 +       /* ID */
8658 +       if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8659 +               goto out;
8660 +       ent.id = simple_strtoul(buf1, &bp, 10);
8661 +       if (bp == buf1)
8662 +               goto out;
8663 +
8664 +       /* expiry */
8665 +       ent.h.expiry_time = get_expiry(&buf);
8666 +       if (ent.h.expiry_time == 0)
8667 +               goto out;
8668 +
8669 +       /* Name */
8670 +       error = qword_get(&buf, buf1, PAGE_SIZE);
8671 +       if (error == -EINVAL)
8672 +               goto out;
8673 +       if (error == -ENOENT)
8674 +               set_bit(CACHE_NEGATIVE, &ent.h.flags);
8675 +       else {
8676 +               if (error >= IDMAP_NAMESZ) {
8677 +                       error = -EINVAL;
8678 +                       goto out;
8679 +               }
8680 +               memcpy(ent.name, buf1, sizeof(ent.name));
8681 +       }
8682 +       error = -ENOMEM;
8683 +       if ((res = idtoname_lookup(&ent, 1)) == NULL)
8684 +               goto out;
8685 +
8686 +       ent_put(&res->h, &idtoname_cache);
8687 +
8688 +       error = 0;
8689 +out:
8690 +       kfree(buf1);
8691 +
8692 +       return error;
8693 +}
8694 +
8695 +static DefineSimpleCacheLookupMap(ent, idtoname);
8696 +
8697 +/*
8698 + * Name -> ID cache
8699 + */
8700 +
8701 +static struct cache_head *nametoid_table[ENT_HASHMAX];
8702 +
8703 +static inline int
8704 +nametoid_hash(struct ent *ent)
8705 +{
8706 +       return hash_str(ent->name, ENT_HASHBITS);
8707 +}
8708 +
8709 +void
8710 +nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
8711 +    int *blen)
8712 +{
8713 +       struct ent *ent = container_of(ch, struct ent, h);
8714 +
8715 +       qword_add(bpp, blen, ent->authname);
8716 +       qword_add(bpp, blen, ent->type == IDMAP_TYPE_GROUP ? "group" : "user");
8717 +       qword_add(bpp, blen, ent->name);
8718 +
8719 +       (*bpp)[-1] = '\n';
8720 +}
8721 +
8722 +static inline int
8723 +nametoid_match(struct ent *a, struct ent *b)
8724 +{
8725 +       return (a->type == b->type && strcmp(a->name, b->name) == 0 &&
8726 +           strcmp(a->authname, b->authname) == 0);
8727 +}
8728 +
8729 +static int
8730 +nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
8731 +{
8732 +       struct ent *ent;
8733 +
8734 +       if (h == NULL) {
8735 +               seq_puts(m, "#domain type name [id]\n");
8736 +               return 0;
8737 +       }
8738 +       ent = container_of(h, struct ent, h);
8739 +       seq_printf(m, "%s %s %s", ent->authname,
8740 +                       ent->type == IDMAP_TYPE_GROUP ? "group" : "user",
8741 +                       ent->name);
8742 +       if (test_bit(CACHE_VALID, &h->flags))
8743 +               seq_printf(m, " %d", ent->id);
8744 +       seq_printf(m, "\n");
8745 +       return 0;
8746 +}
8747 +
8748 +static struct ent *nametoid_lookup(struct ent *, int);
8749 +int                nametoid_parse(struct cache_detail *, char *, int);
8750 +
8751 +struct cache_detail nametoid_cache = {
8752 +       .hash_size      = ENT_HASHMAX,
8753 +       .hash_table     = nametoid_table,
8754 +       .name           = "nfs4.nametoid",
8755 +       .cache_put      = ent_put,
8756 +       .cache_request  = nametoid_request,
8757 +       .cache_parse    = nametoid_parse,
8758 +       .cache_show     = nametoid_show,
8759 +};
8760 +
8761 +int
8762 +nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
8763 +{
8764 +       struct ent ent, *res;
8765 +       char *buf1;
8766 +       int error = -EINVAL;
8767 +
8768 +       if (buf[buflen - 1] != '\n')
8769 +               return (-EINVAL);
8770 +       buf[buflen - 1]= '\0';
8771 +
8772 +       buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL);
8773 +       if (buf1 == NULL)
8774 +               return (-ENOMEM);
8775 +
8776 +       memset(&ent, 0, sizeof(ent));
8777 +
8778 +       /* Authentication name */
8779 +       if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8780 +               goto out;
8781 +       memcpy(ent.authname, buf1, sizeof(ent.authname));
8782 +
8783 +       /* Type */
8784 +       if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8785 +               goto out;
8786 +       ent.type = strcmp(buf1, "user") == 0 ?
8787 +               IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
8788 +
8789 +       /* Name */
8790 +       error = qword_get(&buf, buf1, PAGE_SIZE);
8791 +       if (error <= 0 || error >= IDMAP_NAMESZ)
8792 +               goto out;
8793 +       memcpy(ent.name, buf1, sizeof(ent.name));
8794 +
8795 +       /* expiry */
8796 +       ent.h.expiry_time = get_expiry(&buf);
8797 +       if (ent.h.expiry_time == 0)
8798 +               goto out;
8799 +
8800 +       /* ID */
8801 +       error = get_int(&buf, &ent.id);
8802 +       if (error == -EINVAL)
8803 +               goto out;
8804 +       if (error == -ENOENT)
8805 +               set_bit(CACHE_NEGATIVE, &ent.h.flags);
8806 +
8807 +       error = -ENOMEM;
8808 +       if ((res = nametoid_lookup(&ent, 1)) == NULL)
8809 +               goto out;
8810 +
8811 +       ent_put(&res->h, &nametoid_cache);
8812 +       error = 0;
8813 +out:
8814 +       kfree(buf1);
8815 +
8816 +       return (error);
8817 +}
8818 +
8819 +static DefineSimpleCacheLookupMap(ent, nametoid);
8820 +
8821 +/*
8822 + * Exported API
8823 + */
8824 +
8825 +void
8826 +nfsd_idmap_init(void)
8827 +{
8828 +       cache_register(&idtoname_cache);
8829 +       cache_register(&nametoid_cache);
8830 +}
8831 +
8832 +void
8833 +nfsd_idmap_shutdown(void)
8834 +{
8835 +       cache_unregister(&idtoname_cache);
8836 +       cache_unregister(&nametoid_cache);
8837 +}
8838 +
8839 +/*
8840 + * Deferred request handling
8841 + */
8842 +
8843 +struct idmap_defer_req {
8844 +       struct cache_req                req;
8845 +       struct cache_deferred_req deferred_req;
8846 +       wait_queue_head_t       waitq;
8847 +       atomic_t                        count;
8848 +};
8849 +
8850 +static void
8851 +put_mdr(struct idmap_defer_req *mdr)
8852 +{
8853 +       if (atomic_dec_and_test(&mdr->count))
8854 +               kfree(mdr);
8855 +}
8856 +
8857 +static void
8858 +idmap_revisit(struct cache_deferred_req *dreq, int toomany)
8859 +{
8860 +       struct idmap_defer_req *mdr =
8861 +               container_of(dreq, struct idmap_defer_req, deferred_req);
8862 +
8863 +       wake_up(&mdr->waitq);
8864 +       put_mdr(mdr);
8865 +}
8866 +
8867 +static struct cache_deferred_req *
8868 +idmap_defer(struct cache_req *req)
8869 +{
8870 +       struct idmap_defer_req *mdr =
8871 +               container_of(req, struct idmap_defer_req, req);
8872 +
8873 +       mdr->deferred_req.revisit = idmap_revisit;
8874 +       return (&mdr->deferred_req);
8875 +}
8876 +
8877 +static int threads_waiting = 0;
8878 +
8879 +static inline int
8880 +idmap_lookup_wait(struct idmap_defer_req *mdr, wait_queue_t waitq, struct
8881 +               svc_rqst *rqstp) {
8882 +       int ret = -ETIMEDOUT;
8883 +
8884 +       set_task_state(current, TASK_INTERRUPTIBLE);
8885 +       lock_kernel();
8886 +       /* XXX: Does it matter that threads_waiting isn't per-server? */
8887 +       /* Note: BKL prevents races with nfsd_svc and other lookups */
8888 +       if (2 * threads_waiting > rqstp->rq_server->sv_nrthreads)
8889 +               goto out;
8890 +       threads_waiting++;
8891 +       schedule_timeout(10 * HZ);
8892 +       threads_waiting--;
8893 +       ret = 0;
8894 +out:
8895 +       unlock_kernel();
8896 +       remove_wait_queue(&mdr->waitq, &waitq);
8897 +       set_task_state(current, TASK_RUNNING);
8898 +       put_mdr(mdr);
8899 +       return ret;
8900 +}
8901 +
8902 +static int
8903 +idmap_lookup(struct svc_rqst *rqstp,
8904 +               struct ent *(*lookup_fn)(struct ent *, int), struct ent *key,
8905 +               struct cache_detail *detail, struct ent **item)
8906 +{
8907 +       struct idmap_defer_req *mdr;
8908 +       DECLARE_WAITQUEUE(waitq, current);
8909 +       int ret;
8910 +
8911 +       *item = lookup_fn(key, 0);
8912 +       if (!*item)
8913 +               return -ENOMEM;
8914 +       mdr = kmalloc(sizeof(*mdr), GFP_KERNEL);
8915 +       memset(mdr, 0, sizeof(*mdr));
8916 +       init_waitqueue_head(&mdr->waitq);
8917 +       add_wait_queue(&mdr->waitq, &waitq);
8918 +       atomic_set(&mdr->count, 2);
8919 +       mdr->req.defer = idmap_defer;
8920 +       ret = cache_check(detail, &(*item)->h, &mdr->req);
8921 +       if (ret == -EAGAIN) {
8922 +               ret = idmap_lookup_wait(mdr, waitq, rqstp);
8923 +               if (ret)
8924 +                       goto out;
8925 +               /* Try again, but don't wait. */
8926 +               *item = lookup_fn(key, 0);
8927 +               ret = -ENOMEM;
8928 +               if (!*item)
8929 +                       goto out;
8930 +               ret = -ETIMEDOUT;
8931 +               if (!test_bit(CACHE_VALID, &(*item)->h.flags)) {
8932 +                       ent_put(&(*item)->h, detail);
8933 +                       goto out;
8934 +               }
8935 +               ret = cache_check(detail, &(*item)->h, NULL);
8936 +       }
8937 +out:
8938 +       return ret;
8939 +}
8940 +
8941 +static int
8942 +idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
8943 +               uid_t *id)
8944 +{
8945 +       struct ent *item, key = {
8946 +               .type = type,
8947 +       };
8948 +       int ret;
8949 +
8950 +       if (namelen + 1 > sizeof(key.name))
8951 +               return -EINVAL;
8952 +       memcpy(key.name, name, namelen);
8953 +       key.name[namelen] = '\0';
8954 +       strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
8955 +       ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
8956 +       if (ret)
8957 +               return ret;
8958 +       *id = item->id;
8959 +       ent_put(&item->h, &nametoid_cache);
8960 +       return 0;
8961 +}
8962 +
8963 +static int
8964 +idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
8965 +{
8966 +       struct ent *item, key = {
8967 +               .id = id,
8968 +               .type = type,
8969 +       };
8970 +       int ret;
8971 +
8972 +       strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
8973 +       ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item);
8974 +       if (ret)
8975 +               return ret;
8976 +       ret = strlen(item->name);
8977 +       BUG_ON(ret > IDMAP_NAMESZ);
8978 +       memcpy(name, item->name, ret);
8979 +       ent_put(&item->h, &idtoname_cache);
8980 +       return ret;
8981 +}
8982 +
8983 +int
8984 +nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
8985 +               __u32 *id)
8986 +{
8987 +       return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
8988 +}
8989 +
8990 +int
8991 +nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
8992 +               __u32 *id)
8993 +{
8994 +       return idmap_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id);
8995 +}
8996 +
8997 +int
8998 +nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
8999 +{
9000 +       return idmap_id_to_name(rqstp, IDMAP_TYPE_USER, id, name);
9001 +}
9002 +
9003 +int
9004 +nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
9005 +{
9006 +       return idmap_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name);
9007 +}
9008 diff -puN fs/nfsd/nfsctl.c~CITI_NFS4_ALL fs/nfsd/nfsctl.c
9009 --- linux-2.6.3/fs/nfsd/nfsctl.c~CITI_NFS4_ALL  2004-02-19 16:47:06.000000000 -0500
9010 +++ linux-2.6.3-bfields/fs/nfsd/nfsctl.c        2004-02-19 16:47:06.000000000 -0500
9011 @@ -24,6 +24,7 @@
9012  #include <linux/init.h>
9013  
9014  #include <linux/nfs.h>
9015 +#include <linux/nfsd_idmap.h>
9016  #include <linux/sunrpc/svc.h>
9017  #include <linux/nfsd/nfsd.h>
9018  #include <linux/nfsd/cache.h>
9019 @@ -436,6 +437,9 @@ static int __init init_nfsd(void)
9020         nfsd_cache_init();      /* RPC reply cache */
9021         nfsd_export_init();     /* Exports table */
9022         nfsd_lockd_init();      /* lockd->nfsd callbacks */
9023 +#ifdef CONFIG_NFSD_V4
9024 +       nfsd_idmap_init();      /* Name to ID mapping */
9025 +#endif /* CONFIG_NFSD_V4 */
9026         if (proc_mkdir("fs/nfs", 0)) {
9027                 struct proc_dir_entry *entry;
9028                 entry = create_proc_entry("fs/nfs/exports", 0, NULL);
9029 @@ -462,6 +466,9 @@ static void __exit exit_nfsd(void)
9030         remove_proc_entry("fs/nfs", NULL);
9031         nfsd_stat_shutdown();
9032         nfsd_lockd_shutdown();
9033 +#ifdef CONFIG_NFSD_V4
9034 +       nfsd_idmap_shutdown();
9035 +#endif /* CONFIG_NFSD_V4 */
9036         unregister_filesystem(&nfsd_fs_type);
9037  }
9038  
9039 diff -puN fs/nfsd/nfsproc.c~CITI_NFS4_ALL fs/nfsd/nfsproc.c
9040 --- linux-2.6.3/fs/nfsd/nfsproc.c~CITI_NFS4_ALL 2004-02-19 16:47:06.000000000 -0500
9041 +++ linux-2.6.3-bfields/fs/nfsd/nfsproc.c       2004-02-19 16:47:06.000000000 -0500
9042 @@ -585,6 +585,7 @@ nfserrno (int errno)
9043                 { nfserr_dquot, -EDQUOT },
9044  #endif
9045                 { nfserr_stale, -ESTALE },
9046 +               { nfserr_jukebox, -ETIMEDOUT },
9047                 { nfserr_dropit, -EAGAIN },
9048                 { nfserr_dropit, -ENOMEM },
9049                 { -1, -EIO }
9050 diff -puN /dev/null include/linux/nfsd_idmap.h
9051 --- /dev/null   2004-01-26 19:20:21.000000000 -0500
9052 +++ linux-2.6.3-bfields/include/linux/nfsd_idmap.h      2004-02-19 16:47:06.000000000 -0500
9053 @@ -0,0 +1,54 @@
9054 +/*
9055 + *  include/linux/nfsd_idmap.h
9056 + *
9057 + *  Mapping of UID to name and vice versa.
9058 + *
9059 + *  Copyright (c) 2002, 2003 The Regents of the University of
9060 + *  Michigan.  All rights reserved.
9061 +> *
9062 + *  Marius Aamodt Eriksen <marius@umich.edu>
9063 + *
9064 + *  Redistribution and use in source and binary forms, with or without
9065 + *  modification, are permitted provided that the following conditions
9066 + *  are met:
9067 + *
9068 + *  1. Redistributions of source code must retain the above copyright
9069 + *     notice, this list of conditions and the following disclaimer.
9070 + *  2. Redistributions in binary form must reproduce the above copyright
9071 + *     notice, this list of conditions and the following disclaimer in the
9072 + *     documentation and/or other materials provided with the distribution.
9073 + *  3. Neither the name of the University nor the names of its
9074 + *     contributors may be used to endorse or promote products derived
9075 + *     from this software without specific prior written permission.
9076 + *
9077 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
9078 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
9079 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9080 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
9081 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
9082 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
9083 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
9084 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
9085 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
9086 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
9087 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9088 + */
9089 +
9090 +#ifndef LINUX_NFSD_IDMAP_H
9091 +#define LINUX_NFSD_IDMAP_H
9092 +
9093 +#include <linux/in.h>
9094 +#include <linux/sunrpc/svc.h>
9095 +
9096 +/* XXX from linux/nfs_idmap.h */
9097 +#define IDMAP_NAMESZ 128
9098 +
9099 +void nfsd_idmap_init(void);
9100 +void nfsd_idmap_shutdown(void);
9101 +
9102 +int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
9103 +int nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *);
9104 +int nfsd_map_uid_to_name(struct svc_rqst *, __u32, char *);
9105 +int nfsd_map_gid_to_name(struct svc_rqst *, __u32, char *);
9106 +
9107 +#endif /* LINUX_NFSD_IDMAP_H */
9108 diff -puN include/linux/nfsd/xdr4.h~CITI_NFS4_ALL include/linux/nfsd/xdr4.h
9109 --- linux-2.6.3/include/linux/nfsd/xdr4.h~CITI_NFS4_ALL 2004-02-19 16:47:06.000000000 -0500
9110 +++ linux-2.6.3-bfields/include/linux/nfsd/xdr4.h       2004-02-19 16:47:10.000000000 -0500
9111 @@ -39,6 +39,8 @@
9112  #ifndef _LINUX_NFSD_XDR4_H
9113  #define _LINUX_NFSD_XDR4_H
9114  
9115 +#include <linux/nfs4.h>
9116 +
9117  #define NFSD4_MAX_TAGLEN       128
9118  #define XDR_LEN(n)                     (((n) + 3) & ~3)
9119  
9120 @@ -54,10 +56,10 @@ typedef struct {
9121  
9122  struct nfsd4_change_info {
9123         u32             atomic;
9124 -       u32             before_size;
9125 -       u32             before_ctime;
9126 -       u32             after_size;
9127 -       u32             after_ctime;
9128 +       u32             before_ctime_sec;
9129 +       u32             before_ctime_nsec;
9130 +       u32             after_ctime_sec;
9131 +       u32             after_ctime_nsec;
9132  };
9133  
9134  struct nfsd4_access {
9135 @@ -95,6 +97,7 @@ struct nfsd4_create {
9136         u32             cr_bmval[2];        /* request */
9137         struct iattr    cr_iattr;           /* request */
9138         struct nfsd4_change_info  cr_cinfo; /* response */
9139 +       struct nfs4_acl *cr_acl;
9140  };
9141  #define cr_linklen     u.link.namelen
9142  #define cr_linkname    u.link.name
9143 @@ -216,7 +219,7 @@ struct nfsd4_open {
9144         u32             op_rflags;          /* response */
9145         int             op_truncate;        /* used during processing */
9146         struct nfs4_stateowner *op_stateowner; /* used during processing */
9147 -
9148 +       struct nfs4_acl *op_acl;
9149  };
9150  #define op_iattr       u.iattr
9151  #define op_verf                u.verf
9152 @@ -263,6 +266,10 @@ struct nfsd4_readdir {
9153         u32 *                   offset;
9154  };
9155  
9156 +struct nfsd4_release_lockowner {
9157 +       clientid_t        rl_clientid;
9158 +       struct xdr_netobj rl_owner;
9159 +};
9160  struct nfsd4_readlink {
9161         struct svc_rqst *rl_rqstp;          /* request */
9162         struct svc_fh * rl_fhp;             /* request */
9163 @@ -287,6 +294,7 @@ struct nfsd4_setattr {
9164         stateid_t       sa_stateid;         /* request */
9165         u32             sa_bmval[2];        /* request */
9166         struct iattr    sa_iattr;           /* request */
9167 +       struct nfs4_acl *sa_acl;
9168  };
9169  
9170  struct nfsd4_setclientid {
9171 @@ -359,6 +367,7 @@ struct nfsd4_op {
9172                 struct nfsd4_setclientid_confirm setclientid_confirm;
9173                 struct nfsd4_verify             verify;
9174                 struct nfsd4_write              write;
9175 +               struct nfsd4_release_lockowner  release_lockowner;
9176         } u;
9177         struct nfs4_replay *                    replay;
9178  };
9179 @@ -373,9 +382,12 @@ struct nfsd4_compoundargs {
9180         u32 *                           tmpp;
9181         struct tmpbuf {
9182                 struct tmpbuf *next;
9183 +               void (*release)(const void *);
9184                 void *buf;
9185         }                               *to_free;
9186 -       
9187 +
9188 +       struct svc_rqst                 *rqstp;
9189 +
9190         u32                             taglen;
9191         char *                          tag;
9192         u32                             minorversion;
9193 @@ -404,10 +416,10 @@ set_change_info(struct nfsd4_change_info
9194  {
9195         BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved);
9196         cinfo->atomic = 1;
9197 -       cinfo->before_size = fhp->fh_pre_size;
9198 -       cinfo->before_ctime = fhp->fh_pre_ctime.tv_sec;
9199 -       cinfo->after_size = fhp->fh_post_size;
9200 -       cinfo->after_ctime = fhp->fh_post_ctime.tv_sec;
9201 +       cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec;
9202 +       cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec;
9203 +       cinfo->after_ctime_sec = fhp->fh_post_ctime.tv_sec;
9204 +       cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec;
9205  }
9206  
9207  int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *);
9208 @@ -419,7 +431,7 @@ void nfsd4_encode_operation(struct nfsd4
9209  void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
9210  int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
9211                        struct dentry *dentry, u32 *buffer, int *countp, 
9212 -                      u32 *bmval);
9213 +                      u32 *bmval, struct svc_rqst *);
9214  extern int nfsd4_setclientid(struct svc_rqst *rqstp, 
9215                 struct nfsd4_setclientid *setclid);
9216  extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp, 
9217 @@ -439,6 +451,9 @@ extern int nfsd4_lockt(struct svc_rqst *
9218                 struct nfsd4_lockt *lockt);
9219  extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, 
9220                 struct nfsd4_locku *locku);
9221 +extern int nfsd4_release_lockowner(struct svc_rqst *rqstp,
9222 +               struct nfsd4_release_lockowner *rlockowner);
9223 +extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *);
9224  #endif
9225  
9226  /*
9227 diff -puN -L include/linux/sunrpc/name_lookup.h include/linux/sunrpc/name_lookup.h~CITI_NFS4_ALL /dev/null
9228 --- linux-2.6.3/include/linux/sunrpc/name_lookup.h
9229 +++ /dev/null   2004-01-26 19:20:21.000000000 -0500
9230 @@ -1,38 +0,0 @@
9231 -
9232 -/*
9233 - * map between user/group name and id for a given 'client' 
9234 - */
9235 -
9236 -struct name_ent {
9237 -       char name[20];
9238 -};
9239 -static inline int name_get_user(int uid, struct name_ent **namep)
9240 -{
9241 -       struct name_ent *n = kmalloc(sizeof(*n),GFP_KERNEL);
9242 -       if (n) sprintf(n->name, "%d",uid);
9243 -       *namep = n;
9244 -       return n ? 0 : -ENOMEM;
9245 -}
9246 -static inline int name_get_group(int uid, struct name_ent **namep)
9247 -{
9248 -       struct name_ent *n = kmalloc(sizeof(*n),GFP_KERNEL);
9249 -       if (n) sprintf(n->name, "%d",uid);
9250 -       *namep = n;
9251 -       return n ? 0 : -ENOMEM;
9252 -}
9253 -static inline int name_get_uid(char *name, int name_len, int *uidp)
9254 -{
9255 -       *uidp = simple_strtoul(name, NULL, 0);
9256 -       return 0;
9257 -}
9258 -
9259 -static inline int name_get_gid(char *name, int name_len, int *gidp)
9260 -{
9261 -       *gidp = simple_strtoul(name, NULL, 0);
9262 -       return 0;
9263 -}
9264 -
9265 -static inline void name_put(struct name_ent *ent) 
9266 -{
9267 -       kfree(ent);
9268 -}
9269 diff -puN fs/Makefile~CITI_NFS4_ALL fs/Makefile
9270 --- linux-2.6.3/fs/Makefile~CITI_NFS4_ALL       2004-02-19 16:47:06.000000000 -0500
9271 +++ linux-2.6.3-bfields/fs/Makefile     2004-02-19 16:47:06.000000000 -0500
9272 @@ -68,6 +68,7 @@ obj-$(CONFIG_NFS_FS)          += nfs/
9273  obj-$(CONFIG_EXPORTFS)         += exportfs/
9274  obj-$(CONFIG_NFSD)             += nfsd/
9275  obj-$(CONFIG_LOCKD)            += lockd/
9276 +obj-$(CONFIG_NFS_V4_ACL)        += nfs4acl/
9277  obj-$(CONFIG_NLS)              += nls/
9278  obj-$(CONFIG_SYSV_FS)          += sysv/
9279  obj-$(CONFIG_SMB_FS)           += smbfs/
9280 diff -puN /dev/null fs/nfs4acl/acl.c
9281 --- /dev/null   2004-01-26 19:20:21.000000000 -0500
9282 +++ linux-2.6.3-bfields/fs/nfs4acl/acl.c        2004-02-19 16:47:06.000000000 -0500
9283 @@ -0,0 +1,921 @@
9284 +/*
9285 + *  fs/nfs4acl/acl.c
9286 + *
9287 + *  Common NFSv4 ACL handling code.
9288 + *
9289 + *  Copyright (c) 2002, 2003 The Regents of the University of Michigan.
9290 + *  All rights reserved.
9291 + *
9292 + *  Marius Aamodt Eriksen <marius@umich.edu>
9293 + *  Jeff Sedlak <jsedlak@umich.edu>
9294 + * 
9295 + *  Redistribution and use in source and binary forms, with or without
9296 + *  modification, are permitted provided that the following conditions
9297 + *  are met:
9298 + *
9299 + *  1. Redistributions of source code must retain the above copyright
9300 + *     notice, this list of conditions and the following disclaimer.
9301 + *  2. Redistributions in binary form must reproduce the above copyright
9302 + *     notice, this list of conditions and the following disclaimer in the
9303 + *     documentation and/or other materials provided with the distribution.
9304 + *  3. Neither the name of the University nor the names of its
9305 + *     contributors may be used to endorse or promote products derived
9306 + *     from this software without specific prior written permission.
9307 + *
9308 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
9309 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
9310 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
9311 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
9312 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
9313 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
9314 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
9315 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
9316 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
9317 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
9318 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9319 + */
9320 +
9321 +#include <linux/string.h>
9322 +#include <linux/slab.h>
9323 +#include <linux/list.h>
9324 +#include <linux/types.h>
9325 +#include <linux/fs.h>
9326 +#include <linux/nfs_fs.h>
9327 +#include <linux/posix_acl.h>
9328 +#include <linux/nfs4.h>
9329 +#include <linux/nfs4_acl.h>
9330 +
9331 +#define NFS4_READ_MODE (NFS4_ACE_READ_DATA | NFS4_ACE_READ_NAMED_ATTRS)
9332 +#define NFS4_WRITE_MODE (NFS4_ACE_WRITE_DATA | NFS4_ACE_WRITE_NAMED_ATTRS | NFS4_ACE_APPEND_DATA | NFS4_ACE_DELETE_CHILD)
9333 +#define NFS4_EXECUTE_MODE NFS4_ACE_EXECUTE
9334 +#define NFS4_ANYONE_MODE (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL)
9335 +#define NFS4_OWNER_MODE (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL)
9336 +
9337 +#define MASK_EQUAL(mask1, mask2) \
9338 +       ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )
9339 +
9340 +static u32
9341 +mask_from_posix(unsigned short perm, int owner)
9342 +{
9343 +       int mask = NFS4_ANYONE_MODE;
9344 +       if (owner)
9345 +               mask |= NFS4_OWNER_MODE;
9346 +       if (perm & ACL_READ)
9347 +               mask |= NFS4_READ_MODE;
9348 +       if (perm & ACL_WRITE)
9349 +               mask |= NFS4_WRITE_MODE;
9350 +       if (perm & ACL_EXECUTE)
9351 +               mask |= NFS4_EXECUTE_MODE;
9352 +       return mask;
9353 +}
9354 +
9355 +static int
9356 +mode_from_nfs4(u32 perm, unsigned short *mode, int owner)
9357 +{
9358 +       /* XXX we might also want to ignore DELETE_CHILD on non-directories */
9359 +       /* XXX also add special interpretation to EXECUTE on directories */
9360 +       u32 ignore = NFS4_ACE_SYNCHRONIZE;
9361 +
9362 +       *mode = 0;
9363 +       if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
9364 +               *mode |= ACL_READ;
9365 +       if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE)
9366 +               *mode |= ACL_WRITE;
9367 +       if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
9368 +               *mode |= ACL_EXECUTE;
9369 +       if (!MASK_EQUAL(ignore|perm, ignore|mask_from_posix(*mode, owner)))
9370 +               return -EINVAL;
9371 +       return 0;
9372 +}
9373 +
9374 +struct ace_container {
9375 +       struct nfs4_ace  *ace;
9376 +       struct list_head  ace_l;
9377 +};
9378 +
9379 +static short   ace2type(struct nfs4_ace *);
9380 +static int     _posix_to_nfsv4_one(struct nfs4_acl_idmapper *, void *idarg, struct posix_acl *, struct nfs4_acl *, int);
9381 +static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl_idmapper *, void *idarg, struct nfs4_acl *);
9382 +
9383 +struct nfs4_acl *
9384 +nfs4_acl_posix_to_nfsv4(struct nfs4_acl_idmapper *idmapper, void *idarg,
9385 +               struct posix_acl *pacl, struct posix_acl *dpacl)
9386 +{
9387 +       struct nfs4_acl *acl;
9388 +       int error = -EINVAL;
9389 +
9390 +       if ((pacl != NULL &&
9391 +               (posix_acl_valid(pacl) < 0 || pacl->a_count == 0)) ||
9392 +           (dpacl != NULL &&
9393 +               (posix_acl_valid(dpacl) < 0 || dpacl->a_count == 0)))
9394 +               goto out_err;
9395 +
9396 +       acl = nfs4_acl_new();
9397 +       if (acl == NULL) {
9398 +               error = -ENOMEM;
9399 +               goto out_err;
9400 +       }
9401 +
9402 +       if (pacl != NULL) {
9403 +               error = _posix_to_nfsv4_one(idmapper, idarg, pacl, acl, 0);
9404 +               if (error < 0)
9405 +                       goto out_acl;
9406 +       }
9407 +
9408 +       if (dpacl != NULL) {
9409 +               error = _posix_to_nfsv4_one(idmapper, idarg, dpacl, acl,
9410 +                   NFS4_ACE_FILE_INHERIT_ACE |
9411 +                   NFS4_ACE_DIRECTORY_INHERIT_ACE |                
9412 +                   NFS4_ACE_INHERIT_ONLY_ACE);
9413 +               if (error < 0)
9414 +                       goto out_acl;
9415 +       }
9416 +
9417 +       return acl;
9418 +
9419 +out_acl:
9420 +       nfs4_acl_free(acl);
9421 +out_err:
9422 +       acl = ERR_PTR(error);
9423 +
9424 +       return acl;
9425 +}
9426 +
9427 +static int
9428 +nfs4_acl_add_pair(struct nfs4_acl *acl, int eflag, u32 mask, char *owner,
9429 +                     int owner_len)
9430 +{
9431 +       int error;
9432 +
9433 +       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
9434 +                                eflag, mask, owner, owner_len);
9435 +       if (error < 0)
9436 +               return error;
9437 +       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9438 +                               eflag, ~mask, owner, owner_len);
9439 +       return error;
9440 +}
9441 +
9442 +/* We assume the acl has been verified with posix_acl_valid. */
9443 +static int
9444 +_posix_to_nfsv4_one(struct nfs4_acl_idmapper *idmapper, void *idarg,
9445 +               struct posix_acl *pacl, struct nfs4_acl *acl, int eflag)
9446 +{
9447 +       struct posix_acl_entry *pa, *pe, *group_owner_entry;
9448 +       int error = -EINVAL;
9449 +       u32 mask, mask_mask; 
9450 +       char xname[IDMAP_NAMESZ];
9451 +       int xnamelen;
9452 +
9453 +       BUG_ON(pacl->a_count < 3);
9454 +       pe = pacl->a_entries + pacl->a_count;
9455 +       pa = pe - 2; /* if mask entry exists, it's second from the last. */
9456 +       if (pa->e_tag == ACL_MASK)
9457 +               mask_mask = ~mask_from_posix(pa->e_perm, 0);
9458 +       else
9459 +               mask_mask = 0;
9460 +
9461 +       pa = pacl->a_entries;
9462 +       BUG_ON(pa->e_tag != ACL_USER_OBJ);
9463 +       mask = mask_from_posix(pa->e_perm, 1);
9464 +       error = nfs4_acl_add_pair(acl, eflag, mask, "OWNER@",
9465 +                               sizeof("OWNER@") - 1);
9466 +       if (error < 0)
9467 +               goto out;
9468 +       pa++;
9469 +
9470 +       while (pa->e_tag == ACL_USER) {
9471 +               mask = mask_from_posix(pa->e_perm, 0);
9472 +               error = idmapper->uid2name(idarg, pa->e_id, xname);
9473 +               if (error < 0)
9474 +                       goto out;
9475 +               xnamelen = error;
9476 +
9477 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9478 +                               eflag,  mask_mask, xname, xnamelen);
9479 +               if (error < 0)
9480 +                       goto out;
9481 +
9482 +
9483 +               error = nfs4_acl_add_pair(acl, eflag, mask, xname, xnamelen);
9484 +               if (error < 0)
9485 +                       goto out;
9486 +               pa++;
9487 +       }
9488 +
9489 +       /* In the case of groups, we apply allow ACEs first, then deny ACEs,
9490 +        * since a user can be in more than one group.  */
9491 +
9492 +       /* allow ACEs */
9493 +
9494 +       if (pacl->a_count > 3) {
9495 +               BUG_ON(pa->e_tag != ACL_GROUP_OBJ);
9496 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9497 +                               NFS4_ACE_IDENTIFIER_GROUP | eflag, mask_mask,
9498 +                               "GROUP@", sizeof("GROUP@") - 1);
9499 +               if (error < 0)
9500 +                       goto out;
9501 +       }
9502 +       group_owner_entry = pa;
9503 +       mask = mask_from_posix(pa->e_perm, 0);
9504 +       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
9505 +                       NFS4_ACE_IDENTIFIER_GROUP | eflag, mask,
9506 +                       "GROUP@", sizeof("GROUP@") - 1);
9507 +       if (error < 0)
9508 +               goto out;
9509 +       pa++;
9510 +
9511 +       while (pa->e_tag == ACL_GROUP) {
9512 +               mask = mask_from_posix(pa->e_perm, 0);
9513 +               error = idmapper->gid2name(idarg, pa->e_id, xname);
9514 +               if (error < 0)
9515 +                       goto out;
9516 +               xnamelen = error;
9517 +
9518 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9519 +                               NFS4_ACE_IDENTIFIER_GROUP | eflag,
9520 +                               mask_mask, xname, xnamelen);
9521 +               if (error < 0)
9522 +                       goto out;
9523 +
9524 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
9525 +                   NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, xname, xnamelen);
9526 +               if (error < 0)
9527 +                       goto out;
9528 +               pa++;
9529 +       }
9530 +
9531 +       /* deny ACEs */
9532 +
9533 +       pa = group_owner_entry;
9534 +       mask = mask_from_posix(pa->e_perm, 0);
9535 +       error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9536 +                       NFS4_ACE_IDENTIFIER_GROUP | eflag,
9537 +                       ~mask, "GROUP@", sizeof("GROUP@") - 1);
9538 +       if (error < 0)
9539 +               goto out;
9540 +       pa++;
9541 +       while (pa->e_tag == ACL_GROUP) {
9542 +               mask = mask_from_posix(pa->e_perm, 0);
9543 +               error = idmapper->gid2name(idarg, pa->e_id, xname);
9544 +               if (error < 0)
9545 +                       goto out;
9546 +               xnamelen = error;
9547 +
9548 +               error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9549 +                   NFS4_ACE_IDENTIFIER_GROUP | eflag, ~mask, xname, xnamelen);
9550 +               if (error < 0)
9551 +                       goto out;
9552 +               pa++;
9553 +       }
9554 +
9555 +       if (pa->e_tag == ACL_MASK)
9556 +               pa++;
9557 +       BUG_ON(pa->e_tag != ACL_OTHER);
9558 +       mask = mask_from_posix(pa->e_perm, 0);
9559 +       error = nfs4_acl_add_pair(acl, eflag, mask, "EVERYONE@",
9560 +                               sizeof("EVERYONE@") - 1);
9561 +
9562 +out:
9563 +       return error;
9564 +}
9565 +
9566 +static void
9567 +sort_pacl_range(struct posix_acl *pacl, int start, int end) {
9568 +       int sorted = 0, i;
9569 +       struct posix_acl_entry tmp;
9570 +
9571 +       /* We just do a bubble sort; easy to do in place, and we're not
9572 +        * expecting acl's to be long enough to justify anything more. */
9573 +       while (!sorted) {
9574 +               sorted = 1;
9575 +               for (i = start; i < end; i++) {
9576 +                       if (pacl->a_entries[i].e_id
9577 +                                       > pacl->a_entries[i+1].e_id) {
9578 +                               sorted = 0;
9579 +                               tmp = pacl->a_entries[i];
9580 +                               pacl->a_entries[i] = pacl->a_entries[i+1];
9581 +                               pacl->a_entries[i+1] = tmp;
9582 +                       }
9583 +               }
9584 +       }
9585 +}
9586 +
9587 +static void
9588 +sort_pacl(struct posix_acl *pacl)
9589 +{
9590 +       /* posix_acl_valid requires that users and groups be in order
9591 +        * by uid/gid. */
9592 +       int i, j;
9593 +
9594 +       if (pacl->a_count <= 4)
9595 +               return; /* no users or groups */
9596 +       i = 1;
9597 +       while (pacl->a_entries[i].e_tag == ACL_USER)
9598 +               i++;
9599 +       sort_pacl_range(pacl, 1, i-1);
9600 +
9601 +       BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);
9602 +       j = i++;
9603 +       while (pacl->a_entries[j].e_tag == ACL_GROUP)
9604 +               j++;
9605 +       sort_pacl_range(pacl, i, j-1);
9606 +       return;
9607 +}
9608 +
9609 +static int
9610 +write_pace(struct nfs4_ace *ace, struct posix_acl *pacl,
9611 +               struct posix_acl_entry **pace, short tag,
9612 +               struct nfs4_acl_idmapper *idmapper, void *idarg)
9613 +{
9614 +       struct posix_acl_entry *this = *pace;;
9615 +
9616 +       if (*pace == pacl->a_entries + pacl->a_count)
9617 +               return -EINVAL; /* fell off the end */
9618 +       (*pace)++;
9619 +       this->e_tag = tag;
9620 +       if (mode_from_nfs4(ace->access_mask, &this->e_perm,
9621 +                               tag == ACL_USER_OBJ))
9622 +               return -EINVAL;
9623 +       switch (tag) {
9624 +       case ACL_USER:
9625 +               return idmapper->name2uid(idarg, ace->who, ace->wholen,
9626 +                               &this->e_id);
9627 +       case ACL_GROUP:
9628 +               return idmapper->name2gid(idarg, ace->who, ace->wholen,
9629 +                               &this->e_id);
9630 +       default:
9631 +               this->e_id = ACL_UNDEFINED_ID;
9632 +               return 0;
9633 +       }
9634 +}
9635 +
9636 +static struct nfs4_ace *
9637 +get_next_v4_ace(struct list_head **p, struct list_head *head)
9638 +{
9639 +       struct nfs4_ace *ace;
9640 +
9641 +       *p = (*p)->next;
9642 +       if (*p == head)
9643 +               return NULL;
9644 +       ace = list_entry(*p, struct nfs4_ace, l_ace);
9645 +
9646 +       return ace;
9647 +}
9648 +
9649 +int
9650 +nfs4_acl_nfsv4_to_posix(struct nfs4_acl_idmapper *idmapper, void *idarg,
9651 +               struct nfs4_acl *acl, struct posix_acl **pacl,
9652 +               struct posix_acl **dpacl)
9653 +{
9654 +       struct nfs4_acl *dacl;
9655 +       int error = -ENOMEM;
9656 +
9657 +       *pacl = NULL;
9658 +       *dpacl = NULL;
9659 +
9660 +       dacl = nfs4_acl_new();
9661 +       if (dacl == NULL)
9662 +               goto out;
9663 +
9664 +       error = nfs4_acl_split(acl, dacl);
9665 +       if (error < 0)
9666 +               goto out_acl;
9667 +
9668 +       if (pacl != NULL) {
9669 +               if (acl->naces == 0) {
9670 +                       error = -ENODATA;
9671 +                       goto try_dpacl;
9672 +               }
9673 +
9674 +               *pacl = _nfsv4_to_posix_one(idmapper, idarg, acl);
9675 +               if (IS_ERR(*pacl)) {
9676 +                       error = PTR_ERR(*pacl);
9677 +                       *pacl = NULL;
9678 +                       goto out_acl;
9679 +               }
9680 +       }
9681 +
9682 +try_dpacl:
9683 +       if (dpacl != NULL) {
9684 +               if (dacl->naces == 0) {
9685 +                       if (pacl == NULL || *pacl == NULL)
9686 +                               error = -ENODATA;
9687 +                       goto out_acl;
9688 +               }
9689 +
9690 +               error = 0;
9691 +               *dpacl = _nfsv4_to_posix_one(idmapper, idarg, dacl);
9692 +               if (IS_ERR(*dpacl)) {
9693 +                       error = PTR_ERR(*dpacl);
9694 +                       *dpacl = NULL;
9695 +                       goto out_acl;
9696 +               }
9697 +       }
9698 +
9699 +out_acl:
9700 +       if (error && pacl) {
9701 +               posix_acl_release(*pacl);
9702 +               *pacl = NULL;
9703 +       }
9704 +       nfs4_acl_free(dacl);
9705 +out:
9706 +       return error;
9707 +}
9708 +
9709 +static int
9710 +complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny)
9711 +{
9712 +       return MASK_EQUAL(allow->access_mask, ~deny->access_mask) &&
9713 +               allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
9714 +               deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE &&
9715 +               allow->flag == deny->flag &&
9716 +               allow->wholen == deny->wholen &&
9717 +               memcmp(allow->who, deny->who, allow->wholen) == 0;
9718 +}
9719 +
9720 +static inline int
9721 +user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
9722 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
9723 +               struct nfs4_acl_idmapper *idmapper, void *idarg)
9724 +{
9725 +       int error = -EINVAL;
9726 +       struct nfs4_ace *ace, *ace2;
9727 +
9728 +       ace = get_next_v4_ace(p, &n4acl->ace_head);
9729 +       if (ace == NULL)
9730 +               goto out;
9731 +       if (ace2type(ace) != ACL_USER_OBJ)
9732 +               goto out;
9733 +       error = write_pace(ace, pacl, pace, ACL_USER_OBJ, idmapper, idarg);
9734 +       if (error < 0)
9735 +               goto out;
9736 +       error = -EINVAL;
9737 +       ace2 = get_next_v4_ace(p, &n4acl->ace_head);
9738 +       if (ace2 == NULL)
9739 +               goto out;
9740 +       if (!complementary_ace_pair(ace, ace2))
9741 +               goto out;
9742 +       error = 0;
9743 +out:
9744 +       return error;
9745 +}
9746 +
9747 +static inline int
9748 +users_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
9749 +               struct nfs4_ace **mask_ace,
9750 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
9751 +               struct nfs4_acl_idmapper *idmapper, void *idarg)
9752 +{
9753 +       int error = -EINVAL;
9754 +       struct nfs4_ace *ace, *ace2;
9755 +
9756 +       ace = get_next_v4_ace(p, &n4acl->ace_head);
9757 +       if (ace == NULL)
9758 +               goto out;
9759 +       while (ace2type(ace) == ACL_USER) {
9760 +               if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
9761 +                       goto out;
9762 +               if (*mask_ace &&
9763 +                       !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
9764 +                       goto out;
9765 +               *mask_ace = ace;
9766 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
9767 +               if (ace == NULL)
9768 +                       goto out;
9769 +               if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
9770 +                       goto out;
9771 +               error = write_pace(ace, pacl, pace, ACL_USER, idmapper, idarg);
9772 +               if (error < 0)
9773 +                       goto out;
9774 +               error = -EINVAL;
9775 +               ace2 = get_next_v4_ace(p, &n4acl->ace_head);
9776 +               if (ace2 == NULL)
9777 +                       goto out;
9778 +               if (!complementary_ace_pair(ace, ace2))
9779 +                       goto out;
9780 +               if ((*mask_ace)->flag != ace2->flag ||
9781 +                       ace2->wholen != (*mask_ace)->wholen ||
9782 +                       memcmp(ace2->who, (*mask_ace)->who,
9783 +                               (*mask_ace)->wholen) != 0)
9784 +                       goto out;
9785 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
9786 +               if (ace == NULL)
9787 +                       goto out;
9788 +       }
9789 +       error = 0;
9790 +out:
9791 +       return error;
9792 +}
9793 +
9794 +static inline int
9795 +group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
9796 +               struct nfs4_ace **mask_ace,
9797 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
9798 +               struct nfs4_acl_idmapper *idmapper, void *idarg)
9799 +{
9800 +       int error = -EINVAL;
9801 +       struct nfs4_ace *ace, *ace2;
9802 +       struct ace_container *ac;
9803 +       struct list_head group_l;
9804 +
9805 +       INIT_LIST_HEAD(&group_l);
9806 +       ace = list_entry(*p, struct nfs4_ace, l_ace);
9807 +       
9808 +       /* group owner (mask and allow aces) */
9809 +
9810 +       if (pacl->a_count != 3) {
9811 +               /* then the group owner should be preceded by mask */
9812 +               if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
9813 +                       goto out;
9814 +               if (*mask_ace &&
9815 +                       !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
9816 +                       goto out;
9817 +               *mask_ace = ace;
9818 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
9819 +               if (ace == NULL)
9820 +                       goto out;
9821 +               
9822 +               if ((*mask_ace)->flag != ace->flag ||
9823 +                       ace->wholen != (*mask_ace)->wholen ||
9824 +                       memcmp(ace->who, (*mask_ace)->who,
9825 +                               (*mask_ace)->wholen) != 0)
9826 +                       goto out;
9827 +       }
9828 +
9829 +       if (ace2type(ace) != ACL_GROUP_OBJ)
9830 +               goto out;
9831 +       
9832 +       ac = kmalloc(sizeof(*ac), GFP_KERNEL);
9833 +       error = -ENOMEM;
9834 +       if (ac == NULL)
9835 +               goto out;
9836 +       ac->ace = ace;
9837 +       list_add_tail(&ac->ace_l, &group_l);
9838 +
9839 +       error = -EINVAL;
9840 +       if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
9841 +               goto out;
9842 +
9843 +       error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, idmapper, idarg);
9844 +       if (error < 0)
9845 +               goto out;
9846 +
9847 +       error = -EINVAL;
9848 +       ace = get_next_v4_ace(p, &n4acl->ace_head);
9849 +       if (ace == NULL)
9850 +               goto out;
9851 +
9852 +       /* groups (mask and allow aces) */
9853 +
9854 +       while (ace2type(ace) == ACL_GROUP) {
9855 +               if (*mask_ace == NULL)
9856 +                       goto out;
9857 +
9858 +               if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
9859 +                       !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
9860 +                       goto out;
9861 +               *mask_ace = ace;
9862 +
9863 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
9864 +               if (ace == NULL)
9865 +                       goto out;
9866 +               ac = kmalloc(sizeof(*ac), GFP_KERNEL);
9867 +               error = -ENOMEM;
9868 +               if (ac == NULL)
9869 +                       goto out;
9870 +               error = -EINVAL;
9871 +               if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE ||
9872 +                       ace->wholen != (*mask_ace)->wholen ||
9873 +                       memcmp(ace->who, (*mask_ace)->who, (*mask_ace)->wholen) != 0)
9874 +                       goto out;
9875 +
9876 +               ac->ace = ace;
9877 +               list_add_tail(&ac->ace_l, &group_l);
9878 +
9879 +               error = write_pace(ace, pacl, pace, ACL_GROUP, idmapper, idarg);
9880 +               if (error < 0)
9881 +                       goto out;
9882 +               error = -EINVAL;
9883 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
9884 +               if (ace == NULL)
9885 +                       goto out;
9886 +       }
9887 +
9888 +       /* group owner (deny ace) */
9889 +
9890 +       if (ace2type(ace) != ACL_GROUP_OBJ)
9891 +               goto out;
9892 +       ac = list_entry(group_l.next, struct ace_container, ace_l);
9893 +       ace2 = ac->ace;
9894 +       if (!complementary_ace_pair(ace2, ace))
9895 +               goto out;
9896 +       list_del(group_l.next);
9897 +       kfree(ac);
9898 +
9899 +       /* groups (deny aces) */
9900 +
9901 +       while (!list_empty(&group_l)) {
9902 +               ace = get_next_v4_ace(p, &n4acl->ace_head);
9903 +               if (ace == NULL)
9904 +                       goto out;
9905 +               if (ace2type(ace) != ACL_GROUP)
9906 +                       goto out;
9907 +               ac = list_entry(group_l.next, struct ace_container, ace_l);
9908 +               ace2 = ac->ace;
9909 +               if (!complementary_ace_pair(ace2, ace))
9910 +                       goto out;
9911 +               list_del(group_l.next);
9912 +               kfree(ac);
9913 +       }
9914 +
9915 +       ace = get_next_v4_ace(p, &n4acl->ace_head);
9916 +       if (ace == NULL)
9917 +               goto out;
9918 +       if (ace2type(ace) != ACL_OTHER)
9919 +               goto out;
9920 +       error = 0;
9921 +out:
9922 +       while (!list_empty(&group_l)) {
9923 +               ac = list_entry(group_l.next, struct ace_container, ace_l);
9924 +               list_del(group_l.next);
9925 +               kfree(ac);
9926 +       }
9927 +       return error;
9928 +}
9929 +
9930 +static inline int
9931 +mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
9932 +               struct nfs4_ace **mask_ace,
9933 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
9934 +               struct nfs4_acl_idmapper *idmapper, void *idarg)
9935 +{
9936 +       int error = -EINVAL;
9937 +       struct nfs4_ace *ace;
9938 +
9939 +       ace = list_entry(*p, struct nfs4_ace, l_ace);
9940 +       if (pacl->a_count != 3) {
9941 +               if (*mask_ace == NULL)
9942 +                       goto out;
9943 +               (*mask_ace)->access_mask = ~(*mask_ace)->access_mask;
9944 +               write_pace(*mask_ace, pacl, pace, ACL_MASK, idmapper, idarg);
9945 +       }
9946 +       error = 0;
9947 +out:
9948 +       return error;
9949 +}
9950 +
9951 +static inline int
9952 +other_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
9953 +               struct posix_acl *pacl, struct posix_acl_entry **pace,
9954 +               struct nfs4_acl_idmapper *idmapper, void *idarg)
9955 +{
9956 +       int error = -EINVAL;
9957 +       struct nfs4_ace *ace, *ace2;
9958 +
9959 +       ace = list_entry(*p, struct nfs4_ace, l_ace);
9960 +       if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
9961 +               goto out;
9962 +       error = write_pace(ace, pacl, pace, ACL_OTHER, idmapper, idarg);
9963 +       if (error < 0)
9964 +               goto out;
9965 +       error = -EINVAL;
9966 +       ace2 = get_next_v4_ace(p, &n4acl->ace_head);
9967 +       if (ace2 == NULL)
9968 +               goto out;
9969 +       if (!complementary_ace_pair(ace, ace2))
9970 +               goto out;
9971 +       error = 0;
9972 +out:
9973 +       return error;
9974 +}
9975 +
9976 +static int
9977 +calculate_posix_ace_count(struct nfs4_acl *n4acl)
9978 +{
9979 +       if (n4acl->naces == 6) /* owner, owner group, and other only */
9980 +               return 3;
9981 +       else { /* Otherwise there must be a mask entry. */
9982 +               /* Also, the remaining entries are for named users and
9983 +                * groups, and come in threes (mask, allow, deny): */
9984 +               if ( (n4acl->naces - 7) % 3)
9985 +                       return -1;
9986 +               return 4 + (n4acl->naces - 7)/3;
9987 +       }
9988 +}
9989 +
9990 +
9991 +static struct posix_acl *
9992 +_nfsv4_to_posix_one(struct nfs4_acl_idmapper *idmapper, void *idarg, struct nfs4_acl *n4acl)
9993 +{
9994 +       struct posix_acl *pacl;
9995 +       int error = -EINVAL, nace = 0;
9996 +       struct list_head *p;
9997 +       struct nfs4_ace *mask_ace = NULL;
9998 +       struct posix_acl_entry *pace;
9999 +
10000 +       nace = calculate_posix_ace_count(n4acl);
10001 +
10002 +       pacl = posix_acl_alloc(nace, GFP_KERNEL);
10003 +       error = -ENOMEM;
10004 +       if (pacl == NULL)
10005 +               goto out_err;
10006 +
10007 +       pace = &pacl->a_entries[0];
10008 +       p = &n4acl->ace_head;
10009 +
10010 +       error = user_obj_from_v4(n4acl, &p, pacl, &pace, idmapper, idarg);
10011 +       if (error)
10012 +               goto out_acl;
10013 +
10014 +       error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, idmapper,
10015 +                       idarg);
10016 +       if (error)
10017 +               goto out_acl;
10018 +
10019 +       error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace,
10020 +                       idmapper, idarg);
10021 +       if (error)
10022 +               goto out_acl;
10023 +
10024 +       error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, idmapper, idarg);
10025 +       if (error)
10026 +               goto out_acl;
10027 +       error = other_from_v4(n4acl, &p, pacl, &pace, idmapper, idarg);
10028 +       if (error)
10029 +               goto out_acl;
10030 +
10031 +       error = -EINVAL;
10032 +       if (p->next != &n4acl->ace_head)
10033 +               goto out_acl;
10034 +       if (pace != pacl->a_entries + pacl->a_count)
10035 +               goto out_acl;
10036 +
10037 +       sort_pacl(pacl);
10038 +
10039 +       return pacl;
10040 +out_acl:
10041 +       posix_acl_release(pacl);
10042 +out_err:
10043 +       pacl = ERR_PTR(error);
10044 +       return pacl;
10045 +}
10046 +
10047 +
10048 +struct nfs4_acl *
10049 +nfs4_acl_new(void)
10050 +{
10051 +       struct nfs4_acl *acl;
10052 +
10053 +       if ((acl = kmalloc(sizeof(*acl), GFP_KERNEL)) == NULL)
10054 +               return NULL;
10055 +
10056 +       acl->naces = 0;
10057 +       INIT_LIST_HEAD(&acl->ace_head);
10058 +
10059 +       return acl;
10060 +}
10061 +
10062 +void
10063 +nfs4_acl_free(struct nfs4_acl *acl)
10064 +{
10065 +       struct list_head *h;
10066 +       struct nfs4_ace *ace;
10067 +
10068 +       if (!acl)
10069 +               return;
10070 +
10071 +       while (!list_empty(&acl->ace_head)) {
10072 +               h = acl->ace_head.next;
10073 +               list_del(h);
10074 +               ace = list_entry(h, struct nfs4_ace, l_ace);
10075 +               if (ace->who != NULL)
10076 +                       kfree(ace->who);
10077 +               kfree(ace);
10078 +       }
10079 +
10080 +       kfree(acl);
10081 +
10082 +       return;
10083 +}
10084 +
10085 +int
10086 +nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
10087 +    char *who, u32 wholen)
10088 +{
10089 +       struct nfs4_ace *ace;
10090 +
10091 +       if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL)
10092 +               return -1;
10093 +
10094 +       ace->type = type;
10095 +       ace->flag = flag;
10096 +       ace->access_mask = access_mask;
10097 +       if (wholen > 0) {
10098 +               if ((ace->who = kmalloc(wholen, GFP_KERNEL)) == NULL)
10099 +                       goto fail;
10100 +               memcpy(ace->who, who, wholen);
10101 +       }
10102 +       ace->wholen = wholen;
10103 +
10104 +       list_add_tail(&ace->l_ace, &acl->ace_head);
10105 +
10106 +       return ++acl->naces; /* XXXJBF: why? */
10107 +
10108 +fail:
10109 +       kfree(ace);
10110 +       return -1;
10111 +}
10112 +    
10113 +
10114 +int
10115 +nfs4_acl_merge(struct nfs4_acl *fromacl, struct nfs4_acl *withacl)
10116 +{
10117 +       struct nfs4_ace *ace;
10118 +       struct list_head *h;
10119 +
10120 +       if (fromacl == NULL || withacl == NULL)
10121 +               return 0;
10122 +
10123 +       while (!list_empty(&fromacl->ace_head)) {
10124 +               h = fromacl->ace_head.next;
10125 +               list_del(h);
10126 +               ace = list_entry(h, struct nfs4_ace, l_ace);
10127 +               /* XXX */
10128 +               ace->flag |= NFS4_ACE_FILE_INHERIT_ACE |
10129 +                   NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE;
10130 +               list_add_tail(&ace->l_ace, &withacl->ace_head);
10131 +               withacl->naces++;
10132 +       }
10133 +
10134 +       return 0;
10135 +}
10136 +
10137 +int
10138 +nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
10139 +{
10140 +       struct list_head *h, *n;
10141 +       struct nfs4_ace *ace;
10142 +       int error = 0;
10143 +
10144 +       list_for_each_safe(h, n, &acl->ace_head) {
10145 +               ace = list_entry(h, struct nfs4_ace, l_ace);
10146 +
10147 +               if (!(ace->flag & NFS4_ACE_DIRECTORY_INHERIT_ACE &&
10148 +                       ace->flag & NFS4_ACE_FILE_INHERIT_ACE &&
10149 +                       ace->flag & NFS4_ACE_INHERIT_ONLY_ACE))
10150 +                       continue;
10151 +
10152 +               error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
10153 +                   ace->access_mask, ace->who, ace->wholen) == -1;
10154 +               if (error < 0)
10155 +                       goto out;
10156 +
10157 +               list_del(h);
10158 +               if (ace->who != NULL)
10159 +                       kfree(ace->who);
10160 +               kfree(ace);
10161 +               acl->naces--;
10162 +       }
10163 +
10164 +out:
10165 +       return error;
10166 +}
10167 +
10168 +static struct {
10169 +       char *string;
10170 +       int   stringlen;
10171 +       short   type;
10172 +} s2t_map[] = {
10173 +       {
10174 +               .string    = "OWNER@",
10175 +               .stringlen = sizeof("OWNER@") - 1,
10176 +               .type      = ACL_USER_OBJ
10177 +       },
10178 +       {
10179 +               .string    = "GROUP@",
10180 +               .stringlen = sizeof("GROUP@") - 1,
10181 +               .type      = ACL_GROUP_OBJ
10182 +       },
10183 +       {
10184 +               .string    = "EVERYONE@",
10185 +               .stringlen = sizeof("EVERYONE@") - 1,
10186 +               .type      = ACL_OTHER
10187 +       },
10188 +};
10189 +
10190 +static short
10191 +ace2type(struct nfs4_ace *ace)
10192 +{
10193 +       int i;
10194 +
10195 +       if (ace->who == NULL || ace->wholen <= 0)
10196 +               return (0);
10197 +
10198 +       for (i = 0; i < sizeof(s2t_map) / sizeof(*s2t_map); i++)
10199 +               if (s2t_map[i].stringlen == ace->wholen &&
10200 +                   strncmp(s2t_map[i].string, ace->who, ace->wholen) == 0)
10201 +                       return (s2t_map[i].type);
10202 +
10203 +       return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ? ACL_GROUP : ACL_USER);
10204 +}
10205 diff -puN /dev/null fs/nfs4acl/acl_syms.c
10206 --- /dev/null   2004-01-26 19:20:21.000000000 -0500
10207 +++ linux-2.6.3-bfields/fs/nfs4acl/acl_syms.c   2004-02-19 16:47:06.000000000 -0500
10208 @@ -0,0 +1,51 @@
10209 +/*
10210 + *  fs/nfs4acl/acl_syms.c
10211 + *
10212 + *  Common NFSv4 ACL handling symbol exports.
10213 + *
10214 + *  Copyright (c) 2002 The Regents of the University of Michigan.
10215 + *  All rights reserved.
10216 + *
10217 + *  Marius Aamodt Eriksen <marius@umich.edu>
10218 + * 
10219 + *  Redistribution and use in source and binary forms, with or without
10220 + *  modification, are permitted provided that the following conditions
10221 + *  are met:
10222 + *
10223 + *  1. Redistributions of source code must retain the above copyright
10224 + *     notice, this list of conditions and the following disclaimer.
10225 + *  2. Redistributions in binary form must reproduce the above copyright
10226 + *     notice, this list of conditions and the following disclaimer in the
10227 + *     documentation and/or other materials provided with the distribution.
10228 + *  3. Neither the name of the University nor the names of its
10229 + *     contributors may be used to endorse or promote products derived
10230 + *     from this software without specific prior written permission.
10231 + *
10232 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
10233 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
10234 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
10235 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
10236 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10237 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
10238 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
10239 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
10240 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
10241 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
10242 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10243 + */
10244 +
10245 +
10246 +#include <linux/config.h>
10247 +#include <linux/module.h>
10248 +
10249 +#include <linux/types.h>
10250 +#include <linux/fs.h>
10251 +#include <linux/posix_acl.h>
10252 +#include <linux/nfs4.h>
10253 +#include <linux/nfs4_acl.h>
10254 +
10255 +EXPORT_SYMBOL(nfs4_acl_new);
10256 +EXPORT_SYMBOL(nfs4_acl_free);
10257 +EXPORT_SYMBOL(nfs4_acl_merge);
10258 +EXPORT_SYMBOL(nfs4_acl_split);
10259 +EXPORT_SYMBOL(nfs4_acl_add_ace);
10260 diff -puN /dev/null fs/nfs4acl/Makefile
10261 --- /dev/null   2004-01-26 19:20:21.000000000 -0500
10262 +++ linux-2.6.3-bfields/fs/nfs4acl/Makefile     2004-02-19 16:47:06.000000000 -0500
10263 @@ -0,0 +1,3 @@
10264 +obj-$(CONFIG_NFS_V4_ACL) += nfs4acl.o
10265 +
10266 +nfs4acl-objs := acl.o acl_syms.o
10267 diff -puN /dev/null include/linux/nfs4_acl.h
10268 --- /dev/null   2004-01-26 19:20:21.000000000 -0500
10269 +++ linux-2.6.3-bfields/include/linux/nfs4_acl.h        2004-02-19 16:47:06.000000000 -0500
10270 @@ -0,0 +1,68 @@
10271 +/*
10272 + *  include/linux/nfs4_acl.c
10273 + *
10274 + *  Common NFSv4 ACL handling definitions.
10275 + *
10276 + *  Copyright (c) 2002 The Regents of the University of Michigan.
10277 + *  All rights reserved.
10278 + *
10279 + *  Marius Aamodt Eriksen <marius@umich.edu>
10280 + * 
10281 + *  Redistribution and use in source and binary forms, with or without
10282 + *  modification, are permitted provided that the following conditions
10283 + *  are met:
10284 + *
10285 + *  1. Redistributions of source code must retain the above copyright
10286 + *     notice, this list of conditions and the following disclaimer.
10287 + *  2. Redistributions in binary form must reproduce the above copyright
10288 + *     notice, this list of conditions and the following disclaimer in the
10289 + *     documentation and/or other materials provided with the distribution.
10290 + *  3. Neither the name of the University nor the names of its
10291 + *     contributors may be used to endorse or promote products derived
10292 + *     from this software without specific prior written permission.
10293 + *
10294 + *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
10295 + *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
10296 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
10297 + *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
10298 + *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
10299 + *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
10300 + *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
10301 + *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
10302 + *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
10303 + *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
10304 + *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
10305 + */
10306 +
10307 +#ifndef LINUX_NFS4_ACL_H
10308 +#define LINUX_NFS4_ACL_H
10309 +
10310 +#include <linux/posix_acl.h>
10311 +
10312 +#define NFS4_ACL_TYPE_ACCESS  0
10313 +#define NFS4_ACL_TYPE_DEFAULT 1
10314 +
10315 +/* XXX from include/linux/nfs_idmap.h: */
10316 +#define IDMAP_NAMESZ   128
10317 +
10318 +struct nfs4_acl_idmapper {
10319 +       int     (*name2uid)(void *, const char *, size_t len, __u32 *);
10320 +       int     (*name2gid)(void *, const char *, size_t len, __u32 *);
10321 +       int     (*uid2name)(void *, __u32, char *);
10322 +       int     (*gid2name)(void *, __u32, char *);
10323 +};
10324 +
10325 +struct nfs4_acl  *nfs4_acl_new(void);
10326 +void             nfs4_acl_free(struct nfs4_acl *);
10327 +int               nfs4_acl_merge(struct nfs4_acl *, struct nfs4_acl *);
10328 +int               nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *);
10329 +int               nfs4_acl_add_ace(struct nfs4_acl *, u32, u32,
10330 +                      u32, char *, u32);
10331 +void              nfs4_acl_print(struct nfs4_acl *);
10332 +struct nfs4_acl  *nfs4_acl_posix_to_nfsv4(struct nfs4_acl_idmapper *, void *,
10333 +                      struct posix_acl *, struct posix_acl *);
10334 +int               nfs4_acl_nfsv4_to_posix(struct nfs4_acl_idmapper *, void *,
10335 +                      struct nfs4_acl *, struct posix_acl **,
10336 +                      struct posix_acl **);
10337 +
10338 +#endif /* LINUX_NFS4_ACL_H */
10339 diff -puN include/linux/nfs4.h~CITI_NFS4_ALL include/linux/nfs4.h
10340 --- linux-2.6.3/include/linux/nfs4.h~CITI_NFS4_ALL      2004-02-19 16:47:06.000000000 -0500
10341 +++ linux-2.6.3-bfields/include/linux/nfs4.h    2004-02-19 16:47:14.000000000 -0500
10342 @@ -37,14 +37,67 @@
10343  #define NFS4_SHARE_ACCESS_BOTH 0x0003
10344  #define NFS4_SHARE_DENY_READ   0x0001
10345  #define NFS4_SHARE_DENY_WRITE  0x0002
10346 +#define NFS4_SHARE_DENY_BOTH   0x0003
10347  
10348  #define NFS4_SET_TO_SERVER_TIME        0
10349  #define NFS4_SET_TO_CLIENT_TIME        1
10350  
10351 -#define NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE 0
10352 -#define NFS4_ACE_ACCESS_DENIED_ACE_TYPE  1
10353 -#define NFS4_ACE_SYSTEM_AUDIT_ACE_TYPE   2
10354 -#define NFS4_ACE_SYSTEM_ALARM_ACE_TYPE   3
10355 +#define ACL4_SUPPORT_ALLOW_ACL            0x00000001
10356 +#define ACL4_SUPPORT_DENY_ACL             0x00000002
10357 +#define ACL4_SUPPORT_AUDIT_ACL            0x00000004
10358 +#define ACL4_SUPPORT_ALARM_ACL            0x00000008
10359 +
10360 +#define NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE      0x00000000
10361 +#define NFS4_ACE_ACCESS_DENIED_ACE_TYPE       0x00000001
10362 +#define NFS4_ACE_SYSTEM_AUDIT_ACE_TYPE        0x00000002
10363 +#define NFS4_ACE_SYSTEM_ALARM_ACE_TYPE        0x00000003
10364 +
10365 +#define NFS4_ACE_FILE_INHERIT_ACE             0x00000001
10366 +#define NFS4_ACE_DIRECTORY_INHERIT_ACE        0x00000002
10367 +#define NFS4_ACE_NO_PROPAGATE_INHERIT_ACE     0x00000004
10368 +#define NFS4_ACE_INHERIT_ONLY_ACE             0x00000008
10369 +#define NFS4_ACE_SUCCESSFUL_ACCESS_ACE_FLAG   0x00000010
10370 +#define NFS4_ACE_FAILED_ACCESS_ACE_FLAG       0x00000020
10371 +#define NFS4_ACE_IDENTIFIER_GROUP             0x00000040
10372 +#define NFS4_ACE_OWNER                        0x00000080
10373 +#define NFS4_ACE_GROUP                        0x00000100
10374 +#define NFS4_ACE_EVERYONE                     0x00000200
10375 +
10376 +#define NFS4_ACE_READ_DATA                    0x00000001
10377 +#define NFS4_ACE_LIST_DIRECTORY               0x00000001
10378 +#define NFS4_ACE_WRITE_DATA                   0x00000002
10379 +#define NFS4_ACE_ADD_FILE                     0x00000002
10380 +#define NFS4_ACE_APPEND_DATA                  0x00000004
10381 +#define NFS4_ACE_ADD_SUBDIRECTORY             0x00000004
10382 +#define NFS4_ACE_READ_NAMED_ATTRS             0x00000008
10383 +#define NFS4_ACE_WRITE_NAMED_ATTRS            0x00000010
10384 +#define NFS4_ACE_EXECUTE                      0x00000020
10385 +#define NFS4_ACE_DELETE_CHILD                 0x00000040
10386 +#define NFS4_ACE_READ_ATTRIBUTES              0x00000080
10387 +#define NFS4_ACE_WRITE_ATTRIBUTES             0x00000100
10388 +#define NFS4_ACE_DELETE                       0x00010000
10389 +#define NFS4_ACE_READ_ACL                     0x00020000
10390 +#define NFS4_ACE_WRITE_ACL                    0x00040000
10391 +#define NFS4_ACE_WRITE_OWNER                  0x00080000
10392 +#define NFS4_ACE_SYNCHRONIZE                  0x00100000
10393 +#define NFS4_ACE_GENERIC_READ                 0x00120081
10394 +#define NFS4_ACE_GENERIC_WRITE                0x00160106
10395 +#define NFS4_ACE_GENERIC_EXECUTE              0x001200A0
10396 +#define NFS4_ACE_MASK_ALL                     0x001F01FF
10397 +
10398 +struct nfs4_ace {
10399 +       u32               type;
10400 +       u32               flag;
10401 +       u32               access_mask;
10402 +       char             *who;
10403 +       u32               wholen;
10404 +       struct list_head  l_ace;
10405 +};
10406 +
10407 +struct nfs4_acl {
10408 +       u32              naces;
10409 +       struct list_head ace_head;
10410 +};
10411  
10412  typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
10413  typedef struct { char data[16]; } nfs4_stateid;
10414 @@ -86,6 +139,8 @@ enum nfs_opnum4 {
10415         OP_SETCLIENTID_CONFIRM = 36,
10416         OP_VERIFY = 37,
10417         OP_WRITE = 38,
10418 +       OP_RELEASE_LOCKOWNER = 39,
10419 +       OP_ILLEGAL = 10044,
10420  };
10421  
10422  enum nfsstat4 {
10423 @@ -283,7 +338,6 @@ enum lock_type4 {
10424  
10425  enum {
10426         NFSPROC4_CLNT_NULL = 0,         /* Unused */
10427 -       NFSPROC4_CLNT_COMPOUND,         /* Soon to be unused */
10428         NFSPROC4_CLNT_READ,
10429         NFSPROC4_CLNT_WRITE,
10430         NFSPROC4_CLNT_COMMIT,
10431 @@ -300,6 +354,22 @@ enum {
10432         NFSPROC4_CLNT_LOCK,
10433         NFSPROC4_CLNT_LOCKT,
10434         NFSPROC4_CLNT_LOCKU,
10435 +       NFSPROC4_CLNT_GETACL,
10436 +       NFSPROC4_CLNT_SETACL,
10437 +       NFSPROC4_CLNT_ACCESS,
10438 +       NFSPROC4_CLNT_GETATTR,
10439 +       NFSPROC4_CLNT_LOOKUP,
10440 +       NFSPROC4_CLNT_GETROOT_HEAD,
10441 +       NFSPROC4_CLNT_GETROOT_PATH,
10442 +       NFSPROC4_CLNT_REMOVE,
10443 +       NFSPROC4_CLNT_RENAME,
10444 +       NFSPROC4_CLNT_LINK,
10445 +       NFSPROC4_CLNT_CREATE,
10446 +       NFSPROC4_CLNT_PATHCONF,
10447 +       NFSPROC4_CLNT_STATFS,
10448 +       NFSPROC4_CLNT_UNLINK,
10449 +       NFSPROC4_CLNT_READLINK,
10450 +       NFSPROC4_CLNT_READDIR,
10451  };
10452  
10453  #endif
10454 diff -puN fs/nfs/nfs4xdr.c~CITI_NFS4_ALL fs/nfs/nfs4xdr.c
10455 --- linux-2.6.3/fs/nfs/nfs4xdr.c~CITI_NFS4_ALL  2004-02-19 16:47:07.000000000 -0500
10456 +++ linux-2.6.3-bfields/fs/nfs/nfs4xdr.c        2004-02-19 16:47:15.000000000 -0500
10457 @@ -51,6 +51,7 @@
10458  #include <linux/nfs4.h>
10459  #include <linux/nfs_fs.h>
10460  #include <linux/nfs_idmap.h>
10461 +#include <linux/nfs4_acl.h>
10462  
10463  #define NFSDBG_FACILITY                NFSDBG_XDR
10464  
10465 @@ -81,11 +82,15 @@ static int nfs_stat_to_errno(int);
10466  #define decode_putrootfh_maxsz op_decode_hdr_maxsz
10467  #define encode_getfh_maxsz      op_encode_hdr_maxsz
10468  #define decode_getfh_maxsz      op_decode_hdr_maxsz + 1 + \
10469 -                                (NFS4_FHSIZE >> 2)
10470 +                                ((3+NFS4_FHSIZE) >> 2)
10471  #define encode_getattr_maxsz    op_encode_hdr_maxsz + 3
10472 -#define nfs4_fattr_bitmap_maxsz 26 + 2 * ((NFS4_MAXNAMLEN +1) >> 2)
10473 +#define nfs4_name_maxsz         ( 1 + ((3+NFS4_MAXNAMLEN) >> 2) )
10474 +#define nfs4_fattr_bitmap_maxsz 36 + 2 * nfs4_name_maxsz
10475  #define decode_getattr_maxsz    op_decode_hdr_maxsz + 3 + \
10476                                  nfs4_fattr_bitmap_maxsz
10477 +#define encode_setattr_maxsz    op_decode_hdr_maxsz + 4 + \
10478 +                                nfs4_fattr_bitmap_maxsz
10479 +#define decode_setattr_maxsz    op_decode_hdr_maxsz + 3
10480  #define encode_savefh_maxsz     op_encode_hdr_maxsz
10481  #define decode_savefh_maxsz     op_decode_hdr_maxsz
10482  #define encode_restorefh_maxsz  op_encode_hdr_maxsz
10483 @@ -115,6 +120,18 @@ static int nfs_stat_to_errno(int);
10484                                 3 + (NFS4_VERIFIER_SIZE >> 2)
10485  #define decode_setclientid_confirm_maxsz \
10486                                 op_decode_hdr_maxsz
10487 +#define encode_lookup_maxsz     op_encode_hdr_maxsz + \
10488 +                                1 + ((3 + NFS_MAXFHSIZE) >> 2)
10489 +#define encode_remove_maxsz     op_encode_hdr_maxsz + \
10490 +                                nfs4_name_maxsz
10491 +#define encode_rename_maxsz     op_encode_hdr_maxsz + \
10492 +                                2 * nfs4_name_maxsz
10493 +#define encode_link_maxsz       op_encode_hdr_maxsz + \
10494 +                                nfs4_name_maxsz
10495 +#define encode_create_maxsz     op_encode_hdr_maxsz + \
10496 +                                2 + 2 * nfs4_name_maxsz + \
10497 +                                nfs4_fattr_bitmap_maxsz
10498 +#define decode_create_maxsz     op_decode_hdr_maxsz + 8
10499  
10500  #define NFS4_enc_compound_sz   1024  /* XXX: large enough? */
10501  #define NFS4_dec_compound_sz   1024  /* XXX: large enough? */
10502 @@ -126,6 +143,18 @@ static int nfs_stat_to_errno(int);
10503                                 decode_putfh_maxsz + \
10504                                 decode_read_getattr_maxsz + \
10505                                 op_decode_hdr_maxsz + 2
10506 +#define NFS4_enc_readlink_sz   compound_encode_hdr_maxsz + \
10507 +                               encode_putfh_maxsz + \
10508 +                               op_encode_hdr_maxsz
10509 +#define NFS4_dec_readlink_sz   compound_decode_hdr_maxsz + \
10510 +                               decode_putfh_maxsz + \
10511 +                               op_decode_hdr_maxsz
10512 +#define NFS4_enc_readdir_sz    compound_encode_hdr_maxsz + \
10513 +                               encode_putfh_maxsz + \
10514 +                               op_encode_hdr_maxsz + 9
10515 +#define NFS4_dec_readdir_sz    compound_decode_hdr_maxsz + \
10516 +                               decode_putfh_maxsz + \
10517 +                               op_decode_hdr_maxsz + 2
10518  #define NFS4_enc_write_sz      compound_encode_hdr_maxsz + \
10519                                 encode_putfh_maxsz + \
10520                                 encode_pre_write_getattr_maxsz + \
10521 @@ -255,8 +284,136 @@ static int nfs_stat_to_errno(int);
10522                                 decode_putfh_maxsz + \
10523                                 decode_getattr_maxsz + \
10524                                 op_decode_hdr_maxsz + 4
10525 -
10526 -
10527 +#define NFS4_enc_getacl_sz      compound_encode_hdr_maxsz + \
10528 +                               encode_putfh_maxsz + \
10529 +                               encode_getattr_maxsz
10530 +#define username_maxsz         1 + ((IDMAP_NAMESZ + 3) >> 2)
10531 +#define ace_maxsz              3 + username_maxsz
10532 +#define acl_maxentries         (NFS_ACL_MAX_ENTRIES - 3) * 3 + 6
10533 +#define acl_maxsz              1 + (acl_maxentries) * (ace_maxsz)
10534 +#define NFS4_dec_getacl_sz      compound_decode_hdr_maxsz + \
10535 +                               decode_putfh_maxsz + \
10536 +                               op_decode_hdr_maxsz + 3 + 1 + acl_maxsz
10537 +#define NFS4_enc_setacl_sz      compound_encode_hdr_maxsz + \
10538 +                               encode_putfh_maxsz + \
10539 +                               op_encode_hdr_maxsz + 4 + 1 + acl_maxsz
10540 +#define NFS4_dec_setacl_sz      compound_decode_hdr_maxsz + \
10541 +                               decode_putfh_maxsz + \
10542 +                                decode_setattr_maxsz
10543 +#define NFS4_enc_access_sz      compound_encode_hdr_maxsz + \
10544 +                               encode_putfh_maxsz + \
10545 +                               encode_getattr_maxsz + \
10546 +                               op_encode_hdr_maxsz + 1
10547 +#define NFS4_dec_access_sz      compound_decode_hdr_maxsz + \
10548 +                               decode_putfh_maxsz + \
10549 +                                decode_getattr_maxsz + \
10550 +                                op_decode_hdr_maxsz + 2
10551 +#define NFS4_enc_getattr_sz     compound_encode_hdr_maxsz + \
10552 +                                encode_putfh_maxsz + \
10553 +                                encode_getattr_maxsz
10554 +#define NFS4_dec_getattr_sz     compound_decode_hdr_maxsz + \
10555 +                                decode_putfh_maxsz + \
10556 +                                decode_getattr_maxsz
10557 +#define NFS4_enc_lookup_sz      compound_encode_hdr_maxsz + \
10558 +                                encode_putfh_maxsz + \
10559 +                                encode_getattr_maxsz + \
10560 +                                encode_lookup_maxsz + \
10561 +                                encode_getattr_maxsz + \
10562 +                                encode_getfh_maxsz
10563 +#define NFS4_dec_lookup_sz      compound_decode_hdr_maxsz + \
10564 +                                decode_putfh_maxsz + \
10565 +                                decode_getattr_maxsz + \
10566 +                                op_decode_hdr_maxsz + \
10567 +                                decode_getattr_maxsz + \
10568 +                                decode_getfh_maxsz
10569 +#define NFS4_enc_getroot_head_sz      compound_encode_hdr_maxsz + \
10570 +                                op_encode_hdr_maxsz + 1 + \
10571 +                                encode_getattr_maxsz + \
10572 +                                encode_getfh_maxsz
10573 +#define NFS4_dec_getroot_head_sz      compound_decode_hdr_maxsz + \
10574 +                                op_decode_hdr_maxsz + \
10575 +                                decode_getattr_maxsz + \
10576 +                                decode_getfh_maxsz
10577 +#define NFS4_enc_getroot_path_sz      compound_encode_hdr_maxsz + \
10578 +                                encode_putfh_maxsz + \
10579 +                                encode_lookup_maxsz + \
10580 +                                encode_getattr_maxsz + \
10581 +                                encode_getfh_maxsz
10582 +#define NFS4_dec_getroot_path_sz      compound_decode_hdr_maxsz + \
10583 +                                decode_putfh_maxsz + \
10584 +                                op_decode_hdr_maxsz + \
10585 +                                decode_getattr_maxsz + \
10586 +                                decode_getfh_maxsz
10587 +#define NFS4_enc_remove_sz      compound_encode_hdr_maxsz + \
10588 +                                encode_putfh_maxsz + \
10589 +                                encode_remove_maxsz + \
10590 +                                encode_getattr_maxsz
10591 +#define NFS4_dec_remove_sz      compound_decode_hdr_maxsz + \
10592 +                                decode_putfh_maxsz + \
10593 +                                op_decode_hdr_maxsz + 5 + \
10594 +                                decode_getattr_maxsz
10595 +#define NFS4_enc_unlink_sz      NFS4_enc_remove_sz
10596 +#define NFS4_dec_unlink_sz      NFS4_dec_remove_sz
10597 +#define NFS4_enc_rename_sz      compound_encode_hdr_maxsz + \
10598 +                                encode_putfh_maxsz + \
10599 +                                encode_savefh_maxsz + \
10600 +                                encode_putfh_maxsz + \
10601 +                                encode_rename_maxsz + \
10602 +                                encode_getattr_maxsz + \
10603 +                                encode_restorefh_maxsz + \
10604 +                                encode_getattr_maxsz
10605 +#define NFS4_dec_rename_sz      compound_decode_hdr_maxsz + \
10606 +                                decode_putfh_maxsz + \
10607 +                                decode_savefh_maxsz + \
10608 +                                decode_putfh_maxsz + \
10609 +                                op_decode_hdr_maxsz + 5 + 5 + \
10610 +                                decode_getattr_maxsz + \
10611 +                                decode_restorefh_maxsz + \
10612 +                                decode_getattr_maxsz
10613 +#define NFS4_enc_link_sz        compound_encode_hdr_maxsz + \
10614 +                                encode_putfh_maxsz + \
10615 +                                encode_savefh_maxsz + \
10616 +                                encode_putfh_maxsz + \
10617 +                                encode_link_maxsz + \
10618 +                                encode_getattr_maxsz + \
10619 +                                encode_restorefh_maxsz + \
10620 +                                encode_getattr_maxsz
10621 +#define NFS4_dec_link_sz        compound_decode_hdr_maxsz + \
10622 +                                decode_putfh_maxsz + \
10623 +                                decode_savefh_maxsz + \
10624 +                                decode_putfh_maxsz + \
10625 +                                op_decode_hdr_maxsz + 5 + \
10626 +                                decode_getattr_maxsz + \
10627 +                                decode_restorefh_maxsz + \
10628 +                                decode_getattr_maxsz
10629 +#define NFS4_enc_create_sz      compound_encode_hdr_maxsz + \
10630 +                                encode_putfh_maxsz + \
10631 +                                encode_savefh_maxsz + \
10632 +                                encode_create_maxsz + \
10633 +                                encode_getattr_maxsz + \
10634 +                                encode_getfh_maxsz + \
10635 +                                encode_restorefh_maxsz + \
10636 +                                encode_getattr_maxsz
10637 +#define NFS4_dec_create_sz      compound_decode_hdr_maxsz + \
10638 +                                decode_putfh_maxsz + \
10639 +                                op_decode_hdr_maxsz + \
10640 +                                decode_create_maxsz + \
10641 +                                decode_getattr_maxsz + \
10642 +                                decode_getfh_maxsz + \
10643 +                                op_decode_hdr_maxsz + \
10644 +                                decode_getattr_maxsz
10645 +#define NFS4_enc_pathconf_sz    compound_encode_hdr_maxsz + \
10646 +                                encode_putfh_maxsz + \
10647 +                                encode_getattr_maxsz
10648 +#define NFS4_dec_pathconf_sz    compound_decode_hdr_maxsz + \
10649 +                                decode_putfh_maxsz + \
10650 +                                op_decode_hdr_maxsz + 6
10651 +#define NFS4_enc_statfs_sz      compound_encode_hdr_maxsz + \
10652 +                                encode_putfh_maxsz + \
10653 +                                encode_getattr_maxsz
10654 +#define NFS4_dec_statfs_sz      compound_decode_hdr_maxsz + \
10655 +                                decode_putfh_maxsz + \
10656 +                                op_decode_hdr_maxsz + 12
10657  
10658  static struct {
10659         unsigned int    mode;
10660 @@ -333,8 +490,7 @@ encode_compound_hdr(struct xdr_stream *x
10661  }
10662  
10663  static int
10664 -encode_attrs(struct xdr_stream *xdr, struct iattr *iap,
10665 -    struct nfs_server *server)
10666 +encode_attrs(struct xdr_stream *xdr, struct iattr *iap, struct nfs_server *server)
10667  {
10668         char owner_name[IDMAP_NAMESZ];
10669         char owner_group[IDMAP_NAMESZ];
10670 @@ -352,7 +508,7 @@ encode_attrs(struct xdr_stream *xdr, str
10671          * In the worst-case, this would be
10672          *   12(bitmap) + 4(attrlen) + 8(size) + 4(mode) + 4(atime) + 4(mtime)
10673          *          = 36 bytes, plus any contribution from variable-length fields
10674 -        *            such as owner/group/acl's.
10675 +        *            such as owner/group.
10676          */
10677         len = 16;
10678  
10679 @@ -392,6 +548,7 @@ encode_attrs(struct xdr_stream *xdr, str
10680                 len += 16;
10681         else if (iap->ia_valid & ATTR_MTIME)
10682                 len += 4;
10683 +
10684         RESERVE_SPACE(len);
10685  
10686         /*
10687 @@ -462,13 +619,13 @@ encode_attrs(struct xdr_stream *xdr, str
10688  }
10689  
10690  static int
10691 -encode_access(struct xdr_stream *xdr, struct nfs4_access *access)
10692 +encode_access(struct xdr_stream *xdr, u32 access)
10693  {
10694         uint32_t *p;
10695  
10696         RESERVE_SPACE(8);
10697         WRITE32(OP_ACCESS);
10698 -       WRITE32(access->ac_req_access);
10699 +       WRITE32(access);
10700         
10701         return 0;
10702  }
10703 @@ -500,37 +657,36 @@ encode_commit(struct xdr_stream *xdr, st
10704  }
10705  
10706  static int
10707 -encode_create(struct xdr_stream *xdr, struct nfs4_create *create,
10708 -    struct nfs_server *server)
10709 +encode_create(struct xdr_stream *xdr, struct nfs4_create_arg *create)
10710  {
10711         uint32_t *p;
10712         
10713         RESERVE_SPACE(8);
10714         WRITE32(OP_CREATE);
10715 -       WRITE32(create->cr_ftype);
10716 +       WRITE32(create->ftype);
10717  
10718 -       switch (create->cr_ftype) {
10719 +       switch (create->ftype) {
10720         case NF4LNK:
10721 -               RESERVE_SPACE(4 + create->cr_textlen);
10722 -               WRITE32(create->cr_textlen);
10723 -               WRITEMEM(create->cr_text, create->cr_textlen);
10724 +               RESERVE_SPACE(4 + create->u.symlink->len);
10725 +               WRITE32(create->u.symlink->len);
10726 +               WRITEMEM(create->u.symlink->name, create->u.symlink->len);
10727                 break;
10728  
10729         case NF4BLK: case NF4CHR:
10730                 RESERVE_SPACE(8);
10731 -               WRITE32(create->cr_specdata1);
10732 -               WRITE32(create->cr_specdata2);
10733 +               WRITE32(create->u.device.specdata1);
10734 +               WRITE32(create->u.device.specdata2);
10735                 break;
10736  
10737         default:
10738                 break;
10739         }
10740  
10741 -       RESERVE_SPACE(4 + create->cr_namelen);
10742 -       WRITE32(create->cr_namelen);
10743 -       WRITEMEM(create->cr_name, create->cr_namelen);
10744 +       RESERVE_SPACE(4 + create->name->len);
10745 +       WRITE32(create->name->len);
10746 +       WRITEMEM(create->name->name, create->name->len);
10747  
10748 -       return encode_attrs(xdr, create->cr_attrs, server);
10749 +       return encode_attrs(xdr, create->attrs, create->server);
10750  }
10751  
10752  static int
10753 @@ -558,11 +714,14 @@ encode_getattr_two(struct xdr_stream *xd
10754          return 0;
10755  }
10756  
10757 +extern u32 nfs4_fattr_bitmap[];
10758 +extern u32 nfs4_statfs_bitmap[];
10759 +
10760  static inline int
10761 -encode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr)
10762 +encode_getfattr(struct xdr_stream *xdr)
10763  {
10764 -       return encode_getattr_two(xdr, getattr->gt_bmval[0],
10765 -                                       getattr->gt_bmval[1]);
10766 +       return encode_getattr_two(xdr, nfs4_fattr_bitmap[0], 
10767 +                                      nfs4_fattr_bitmap[1]);
10768  }
10769  
10770  /*
10771 @@ -618,14 +777,14 @@ encode_getfh(struct xdr_stream *xdr)
10772  }
10773  
10774  static int
10775 -encode_link(struct xdr_stream *xdr, struct nfs4_link *link)
10776 +encode_link(struct xdr_stream *xdr, struct qstr *name)
10777  {
10778         uint32_t *p;
10779  
10780 -       RESERVE_SPACE(8 + link->ln_namelen);
10781 +       RESERVE_SPACE(8 + name->len);
10782         WRITE32(OP_LINK);
10783 -       WRITE32(link->ln_namelen);
10784 -       WRITEMEM(link->ln_name, link->ln_namelen);
10785 +       WRITE32(name->len);
10786 +       WRITEMEM(name->name, name->len);
10787         
10788         return 0;
10789  }
10790 @@ -705,15 +864,15 @@ encode_locku(struct xdr_stream *xdr, str
10791  }
10792  
10793  static int
10794 -encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup)
10795 +encode_lookup(struct xdr_stream *xdr, struct qstr *name)
10796  {
10797 -       int len = lookup->lo_name->len;
10798 +       int len = name->len;
10799         uint32_t *p;
10800  
10801         RESERVE_SPACE(8 + len);
10802         WRITE32(OP_LOOKUP);
10803         WRITE32(len);
10804 -       WRITEMEM(lookup->lo_name->name, len);
10805 +       WRITEMEM(name->name, len);
10806  
10807         return 0;
10808  }
10809 @@ -883,7 +1042,7 @@ encode_read(struct xdr_stream *xdr, stru
10810  }
10811  
10812  static int
10813 -encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir *readdir, struct rpc_rqst *req)
10814 +encode_readdir(struct xdr_stream *xdr, struct nfs4_readdir_arg *readdir, struct rpc_rqst *req)
10815  {
10816         struct rpc_auth *auth = req->rq_task->tk_auth;
10817         int replen;
10818 @@ -891,21 +1050,21 @@ encode_readdir(struct xdr_stream *xdr, s
10819  
10820         RESERVE_SPACE(32+sizeof(nfs4_verifier));
10821         WRITE32(OP_READDIR);
10822 -       WRITE64(readdir->rd_cookie);
10823 -       WRITEMEM(readdir->rd_req_verifier.data, sizeof(readdir->rd_req_verifier.data));
10824 -       WRITE32(readdir->rd_count >> 5);  /* meaningless "dircount" field */
10825 -       WRITE32(readdir->rd_count);
10826 +       WRITE64(readdir->cookie);
10827 +       WRITEMEM(readdir->req_verifier.data, sizeof(readdir->req_verifier.data));
10828 +       WRITE32(readdir->count >> 5);  /* meaningless "dircount" field */
10829 +       WRITE32(readdir->count);
10830         WRITE32(2);
10831 -       WRITE32(readdir->rd_bmval[0]);
10832 -       WRITE32(readdir->rd_bmval[1]);
10833 +       WRITE32(FATTR4_WORD0_FILEID);
10834 +       WRITE32(0);
10835  
10836         /* set up reply iovec
10837          *    toplevel_status + taglen + rescount + OP_PUTFH + status
10838          *      + OP_READDIR + status + verifer(2)  = 9
10839          */
10840         replen = (RPC_REPHDRSIZE + auth->au_rslack + 9) << 2;
10841 -       xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->rd_pages,
10842 -                        readdir->rd_pgbase, readdir->rd_count);
10843 +       xdr_inline_pages(&req->rq_rcv_buf, replen, readdir->pages,
10844 +                        readdir->pgbase, readdir->count);
10845  
10846         return 0;
10847  }
10848 @@ -925,37 +1084,37 @@ encode_readlink(struct xdr_stream *xdr, 
10849          *      + OP_READLINK + status  = 7
10850          */
10851         replen = (RPC_REPHDRSIZE + auth->au_rslack + 7) << 2;
10852 -       xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->rl_pages, 0, readlink->rl_count);
10853 +       xdr_inline_pages(&req->rq_rcv_buf, replen, readlink->pages, 0, readlink->count);
10854         
10855         return 0;
10856  }
10857  
10858  static int
10859 -encode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove)
10860 +encode_remove(struct xdr_stream *xdr, struct qstr *name)
10861  {
10862         uint32_t *p;
10863  
10864 -       RESERVE_SPACE(8 + remove->rm_namelen);
10865 +       RESERVE_SPACE(8 + name->len);
10866         WRITE32(OP_REMOVE);
10867 -       WRITE32(remove->rm_namelen);
10868 -       WRITEMEM(remove->rm_name, remove->rm_namelen);
10869 +       WRITE32(name->len);
10870 +       WRITEMEM(name->name, name->len);
10871  
10872         return 0;
10873  }
10874  
10875  static int
10876 -encode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename)
10877 +encode_rename(struct xdr_stream *xdr, struct qstr *oldname, struct qstr *newname)
10878  {
10879         uint32_t *p;
10880  
10881 -       RESERVE_SPACE(8 + rename->rn_oldnamelen);
10882 +       RESERVE_SPACE(8 + oldname->len);
10883         WRITE32(OP_RENAME);
10884 -       WRITE32(rename->rn_oldnamelen);
10885 -       WRITEMEM(rename->rn_oldname, rename->rn_oldnamelen);
10886 +       WRITE32(oldname->len);
10887 +       WRITEMEM(oldname->name, oldname->len);
10888         
10889 -       RESERVE_SPACE(4 + rename->rn_newnamelen);
10890 -       WRITE32(rename->rn_newnamelen);
10891 -       WRITEMEM(rename->rn_newname, rename->rn_newnamelen);
10892 +       RESERVE_SPACE(4 + newname->len);
10893 +       WRITE32(newname->len);
10894 +       WRITEMEM(newname->name, newname->len);
10895  
10896         return 0;
10897  }
10898 @@ -1011,6 +1170,39 @@ encode_setattr(struct xdr_stream *xdr, s
10899          return 0;
10900  }
10901  
10902 +extern nfs4_stateid zero_stateid;
10903 +
10904 +#ifdef CONFIG_NFS_V4_ACL
10905 +
10906 +static int
10907 +encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
10908 +{
10909 +       uint32_t *p, *attrbuflen;
10910 +       struct nfs4_ace *ace;
10911 +       struct nfs4_acl *acl = arg->acl;
10912 +
10913 +       RESERVE_SPACE(4+sizeof(zero_stateid.data));
10914 +       WRITE32(OP_SETATTR);
10915 +       WRITEMEM(zero_stateid.data, sizeof(zero_stateid.data));
10916 +       RESERVE_SPACE(4*4);
10917 +       WRITE32(1);
10918 +       WRITE32(FATTR4_WORD0_ACL);
10919 +       attrbuflen = p++;
10920 +       WRITE32(acl->naces);
10921 +       list_for_each_entry(ace, &acl->ace_head, l_ace) {
10922 +               RESERVE_SPACE(4*4 + (XDR_QUADLEN(ace->wholen) << 2));
10923 +               WRITE32(ace->type);
10924 +               WRITE32(ace->flag);
10925 +               WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL);
10926 +               WRITE32(ace->wholen);
10927 +               WRITEMEM(ace->who, ace->wholen);
10928 +       }
10929 +       *attrbuflen = htonl((char *)p - (char *)attrbuflen - 4);
10930 +       return 0;
10931 +}
10932 +
10933 +#endif /* CONFIG_NFS_V4_ACL */
10934 +
10935  static int
10936  encode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid *setclientid)
10937  {
10938 @@ -1068,312 +1260,566 @@ encode_write(struct xdr_stream *xdr, str
10939  
10940         return 0;
10941  }
10942 -
10943 -/* FIXME: this sucks */
10944 -static int
10945 -encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req)
10946 -{
10947 -       struct compound_hdr hdr = {
10948 -               .taglen = cp->taglen,
10949 -               .tag    = cp->tag,
10950 -               .nops   = cp->req_nops,
10951 -       };
10952 -       int i, status = 0;
10953 -
10954 -       encode_compound_hdr(xdr, &hdr);
10955 -
10956 -       for (i = 0; i < cp->req_nops; i++) {
10957 -               switch (cp->ops[i].opnum) {
10958 -               case OP_ACCESS:
10959 -                       status = encode_access(xdr, &cp->ops[i].u.access);
10960 -                       break;
10961 -               case OP_CREATE:
10962 -                       status = encode_create(xdr, &cp->ops[i].u.create, cp->server);
10963 -                       break;
10964 -               case OP_GETATTR:
10965 -                       status = encode_getattr(xdr, &cp->ops[i].u.getattr);
10966 -                       break;
10967 -               case OP_GETFH:
10968 -                       status = encode_getfh(xdr);
10969 -                       break;
10970 -               case OP_LINK:
10971 -                       status = encode_link(xdr, &cp->ops[i].u.link);
10972 -                       break;
10973 -               case OP_LOOKUP:
10974 -                       status = encode_lookup(xdr, &cp->ops[i].u.lookup);
10975 -                       break;
10976 -               case OP_PUTFH:
10977 -                       status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle);
10978 -                       break;
10979 -               case OP_PUTROOTFH:
10980 -                       status = encode_putrootfh(xdr);
10981 -                       break;
10982 -               case OP_READDIR:
10983 -                       status = encode_readdir(xdr, &cp->ops[i].u.readdir, req);
10984 -                       break;
10985 -               case OP_READLINK:
10986 -                       status = encode_readlink(xdr, &cp->ops[i].u.readlink, req);
10987 -                       break;
10988 -               case OP_REMOVE:
10989 -                       status = encode_remove(xdr, &cp->ops[i].u.remove);
10990 -                       break;
10991 -               case OP_RENAME:
10992 -                       status = encode_rename(xdr, &cp->ops[i].u.rename);
10993 -                       break;
10994 -               case OP_RESTOREFH:
10995 -                       status = encode_restorefh(xdr);
10996 -                       break;
10997 -               case OP_SAVEFH:
10998 -                       status = encode_savefh(xdr);
10999 -                       break;
11000 -               default:
11001 -                       BUG();
11002 -               }
11003 -               if (status)
11004 -                       return status;
11005 -       }
11006 -       
11007 -       return 0;
11008 -}
11009  /*
11010   * END OF "GENERIC" ENCODE ROUTINES.
11011   */
11012  
11013 -
11014  /*
11015 - * Encode COMPOUND argument
11016 + * Encode ACCESS request
11017   */
11018  static int
11019 -nfs4_xdr_enc_compound(struct rpc_rqst *req, uint32_t *p, struct nfs4_compound *cp)
11020 +nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, struct nfs4_accessargs *args)
11021  {
11022         struct xdr_stream xdr;
11023 +       struct compound_hdr hdr = {
11024 +               .nops   = 3,
11025 +       };
11026         int status;
11027 -       
11028 -       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11029 -       status = encode_compound(&xdr, cp, req);
11030 -       cp->timestamp = jiffies;
11031 -       return status;
11032 -}
11033 -/*
11034 - * Encode a CLOSE request
11035 - */
11036 -static int
11037 -nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
11038 -{
11039 -        struct xdr_stream xdr;
11040 -        struct compound_hdr hdr = {
11041 -                .nops   = 2,
11042 -        };
11043 -        int status;
11044  
11045 -        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11046 -        encode_compound_hdr(&xdr, &hdr);
11047 -        status = encode_putfh(&xdr, args->fh);
11048 -        if(status)
11049 -                goto out;
11050 -        status = encode_close(&xdr, args);
11051 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11052 +       encode_compound_hdr(&xdr, &hdr);
11053 +       status = encode_putfh(&xdr, args->fhandle);
11054 +       if (status)
11055 +               goto out;
11056 +       status = encode_getfattr(&xdr);
11057 +       if (status)
11058 +               goto out;
11059 +       status = encode_access(&xdr, args->req_access);
11060  out:
11061 -        return status;
11062 +       return status;
11063  }
11064  
11065  /*
11066 - * Encode an OPEN request
11067 + * Encode LOOKUP request
11068   */
11069  static int
11070 -nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
11071 +nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, struct nfs4_lookupargs *args)
11072  {
11073         struct xdr_stream xdr;
11074         struct compound_hdr hdr = {
11075 -               .nops   = 7,
11076 +               .nops   = 5,
11077         };
11078         int status;
11079  
11080         xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11081         encode_compound_hdr(&xdr, &hdr);
11082 -       status = encode_putfh(&xdr, args->fh);
11083 +       status = encode_putfh(&xdr, args->dir_fh);
11084         if (status)
11085                 goto out;
11086 -       status = encode_savefh(&xdr);
11087 +       status = encode_getfattr(&xdr);
11088         if (status)
11089                 goto out;
11090 -       status = encode_open(&xdr, args);
11091 +       status = encode_lookup(&xdr, args->name);
11092         if (status)
11093                 goto out;
11094 -       status = encode_getattr(&xdr, args->f_getattr);
11095 +       status = encode_getfattr(&xdr);
11096         if (status)
11097                 goto out;
11098         status = encode_getfh(&xdr);
11099 -       if (status)
11100 -               goto out;
11101 -       status = encode_restorefh(&xdr);
11102 -       if (status)
11103 -               goto out;
11104 -       status = encode_getattr(&xdr, args->d_getattr);
11105  out:
11106         return status;
11107  }
11108  
11109  /*
11110 - * Encode an OPEN_CONFIRM request
11111 + * Encode GETROOT_HEAD request
11112   */
11113  static int
11114 -nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
11115 +nfs4_xdr_enc_getroot_head(struct rpc_rqst *req, uint32_t *p, void *args)
11116  {
11117         struct xdr_stream xdr;
11118         struct compound_hdr hdr = {
11119 -               .nops   = 2,
11120 +               .nops   = 3,
11121         };
11122         int status;
11123  
11124         xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11125         encode_compound_hdr(&xdr, &hdr);
11126 -       status = encode_putfh(&xdr, args->fh);
11127 -       if(status)
11128 +       status = encode_putrootfh(&xdr);
11129 +       if (status)
11130                 goto out;
11131 -       status = encode_open_confirm(&xdr, args);
11132 +       status = encode_getfattr(&xdr);
11133 +       if (status)
11134 +               goto out;
11135 +       status = encode_getfh(&xdr);
11136  out:
11137         return status;
11138  }
11139  
11140  /*
11141 - * Encode an OPEN request
11142 + * Encode GETROOT_PATH request
11143   */
11144  static int
11145 -nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p,
11146 -               struct nfs_open_reclaimargs *args)
11147 +nfs4_xdr_enc_getroot_path(struct rpc_rqst *req, uint32_t *p, struct nfs4_getroot_arg *args)
11148  {
11149         struct xdr_stream xdr;
11150         struct compound_hdr hdr = {
11151 -               .nops   = 3,
11152 +               .nops   = 4,
11153         };
11154         int status;
11155  
11156         xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11157         encode_compound_hdr(&xdr, &hdr);
11158 -       status = encode_putfh(&xdr, args->fh);
11159 +       status = encode_putfh(&xdr, args->fhandle);
11160         if (status)
11161                 goto out;
11162 -       status = encode_open_reclaim(&xdr, args);
11163 +       status = encode_lookup(&xdr, args->name);
11164 +       if (status)
11165 +               goto out;
11166 +       status = encode_getfattr(&xdr);
11167         if (status)
11168                 goto out;
11169 -       status = encode_getattr(&xdr, args->f_getattr);
11170 +       status = encode_getfh(&xdr);
11171  out:
11172         return status;
11173  }
11174  
11175  /*
11176 - * Encode an OPEN_DOWNGRADE request
11177 + * Encode REMOVE request
11178   */
11179  static int
11180 -nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
11181 +nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, struct nfs4_remove_arg *args)
11182  {
11183         struct xdr_stream xdr;
11184         struct compound_hdr hdr = {
11185 -               .nops   = 2,
11186 +               .nops   = 3,
11187         };
11188         int status;
11189  
11190         xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11191         encode_compound_hdr(&xdr, &hdr);
11192 -       status = encode_putfh(&xdr, args->fh);
11193 +       status = encode_putfh(&xdr, args->fhandle);
11194         if (status)
11195                 goto out;
11196 -       status = encode_open_downgrade(&xdr, args);
11197 +       status = encode_remove(&xdr, args->name);
11198 +       if (status)
11199 +               goto out;
11200 +       status = encode_getfattr(&xdr);
11201  out:
11202         return status;
11203  }
11204  
11205  /*
11206 - * Encode a LOCK request
11207 + * Encode UNLINK request
11208   */
11209  static int
11210 -nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
11211 +nfs4_xdr_enc_unlink(struct rpc_rqst *req, uint32_t *p, struct nfs4_unlink *args)
11212  {
11213         struct xdr_stream xdr;
11214         struct compound_hdr hdr = {
11215 -               .nops   = 2,
11216 +               .nops   = 3,
11217         };
11218         int status;
11219  
11220         xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11221         encode_compound_hdr(&xdr, &hdr);
11222         status = encode_putfh(&xdr, args->fh);
11223 -       if(status)
11224 +       if (status)
11225                 goto out;
11226 -       status = encode_lock(&xdr, args);
11227 +       status = encode_remove(&xdr, args->name);
11228 +       if (status)
11229 +               goto out;
11230 +       status = encode_getfattr(&xdr);
11231  out:
11232         return status;
11233  }
11234  
11235  /*
11236 - * Encode a LOCKT request
11237 + * Encode RENAME request
11238   */
11239  static int
11240 -nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
11241 +nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, struct nfs4_rename_arg *args)
11242  {
11243         struct xdr_stream xdr;
11244         struct compound_hdr hdr = {
11245 -               .nops   = 2,
11246 +               .nops   = 7,
11247         };
11248         int status;
11249  
11250         xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11251         encode_compound_hdr(&xdr, &hdr);
11252 -       status = encode_putfh(&xdr, args->fh);
11253 -       if(status)
11254 +       status = encode_putfh(&xdr, args->old_dir);
11255 +       if (status)
11256                 goto out;
11257 -       status = encode_lockt(&xdr, args);
11258 +       status = encode_savefh(&xdr);
11259 +       if (status)
11260 +               goto out;
11261 +       status = encode_putfh(&xdr, args->new_dir);
11262 +       if (status)
11263 +               goto out;
11264 +       status = encode_rename(&xdr, args->old_name, args->new_name);
11265 +       if (status)
11266 +               goto out;
11267 +       status = encode_getfattr(&xdr);
11268 +       if (status)
11269 +               goto out;
11270 +       status = encode_restorefh(&xdr);
11271 +       if (status)
11272 +               goto out;
11273 +       status = encode_getfattr(&xdr);
11274  out:
11275         return status;
11276  }
11277  
11278  /*
11279 - * Encode a LOCKU request
11280 + * Encode LINK request
11281   */
11282  static int
11283 -nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
11284 +nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, struct nfs4_link_arg *args)
11285  {
11286         struct xdr_stream xdr;
11287         struct compound_hdr hdr = {
11288 -               .nops   = 2,
11289 +               .nops   = 7,
11290         };
11291         int status;
11292  
11293         xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11294         encode_compound_hdr(&xdr, &hdr);
11295         status = encode_putfh(&xdr, args->fh);
11296 -       if(status)
11297 +       if (status)
11298                 goto out;
11299 -       status = encode_locku(&xdr, args);
11300 +       status = encode_savefh(&xdr);
11301 +       if (status)
11302 +               goto out;
11303 +       status = encode_putfh(&xdr, args->dir_fh);
11304 +       if (status)
11305 +               goto out;
11306 +       status = encode_link(&xdr, args->name);
11307 +       if (status)
11308 +               goto out;
11309 +       status = encode_getfattr(&xdr);
11310 +       if (status)
11311 +               goto out;
11312 +       status = encode_restorefh(&xdr);
11313 +       if (status)
11314 +               goto out;
11315 +       status = encode_getfattr(&xdr);
11316  out:
11317         return status;
11318  }
11319  
11320  /*
11321 - * Encode a READ request
11322 + * Encode CREATE request
11323   */
11324  static int
11325 -nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
11326 +nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, struct nfs4_create_arg *args)
11327  {
11328 -       struct rpc_auth *auth = req->rq_task->tk_auth;
11329         struct xdr_stream xdr;
11330         struct compound_hdr hdr = {
11331 -               .nops   = 3,
11332 +               .nops   = 7,
11333         };
11334 -       int replen, status;
11335 +       int status;
11336  
11337         xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11338         encode_compound_hdr(&xdr, &hdr);
11339 -       status = encode_putfh(&xdr, args->fh);
11340 +       status = encode_putfh(&xdr, args->dir_fh);
11341         if (status)
11342                 goto out;
11343 -       status = encode_read(&xdr, args);
11344 +       status = encode_savefh(&xdr);
11345         if (status)
11346                 goto out;
11347 -       status = encode_read_getattr(&xdr);
11348 -
11349 -       /* set up reply iovec
11350 -        *    toplevel status + taglen=0 + rescount + OP_PUTFH + status
11351 +       status = encode_create(&xdr, args);
11352 +       if (status)
11353 +               goto out;
11354 +       status = encode_getfattr(&xdr);
11355 +       if (status)
11356 +               goto out;
11357 +       status = encode_getfh(&xdr);
11358 +       if (status)
11359 +               goto out;
11360 +       status = encode_restorefh(&xdr);
11361 +       if (status)
11362 +               goto out;
11363 +       status = encode_getfattr(&xdr);
11364 +out:
11365 +       return status;
11366 +}
11367 +
11368 +/*
11369 + * Encode GETATTR request
11370 + */
11371 +static int
11372 +nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, struct nfs_fh *fh)
11373 +{
11374 +       struct xdr_stream xdr;
11375 +       struct compound_hdr hdr = {
11376 +               .nops   = 2,
11377 +       };
11378 +       int status;
11379 +
11380 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11381 +       encode_compound_hdr(&xdr, &hdr);
11382 +       status = encode_putfh(&xdr, fh);
11383 +       if (status)
11384 +               goto out;
11385 +       status = encode_getfattr(&xdr);
11386 + out:
11387 +       return status;
11388 +}
11389 +
11390 +/*
11391 + * Encode a CLOSE request
11392 + */
11393 +static int
11394 +nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
11395 +{
11396 +        struct xdr_stream xdr;
11397 +        struct compound_hdr hdr = {
11398 +                .nops   = 2,
11399 +        };
11400 +        int status;
11401 +
11402 +        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11403 +        encode_compound_hdr(&xdr, &hdr);
11404 +        status = encode_putfh(&xdr, args->fh);
11405 +        if(status)
11406 +                goto out;
11407 +        status = encode_close(&xdr, args);
11408 +out:
11409 +        return status;
11410 +}
11411 +
11412 +/*
11413 + * Encode an OPEN request
11414 + */
11415 +static int
11416 +nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
11417 +{
11418 +       struct xdr_stream xdr;
11419 +       struct compound_hdr hdr = {
11420 +               .nops   = 7,
11421 +       };
11422 +       int status;
11423 +
11424 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11425 +       encode_compound_hdr(&xdr, &hdr);
11426 +       status = encode_putfh(&xdr, args->fh);
11427 +       if (status)
11428 +               goto out;
11429 +       status = encode_savefh(&xdr);
11430 +       if (status)
11431 +               goto out;
11432 +       status = encode_open(&xdr, args);
11433 +       if (status)
11434 +               goto out;
11435 +       status = encode_getfattr(&xdr);
11436 +       if (status)
11437 +               goto out;
11438 +       status = encode_getfh(&xdr);
11439 +       if (status)
11440 +               goto out;
11441 +       status = encode_restorefh(&xdr);
11442 +       if (status)
11443 +               goto out;
11444 +       status = encode_getfattr(&xdr);
11445 +out:
11446 +       return status;
11447 +}
11448 +
11449 +/*
11450 + * Encode an OPEN_CONFIRM request
11451 + */
11452 +static int
11453 +nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
11454 +{
11455 +       struct xdr_stream xdr;
11456 +       struct compound_hdr hdr = {
11457 +               .nops   = 2,
11458 +       };
11459 +       int status;
11460 +
11461 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11462 +       encode_compound_hdr(&xdr, &hdr);
11463 +       status = encode_putfh(&xdr, args->fh);
11464 +       if(status)
11465 +               goto out;
11466 +       status = encode_open_confirm(&xdr, args);
11467 +out:
11468 +       return status;
11469 +}
11470 +
11471 +/*
11472 + * Encode an OPEN request
11473 + */
11474 +static int
11475 +nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p,
11476 +               struct nfs_open_reclaimargs *args)
11477 +{
11478 +       struct xdr_stream xdr;
11479 +       struct compound_hdr hdr = {
11480 +               .nops   = 3,
11481 +       };
11482 +       int status;
11483 +
11484 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11485 +       encode_compound_hdr(&xdr, &hdr);
11486 +       status = encode_putfh(&xdr, args->fh);
11487 +       if (status)
11488 +               goto out;
11489 +       status = encode_open_reclaim(&xdr, args);
11490 +       if (status)
11491 +               goto out;
11492 +       status = encode_getfattr(&xdr);
11493 +out:
11494 +       return status;
11495 +}
11496 +
11497 +/*
11498 + * Encode an OPEN_DOWNGRADE request
11499 + */
11500 +static int
11501 +nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
11502 +{
11503 +       struct xdr_stream xdr;
11504 +       struct compound_hdr hdr = {
11505 +               .nops   = 2,
11506 +       };
11507 +       int status;
11508 +
11509 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11510 +       encode_compound_hdr(&xdr, &hdr);
11511 +       status = encode_putfh(&xdr, args->fh);
11512 +       if (status)
11513 +               goto out;
11514 +       status = encode_open_downgrade(&xdr, args);
11515 +out:
11516 +       return status;
11517 +}
11518 +
11519 +/*
11520 + * Encode a LOCK request
11521 + */
11522 +static int
11523 +nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
11524 +{
11525 +       struct xdr_stream xdr;
11526 +       struct compound_hdr hdr = {
11527 +               .nops   = 2,
11528 +       };
11529 +       int status;
11530 +
11531 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11532 +       encode_compound_hdr(&xdr, &hdr);
11533 +       status = encode_putfh(&xdr, args->fh);
11534 +       if(status)
11535 +               goto out;
11536 +       status = encode_lock(&xdr, args);
11537 +out:
11538 +       return status;
11539 +}
11540 +
11541 +/*
11542 + * Encode a LOCKT request
11543 + */
11544 +static int
11545 +nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
11546 +{
11547 +       struct xdr_stream xdr;
11548 +       struct compound_hdr hdr = {
11549 +               .nops   = 2,
11550 +       };
11551 +       int status;
11552 +
11553 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11554 +       encode_compound_hdr(&xdr, &hdr);
11555 +       status = encode_putfh(&xdr, args->fh);
11556 +       if(status)
11557 +               goto out;
11558 +       status = encode_lockt(&xdr, args);
11559 +out:
11560 +       return status;
11561 +}
11562 +
11563 +/*
11564 + * Encode a LOCKU request
11565 + */
11566 +static int
11567 +nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
11568 +{
11569 +       struct xdr_stream xdr;
11570 +       struct compound_hdr hdr = {
11571 +               .nops   = 2,
11572 +       };
11573 +       int status;
11574 +
11575 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11576 +       encode_compound_hdr(&xdr, &hdr);
11577 +       status = encode_putfh(&xdr, args->fh);
11578 +       if(status)
11579 +               goto out;
11580 +       status = encode_locku(&xdr, args);
11581 +out:
11582 +       return status;
11583 +}
11584 +
11585 +/*
11586 + * Encode a READLINK request
11587 + */
11588 +static int
11589 +nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, struct nfs4_readlink *args)
11590 +{
11591 +       struct xdr_stream xdr;
11592 +       struct compound_hdr hdr = {
11593 +               .nops   = 2,
11594 +       };
11595 +       int status;
11596 +
11597 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11598 +       encode_compound_hdr(&xdr, &hdr);
11599 +       status = encode_putfh(&xdr, args->fh);
11600 +       if(status)
11601 +               goto out;
11602 +       status = encode_readlink(&xdr, args, req);
11603 +out:
11604 +       return status;
11605 +}
11606 +
11607 +/*
11608 + * Encode a READDIR request
11609 + */
11610 +static int
11611 +nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, struct nfs4_readdir_arg *args)
11612 +{
11613 +       struct xdr_stream xdr;
11614 +       struct compound_hdr hdr = {
11615 +               .nops   = 2,
11616 +       };
11617 +       int status;
11618 +
11619 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11620 +       encode_compound_hdr(&xdr, &hdr);
11621 +       status = encode_putfh(&xdr, args->fh);
11622 +       if(status)
11623 +               goto out;
11624 +       status = encode_readdir(&xdr, args, req);
11625 +out:
11626 +       return status;
11627 +}
11628 +
11629 +/*
11630 + * Encode a READ request
11631 + */
11632 +static int
11633 +nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
11634 +{
11635 +       struct rpc_auth *auth = req->rq_task->tk_auth;
11636 +       struct xdr_stream xdr;
11637 +       struct compound_hdr hdr = {
11638 +               .nops   = 3,
11639 +       };
11640 +       int replen, status;
11641 +
11642 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11643 +       encode_compound_hdr(&xdr, &hdr);
11644 +       status = encode_putfh(&xdr, args->fh);
11645 +       if (status)
11646 +               goto out;
11647 +       status = encode_read(&xdr, args);
11648 +       if (status)
11649 +               goto out;
11650 +       status = encode_read_getattr(&xdr);
11651 +
11652 +       /* set up reply iovec
11653 +        *    toplevel status + taglen=0 + rescount + OP_PUTFH + status
11654          *       + OP_READ + status + eof + datalen = 9
11655          */
11656         replen = (RPC_REPHDRSIZE + auth->au_rslack +
11657 @@ -1405,12 +1851,62 @@ nfs4_xdr_enc_setattr(struct rpc_rqst *re
11658          status = encode_setattr(&xdr, args, args->server);
11659          if(status)
11660                  goto out;
11661 -        status = encode_getattr(&xdr, args->attr);
11662 +        status = encode_getfattr(&xdr);
11663 +out:
11664 +        return status;
11665 +}
11666 +
11667 +#ifdef CONFIG_NFS_V4_ACL
11668 +
11669 +/*
11670 + * Encode an SETACL request
11671 + */
11672 +static int
11673 +nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args)
11674 +
11675 +{
11676 +        struct xdr_stream xdr;
11677 +        struct compound_hdr hdr = {
11678 +                .nops   = 2,
11679 +        };
11680 +        int status;
11681 +
11682 +        xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11683 +        encode_compound_hdr(&xdr, &hdr);
11684 +        status = encode_putfh(&xdr, args->fh);
11685 +        if(status)
11686 +                goto out;
11687 +        status = encode_setacl(&xdr, args);
11688  out:
11689          return status;
11690  }
11691  
11692  /*
11693 + * Encode a GETACL request
11694 + */
11695 +static int
11696 +nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p,struct nfs_fh *fhandle)
11697 +{
11698 +       struct xdr_stream xdr;
11699 +       struct compound_hdr hdr = {
11700 +               .nops   = 2,
11701 +       };
11702 +       int status;
11703 +
11704 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11705 +       encode_compound_hdr(&xdr, &hdr);
11706 +       status = encode_putfh(&xdr, fhandle);
11707 +       if (status)
11708 +               goto out;
11709 +       status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
11710 +out:
11711 +       return status;
11712 +
11713 +}
11714 +
11715 +#endif /* CONFIG_NFS_V4_ACL */
11716 +
11717 +/*
11718   * Encode a WRITE request
11719   */
11720  static int
11721 @@ -1487,6 +1983,48 @@ nfs4_xdr_enc_fsinfo(struct rpc_rqst *req
11722  }
11723  
11724  /*
11725 + * a PATHCONF request
11726 + */
11727 +static int
11728 +nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_fh *fhandle)
11729 +{
11730 +       struct xdr_stream xdr;
11731 +       struct compound_hdr hdr = {
11732 +               .nops   = 2,
11733 +       };
11734 +       int status;
11735 +
11736 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11737 +       encode_compound_hdr(&xdr, &hdr);
11738 +       status = encode_putfh(&xdr, fhandle);
11739 +       if (!status)
11740 +               status = encode_getattr_one(&xdr,FATTR4_WORD0_MAXLINK | 
11741 +                                                FATTR4_WORD0_MAXNAME );
11742 +       return status;
11743 +}
11744 +
11745 +/*
11746 + * a STATFS request
11747 + */
11748 +static int
11749 +nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fh *fhandle)
11750 +{
11751 +       struct xdr_stream xdr;
11752 +       struct compound_hdr hdr = {
11753 +               .nops   = 2,
11754 +       };
11755 +       int status;
11756 +
11757 +       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11758 +       encode_compound_hdr(&xdr, &hdr);
11759 +       status = encode_putfh(&xdr, fhandle);
11760 +       if (!status)
11761 +               status = encode_getattr_two(&xdr,nfs4_statfs_bitmap[0],
11762 +                                                nfs4_statfs_bitmap[1]);
11763 +       return status;
11764 +}
11765 +
11766 +/*
11767   * a RENEW request
11768   */
11769  static int
11770 @@ -1636,7 +2174,7 @@ decode_change_info(struct xdr_stream *xd
11771  }
11772  
11773  static int
11774 -decode_access(struct xdr_stream *xdr, struct nfs4_access *access)
11775 +decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
11776  {
11777         uint32_t *p;
11778         uint32_t supp, acc;
11779 @@ -1648,12 +2186,12 @@ decode_access(struct xdr_stream *xdr, st
11780         READ_BUF(8);
11781         READ32(supp);
11782         READ32(acc);
11783 -       if ((supp & ~access->ac_req_access) || (acc & ~supp)) {
11784 +       if ((supp & ~access->req_access) || (acc & ~supp)) {
11785                 printk(KERN_NOTICE "NFS: server returned bad bits in access call!\n");
11786                 return -EIO;
11787         }
11788 -       *access->ac_resp_supported = supp;
11789 -       *access->ac_resp_access = acc;
11790 +       *access->resp_supported = supp;
11791 +       *access->resp_access = acc;
11792         return 0;
11793  }
11794  
11795 @@ -1686,7 +2224,7 @@ decode_commit(struct xdr_stream *xdr, st
11796  }
11797  
11798  static int
11799 -decode_create(struct xdr_stream *xdr, struct nfs4_create *create)
11800 +decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
11801  {
11802         uint32_t *p;
11803         uint32_t bmlen;
11804 @@ -1695,7 +2233,7 @@ decode_create(struct xdr_stream *xdr, st
11805         status = decode_op_hdr(xdr, OP_CREATE);
11806         if (status)
11807                 return status;
11808 -       if ((status = decode_change_info(xdr, create->cr_cinfo)))
11809 +       if ((status = decode_change_info(xdr, cinfo)))
11810                 return status;
11811         READ_BUF(4);
11812         READ32(bmlen);
11813 @@ -1703,17 +2241,144 @@ decode_create(struct xdr_stream *xdr, st
11814         return 0;
11815  }
11816  
11817 -extern uint32_t nfs4_fattr_bitmap[2];
11818  extern uint32_t nfs4_fsstat_bitmap[2];
11819 -extern uint32_t nfs4_pathconf_bitmap[2];
11820  
11821  static int
11822 -decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr,
11823 +decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
11824 +{
11825 +       uint32_t attrlen, bmlen,
11826 +                bmval0 = 0,
11827 +                bmval1 = 0,
11828 +                len = 0;
11829 +       uint32_t *p;
11830 +       int status;
11831 +       
11832 +       status = decode_op_hdr(xdr, OP_GETATTR);
11833 +       if (status)
11834 +               return status;
11835 +        
11836 +        READ_BUF(4);
11837 +        READ32(bmlen);
11838 +        if (bmlen > 2)
11839 +                goto xdr_error;
11840 +       
11841 +        READ_BUF((bmlen << 2) + 4);
11842 +        if (bmlen > 0)
11843 +                READ32(bmval0);
11844 +        if (bmlen > 1)
11845 +                READ32(bmval1);
11846 +        READ32(attrlen);
11847 +
11848 +       if ((bmval0 & ~nfs4_statfs_bitmap[0]) ||
11849 +           (bmval1 & ~nfs4_statfs_bitmap[1])) {
11850 +               dprintk("read_attrs: server returned bad attributes!\n");
11851 +               goto xdr_error;
11852 +       }
11853 +
11854 +       if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
11855 +               READ_BUF(8);
11856 +               len += 8;
11857 +               READ64(fsstat->afiles);
11858 +               dprintk("read_attrs: files_avail=0x%Lx\n", (long long) fsstat->afiles);
11859 +       }
11860 +       if (bmval0 & FATTR4_WORD0_FILES_FREE) {
11861 +               READ_BUF(8);
11862 +               len += 8;
11863 +               READ64(fsstat->ffiles);
11864 +               dprintk("read_attrs: files_free=0x%Lx\n", (long long) fsstat->ffiles);
11865 +       }
11866 +       if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
11867 +               READ_BUF(8);
11868 +               len += 8;
11869 +               READ64(fsstat->tfiles);
11870 +               dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles);
11871 +       }
11872 +       
11873 +       if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
11874 +               READ_BUF(8);
11875 +               len += 8;
11876 +               READ64(fsstat->abytes);
11877 +               dprintk("read_attrs: savail=0x%Lx\n", (long long) fsstat->abytes);
11878 +       }
11879 +       if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
11880 +               READ_BUF(8);
11881 +               len += 8;
11882 +               READ64(fsstat->fbytes);
11883 +               dprintk("read_attrs: sfree=0x%Lx\n", (long long) fsstat->fbytes);
11884 +       }
11885 +       if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
11886 +               READ_BUF(8);
11887 +               len += 8;
11888 +               READ64(fsstat->tbytes);
11889 +               dprintk("read_attrs: stotal=0x%Lx\n", (long long) fsstat->tbytes);
11890 +       }
11891 +       if (len != attrlen)
11892 +               goto xdr_error;
11893 +       
11894 +       DECODE_TAIL;
11895 +}
11896 +
11897 +static int
11898 +decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
11899 +{
11900 +       uint32_t bmlen,
11901 +                attrlen = 0, 
11902 +                bmval0 = 0,
11903 +                bmval1 = 0,
11904 +                len = 0;
11905 +       uint32_t *p;
11906 +       int status;
11907 +       
11908 +       status = decode_op_hdr(xdr, OP_GETATTR);
11909 +       if (status)
11910 +               return status;
11911 +        
11912 +        READ_BUF(4);
11913 +        READ32(bmlen);
11914 +        if ( (bmlen < 1) || (bmlen >2) )
11915 +                goto xdr_error;
11916 +        READ_BUF((bmlen << 2) + 4);
11917 +       READ32(bmval0);
11918 +       if (bmval0 & ~(FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME)) {
11919 +               goto out_bad_bitmap;
11920 +       }
11921 +       if (bmlen == 2) {
11922 +               READ32(bmval1);
11923 +               if (bmval1 != 0)
11924 +                       goto out_bad_bitmap;
11925 +       }
11926 +
11927 +        READ32(attrlen);
11928 +       if (bmval0 & FATTR4_WORD0_MAXLINK) {
11929 +               READ_BUF(4);
11930 +               len += 4;
11931 +               READ32(pathconf->max_link);
11932 +               dprintk("read_attrs: maxlink=%d\n", pathconf->max_link);
11933 +       }
11934 +        if (bmval0 & FATTR4_WORD0_MAXNAME) {
11935 +                READ_BUF(4);
11936 +                len += 4;
11937 +                READ32(pathconf->max_namelen);
11938 +                dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen);
11939 +        }
11940 +       
11941 +        if (len != attrlen)
11942 +                goto xdr_error;
11943 +       return 0;
11944 +
11945 +out_bad_bitmap:
11946 +       printk(KERN_NOTICE "%s: server returned bad attribute bitmap\n",__FUNCTION__);
11947 +       return -EIO;
11948 +
11949 +xdr_error:
11950 +       printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__);
11951 +       return -EIO;
11952 +}
11953 +
11954 +static int
11955 +decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *nfp,
11956      struct nfs_server *server)
11957  {
11958 -       struct nfs_fattr *nfp = getattr->gt_attrs;
11959 -       struct nfs_fsstat *fsstat = getattr->gt_fsstat;
11960 -       struct nfs_pathconf *pathconf = getattr->gt_pathconf;
11961         uint32_t attrlen, dummy32, bmlen,
11962                  bmval0 = 0,
11963                  bmval1 = 0,
11964 @@ -1739,25 +2404,25 @@ decode_getattr(struct xdr_stream *xdr, s
11965                  READ32(bmval1);
11966          READ32(attrlen);
11967  
11968 -       if ((bmval0 & ~getattr->gt_bmval[0]) ||
11969 -           (bmval1 & ~getattr->gt_bmval[1])) {
11970 +       if ((bmval0 & ~nfs4_fattr_bitmap[0]) ||
11971 +           (bmval1 & ~nfs4_fattr_bitmap[1])) {
11972                 dprintk("read_attrs: server returned bad attributes!\n");
11973                 goto xdr_error;
11974         }
11975 -       if (nfp) {
11976 -               nfp->bitmap[0] = bmval0;
11977 -               nfp->bitmap[1] = bmval1;
11978 -       }
11979 +
11980 +       BUG_ON(!nfp);
11981 +
11982 +       nfp->bitmap[0] = bmval0;
11983 +       nfp->bitmap[1] = bmval1;
11984  
11985         /*
11986          * In case the server doesn't return some attributes,
11987          * we initialize them here to some nominal values..
11988          */
11989 -       if (nfp) {
11990 -               nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
11991 -               nfp->nlink = 1;
11992 -               nfp->timestamp = jiffies;
11993 -       }
11994 +       nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
11995 +       nfp->nlink = 1;
11996 +       nfp->timestamp = jiffies;
11997 +
11998          if (bmval0 & FATTR4_WORD0_TYPE) {
11999                  READ_BUF(4);
12000                  len += 4;
12001 @@ -1797,37 +2462,6 @@ decode_getattr(struct xdr_stream *xdr, s
12002                  READ64(nfp->fileid);
12003                  dprintk("read_attrs: fileid=%Ld\n", (long long) nfp->fileid);
12004          }
12005 -       if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
12006 -               READ_BUF(8);
12007 -               len += 8;
12008 -               READ64(fsstat->afiles);
12009 -               dprintk("read_attrs: files_avail=0x%Lx\n", (long long) fsstat->afiles);
12010 -       }
12011 -        if (bmval0 & FATTR4_WORD0_FILES_FREE) {
12012 -                READ_BUF(8);
12013 -                len += 8;
12014 -                READ64(fsstat->ffiles);
12015 -                dprintk("read_attrs: files_free=0x%Lx\n", (long long) fsstat->ffiles);
12016 -        }
12017 -        if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
12018 -                READ_BUF(8);
12019 -                len += 8;
12020 -                READ64(fsstat->tfiles);
12021 -                dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles);
12022 -        }
12023 -       if (bmval0 & FATTR4_WORD0_MAXLINK) {
12024 -               READ_BUF(4);
12025 -               len += 4;
12026 -               READ32(pathconf->max_link);
12027 -               dprintk("read_attrs: maxlink=%d\n", pathconf->max_link);
12028 -       }
12029 -        if (bmval0 & FATTR4_WORD0_MAXNAME) {
12030 -                READ_BUF(4);
12031 -                len += 4;
12032 -                READ32(pathconf->max_namelen);
12033 -                dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen);
12034 -        }
12035 -       
12036          if (bmval1 & FATTR4_WORD1_MODE) {
12037                  READ_BUF(4);
12038                  len += 4;
12039 @@ -1851,9 +2485,11 @@ decode_getattr(struct xdr_stream *xdr, s
12040                 }
12041                 READ_BUF(dummy32);
12042                 len += (XDR_QUADLEN(dummy32) << 2);
12043 -               if ((status = nfs_map_name_to_uid(server->nfs4_state, (char *)p, dummy32,
12044 -                                               &nfp->uid)) < 0) {
12045 -                       dprintk("read_attrs: name-to-uid mapping failed!\n");
12046 +               status = nfs_map_name_to_uid(server->nfs4_state, (char *)p,
12047 +                               dummy32, &nfp->uid);
12048 +               if (status) {
12049 +                       dprintk("read_attrs: nfs_map_name_to_uid failed!\n");
12050 +                       /* goto out; */
12051                         nfp->uid = -2;
12052                 }
12053                 dprintk("read_attrs: uid=%d\n", (int)nfp->uid);
12054 @@ -1868,10 +2504,12 @@ decode_getattr(struct xdr_stream *xdr, s
12055                 }
12056                 READ_BUF(dummy32);
12057                 len += (XDR_QUADLEN(dummy32) << 2);
12058 -               if ((status = nfs_map_group_to_gid(server->nfs4_state, (char *)p, dummy32,
12059 -                                               &nfp->gid)) < 0) {
12060 -                       dprintk("read_attrs: group-to-gid mapping failed!\n");
12061 +               status = nfs_map_group_to_gid(server->nfs4_state, (char *)p,
12062 +                               dummy32, &nfp->gid);
12063 +               if (status) {
12064 +                       dprintk("read_attrs: gss_get_num failed!\n");
12065                         nfp->gid = -2;
12066 +                       /* goto out; */
12067                 }
12068                 dprintk("read_attrs: gid=%d\n", (int)nfp->gid);
12069          }
12070 @@ -1882,28 +2520,10 @@ decode_getattr(struct xdr_stream *xdr, s
12071                 len += 8;
12072                 READ32(major);
12073                 READ32(minor);
12074 -               nfp->rdev = MKDEV(major, minor);
12075 -               if (MAJOR(nfp->rdev) != major || MINOR(nfp->rdev) != minor)
12076 -                       nfp->rdev = 0;
12077 -               dprintk("read_attrs: rdev=%u:%u\n", major, minor);
12078 -        }
12079 -        if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
12080 -                READ_BUF(8);
12081 -                len += 8;
12082 -                READ64(fsstat->abytes);
12083 -                dprintk("read_attrs: savail=0x%Lx\n", (long long) fsstat->abytes);
12084 -        }
12085 -       if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
12086 -                READ_BUF(8);
12087 -                len += 8;
12088 -                READ64(fsstat->fbytes);
12089 -                dprintk("read_attrs: sfree=0x%Lx\n", (long long) fsstat->fbytes);
12090 -        }
12091 -        if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
12092 -                READ_BUF(8);
12093 -                len += 8;
12094 -                READ64(fsstat->tbytes);
12095 -                dprintk("read_attrs: stotal=0x%Lx\n", (long long) fsstat->tbytes);
12096 +               nfp->rdev = MKDEV(major, minor);
12097 +               if (MAJOR(nfp->rdev) != major || MINOR(nfp->rdev) != minor)
12098 +                       nfp->rdev = 0;
12099 +               dprintk("read_attrs: rdev=%u:%u\n", major, minor);
12100          }
12101          if (bmval1 & FATTR4_WORD1_SPACE_USED) {
12102                  READ_BUF(8);
12103 @@ -1935,6 +2555,88 @@ decode_getattr(struct xdr_stream *xdr, s
12104          DECODE_TAIL;
12105  }
12106  
12107 +#ifdef CONFIG_NFS_V4_ACL
12108 +
12109 +static int
12110 +decode_getacl(struct xdr_stream *xdr, struct nfs4_acl **aclp)
12111 +{
12112 +       uint32_t attrlen, bmlen,
12113 +                bmval0 = 0,
12114 +                bmval1 = 0,
12115 +                len = 0;
12116 +       uint32_t *p;
12117 +       int status;
12118 +       
12119 +       status = decode_op_hdr(xdr, OP_GETATTR);
12120 +       if (status)
12121 +               return status;
12122 +        
12123 +        READ_BUF(4);
12124 +        READ32(bmlen);
12125 +        if (bmlen > 2)
12126 +                goto xdr_error;
12127 +       
12128 +        READ_BUF((bmlen << 2) + 4);
12129 +        if (bmlen > 0)
12130 +                READ32(bmval0);
12131 +        if (bmlen > 1)
12132 +                READ32(bmval1);
12133 +        READ32(attrlen);
12134 +
12135 +       if ((bmval0 & ~FATTR4_WORD0_ACL) || (bmval1)) {
12136 +               dprintk("read_attrs: server returned bad attributes!\n");
12137 +               goto xdr_error;
12138 +       }
12139 +       if (bmval0 & FATTR4_WORD0_ACL) {
12140 +               struct nfs4_acl *acl;
12141 +               struct nfs4_ace ace;
12142 +               int i;
12143 +               u_int nace;
12144 +
12145 +               if (aclp == NULL)
12146 +                       goto xdr_error; /* XXX MARIUS */
12147 +
12148 +               READ_BUF(4); len += 4;
12149 +               READ32(nace);
12150 +
12151 +               if (nace == 0) {
12152 +                       *aclp = NULL;
12153 +                       goto out_acl;
12154 +               }
12155 +
12156 +               acl = *aclp = nfs4_acl_new();
12157 +               if (acl == NULL) {
12158 +                       status = -ENOMEM;
12159 +                       goto out;
12160 +               }
12161 +
12162 +               for (i = 0; i < nace; i++) {
12163 +                       READ_BUF(16); len += 16;
12164 +                       READ32(ace.type);
12165 +                       READ32(ace.flag);
12166 +                       READ32(ace.access_mask);
12167 +                       ace.access_mask &= NFS4_ACE_MASK_ALL;
12168 +                       READ32(ace.wholen);
12169 +                       READ_BUF(ace.wholen);
12170 +                       len += XDR_QUADLEN(ace.wholen) << 2;
12171 +                       status = nfs4_acl_add_ace(acl, ace.type, ace.flag,
12172 +                           ace.access_mask, (char *)p, ace.wholen);
12173 +                       if (status < 0)
12174 +                               goto out;
12175 +                       p += XDR_QUADLEN(ace.wholen);
12176 +               }
12177 +       } else if (aclp != NULL)
12178 +               *aclp = NULL;
12179 +out_acl:
12180 +
12181 +        if (len != attrlen)
12182 +                goto xdr_error;
12183 +       
12184 +        DECODE_TAIL;
12185 +}
12186 +
12187 +#endif /* CONFIG_NFS_V4_ACL */
12188 +
12189  static int
12190  decode_change_attr(struct xdr_stream *xdr, uint64_t *change_attr)
12191  {
12192 @@ -2067,6 +2769,77 @@ out_bad_bitmap:
12193         return -EIO;
12194  }
12195  
12196 +static int
12197 +decode_putfh(struct xdr_stream *xdr)
12198 +{
12199 +       return decode_op_hdr(xdr, OP_PUTFH);
12200 +}
12201 +
12202 +static int
12203 +decode_setattr(struct xdr_stream *xdr)
12204 +{
12205 +       uint32_t *p;
12206 +       uint32_t bmlen;
12207 +       int status;
12208 +
12209 +        
12210 +       status = decode_op_hdr(xdr, OP_SETATTR);
12211 +       if (status)
12212 +               return status;
12213 +       READ_BUF(4);
12214 +       READ32(bmlen);
12215 +       READ_BUF(bmlen << 2);
12216 +       return 0;
12217 +}
12218 +
12219 +#ifdef CONFIG_NFS_V4_ACL
12220 +
12221 +/*
12222 + * Decode SETACL response
12223 + */
12224 +static int
12225 +nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res)
12226 +{
12227 +       struct xdr_stream xdr;
12228 +       struct compound_hdr hdr;
12229 +       int status;
12230 +
12231 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12232 +       status = decode_compound_hdr(&xdr, &hdr);
12233 +       if (status)
12234 +               goto out;
12235 +       status = decode_putfh(&xdr);
12236 +       if (status)
12237 +               goto out;
12238 +       status = decode_setattr(&xdr);
12239 +out:
12240 +       return status;
12241 +}
12242 +
12243 +/*
12244 + * Decode GETACL response
12245 + */
12246 +static int
12247 +nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_acl **res)
12248 +{
12249 +       struct xdr_stream xdr;
12250 +       struct compound_hdr hdr;
12251 +       int status;
12252 +       
12253 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12254 +       status = decode_compound_hdr(&xdr, &hdr);
12255 +       if (status)
12256 +               goto out;
12257 +       status = decode_putfh(&xdr);
12258 +       if (status)
12259 +               goto out;
12260 +       status = decode_getacl(&xdr, res);
12261 +
12262 +out:
12263 +       return status;
12264 +}
12265 +
12266 +#endif /* CONFIG_NFS_V4_ACL */
12267  
12268  static int
12269  decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
12270 @@ -2137,9 +2910,8 @@ out_bad_bitmap:
12271  }
12272  
12273  static int
12274 -decode_getfh(struct xdr_stream *xdr, struct nfs4_getfh *getfh)
12275 +decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
12276  {
12277 -       struct nfs_fh *fh = getfh->gf_fhandle;
12278         uint32_t *p;
12279         uint32_t len;
12280         int status;
12281 @@ -2161,14 +2933,14 @@ decode_getfh(struct xdr_stream *xdr, str
12282  }
12283  
12284  static int
12285 -decode_link(struct xdr_stream *xdr, struct nfs4_link *link)
12286 +decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
12287  {
12288         int status;
12289         
12290         status = decode_op_hdr(xdr, OP_LINK);
12291         if (status)
12292                 return status;
12293 -       return decode_change_info(xdr, link->ln_cinfo);
12294 +       return decode_change_info(xdr, cinfo);
12295  }
12296  
12297  /*
12298 @@ -2296,12 +3068,6 @@ decode_open_downgrade(struct xdr_stream 
12299  }
12300  
12301  static int
12302 -decode_putfh(struct xdr_stream *xdr)
12303 -{
12304 -       return decode_op_hdr(xdr, OP_PUTFH);
12305 -}
12306 -
12307 -static int
12308  decode_putrootfh(struct xdr_stream *xdr)
12309  {
12310         return decode_op_hdr(xdr, OP_PUTROOTFH);
12311 @@ -2336,7 +3102,7 @@ decode_read(struct xdr_stream *xdr, stru
12312  }
12313  
12314  static int
12315 -decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir *readdir)
12316 +decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
12317  {
12318         struct xdr_buf  *rcvbuf = &req->rq_rcv_buf;
12319         struct page     *page = *rcvbuf->pages;
12320 @@ -2350,7 +3116,7 @@ decode_readdir(struct xdr_stream *xdr, s
12321         if (status)
12322                 return status;
12323         READ_BUF(8);
12324 -       COPYMEM(readdir->rd_resp_verifier.data, 8);
12325 +       COPYMEM(readdir->resp_verifier.data, 8);
12326  
12327         hdrlen = (char *) p - (char *) iov->iov_base;
12328         recvd = req->rq_received - hdrlen;
12329 @@ -2358,9 +3124,9 @@ decode_readdir(struct xdr_stream *xdr, s
12330                 pglen = recvd;
12331         xdr_read_pages(xdr, pglen);
12332  
12333 -       BUG_ON(pglen + readdir->rd_pgbase > PAGE_CACHE_SIZE);
12334 +       BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
12335         kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
12336 -       end = (uint32_t *) ((char *)p + pglen + readdir->rd_pgbase);
12337 +       end = (uint32_t *) ((char *)p + pglen + readdir->pgbase);
12338         entry = p;
12339         for (nr = 0; *p++; nr++) {
12340                 if (p + 3 > end)
12341 @@ -2421,7 +3187,7 @@ err_unmap:
12342  }
12343  
12344  static int
12345 -decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readlink *readlink)
12346 +decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
12347  {
12348         struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
12349         struct iovec *iov = rcvbuf->head;
12350 @@ -2469,30 +3235,30 @@ decode_restorefh(struct xdr_stream *xdr)
12351  }
12352  
12353  static int
12354 -decode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove)
12355 +decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
12356  {
12357         int status;
12358  
12359         status = decode_op_hdr(xdr, OP_REMOVE);
12360         if (status)
12361                 goto out;
12362 -       status = decode_change_info(xdr, remove->rm_cinfo);
12363 +       status = decode_change_info(xdr, cinfo);
12364  out:
12365         return status;
12366  }
12367  
12368  static int
12369 -decode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename)
12370 +decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
12371 +             struct nfs4_change_info *new_cinfo)
12372  {
12373         int status;
12374  
12375         status = decode_op_hdr(xdr, OP_RENAME);
12376         if (status)
12377                 goto out;
12378 -       if ((status = decode_change_info(xdr, rename->rn_src_cinfo)))
12379 -               goto out;
12380 -       if ((status = decode_change_info(xdr, rename->rn_dst_cinfo)))
12381 +       if ((status = decode_change_info(xdr, old_cinfo)))
12382                 goto out;
12383 +       status = decode_change_info(xdr, new_cinfo);
12384  out:
12385         return status;
12386  }
12387 @@ -2510,23 +3276,6 @@ decode_savefh(struct xdr_stream *xdr)
12388  }
12389  
12390  static int
12391 -decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
12392 -{
12393 -       uint32_t *p;
12394 -       uint32_t bmlen;
12395 -       int status;
12396 -
12397 -        
12398 -       status = decode_op_hdr(xdr, OP_SETATTR);
12399 -       if (status)
12400 -               return status;
12401 -       READ_BUF(4);
12402 -       READ32(bmlen);
12403 -       READ_BUF(bmlen << 2);
12404 -       return 0;
12405 -}
12406 -
12407 -static int
12408  decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
12409  {
12410         uint32_t *p;
12411 @@ -2566,158 +3315,348 @@ decode_setclientid(struct xdr_stream *xd
12412  }
12413  
12414  static int
12415 -decode_setclientid_confirm(struct xdr_stream *xdr)
12416 +decode_setclientid_confirm(struct xdr_stream *xdr)
12417 +{
12418 +       return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
12419 +}
12420 +
12421 +static int
12422 +decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
12423 +{
12424 +       uint32_t *p;
12425 +       int status;
12426 +
12427 +       status = decode_op_hdr(xdr, OP_WRITE);
12428 +       if (status)
12429 +               return status;
12430 +
12431 +       READ_BUF(16);
12432 +       READ32(res->count);
12433 +       READ32(res->verf->committed);
12434 +       COPYMEM(res->verf->verifier, 8);
12435 +       return 0;
12436 +}
12437 +
12438 +/*
12439 + * Decode OPEN_DOWNGRADE response
12440 + */
12441 +static int
12442 +nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
12443 +{
12444 +        struct xdr_stream xdr;
12445 +        struct compound_hdr hdr;
12446 +        int status;
12447 +
12448 +        xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12449 +        status = decode_compound_hdr(&xdr, &hdr);
12450 +        if (status)
12451 +                goto out;
12452 +        status = decode_putfh(&xdr);
12453 +        if (status)
12454 +                goto out;
12455 +        status = decode_open_downgrade(&xdr, res);
12456 +out:
12457 +        return status;
12458 +}
12459 +
12460 +/*
12461 + * END OF "GENERIC" DECODE ROUTINES.
12462 + */
12463 +
12464 +/*
12465 + * Decode ACCESS response
12466 + */
12467 +static int
12468 +nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res)
12469 +{
12470 +       struct xdr_stream xdr;
12471 +       struct compound_hdr hdr;
12472 +       int status;
12473 +       
12474 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12475 +       status = decode_compound_hdr(&xdr, &hdr);
12476 +       if (status)
12477 +               goto out;
12478 +       status = decode_putfh(&xdr);
12479 +       if (status)
12480 +               goto out;
12481 +       status = decode_getfattr(&xdr, res->fattr, res->server);
12482 +       if (status)
12483 +               goto out;
12484 +       status = decode_access(&xdr, res);
12485 +out:
12486 +       return status;
12487 +}
12488 +
12489 +/*
12490 + * Decode LOOKUP response
12491 + */
12492 +static int
12493 +nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookupres *res)
12494 +{
12495 +       struct xdr_stream xdr;
12496 +       struct compound_hdr hdr;
12497 +       int status;
12498 +       
12499 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12500 +       status = decode_compound_hdr(&xdr, &hdr);
12501 +       if (status)
12502 +               goto out;
12503 +       status = decode_putfh(&xdr);
12504 +       if (status)
12505 +               goto out;
12506 +       status = decode_getfattr(&xdr, res->dirattr, res->server);
12507 +       if (status)
12508 +               goto out;
12509 +       status = decode_lookup(&xdr);
12510 +       if (status)
12511 +               goto out;
12512 +       status = decode_getfattr(&xdr, res->fattr, res->server);
12513 +       if (status)
12514 +               goto out;
12515 +       status = decode_getfh(&xdr, res->fhandle);
12516 +out:
12517 +       return status;
12518 +}
12519 +
12520 +/*
12521 + * Decode GETROOT_HEAD response
12522 + */
12523 +static int
12524 +nfs4_xdr_dec_getroot_head(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getroot_res *res)
12525 +{
12526 +       struct xdr_stream xdr;
12527 +       struct compound_hdr hdr;
12528 +       int status;
12529 +       
12530 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12531 +       status = decode_compound_hdr(&xdr, &hdr);
12532 +       if (status)
12533 +               goto out;
12534 +       status = decode_putrootfh(&xdr);
12535 +       if (status)
12536 +               goto out;
12537 +       status = decode_getfattr(&xdr, res->fattr, res->server);
12538 +       if (status)
12539 +               goto out;
12540 +       status = decode_getfh(&xdr, res->fhandle);
12541 +out:
12542 +       return status;
12543 +}
12544 +
12545 +/*
12546 + * Decode GETROOT_PATH response
12547 + */
12548 +static int
12549 +nfs4_xdr_dec_getroot_path(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getroot_res *res)
12550 +{
12551 +       struct xdr_stream xdr;
12552 +       struct compound_hdr hdr;
12553 +       int status;
12554 +       
12555 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12556 +       status = decode_compound_hdr(&xdr, &hdr);
12557 +       if (status)
12558 +               goto out;
12559 +       status = decode_putfh(&xdr);
12560 +       if (status)
12561 +               goto out;
12562 +       status = decode_lookup(&xdr);
12563 +       if (status)
12564 +               goto out;
12565 +       status = decode_getfattr(&xdr, res->fattr, res->server);
12566 +       if (status)
12567 +               goto out;
12568 +       status = decode_getfh(&xdr, res->fhandle);
12569 +out:
12570 +       return status;
12571 +}
12572 +
12573 +/*
12574 + * Decode REMOVE response
12575 + */
12576 +static int
12577 +nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_remove_res *res)
12578  {
12579 -       return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
12580 +       struct xdr_stream xdr;
12581 +       struct compound_hdr hdr;
12582 +       int status;
12583 +       
12584 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12585 +       status = decode_compound_hdr(&xdr, &hdr);
12586 +       if (status)
12587 +               goto out;
12588 +       status = decode_putfh(&xdr);
12589 +       if (status)
12590 +               goto out;
12591 +       status = decode_remove(&xdr, res->dir_cinfo);
12592 +       if (status)
12593 +               goto out;
12594 +       status = decode_getfattr(&xdr, res->dir_attr, res->server);
12595 +out:
12596 +       return status;
12597  }
12598  
12599 +/*
12600 + * Decode UNLINK response
12601 + */
12602  static int
12603 -decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
12604 +nfs4_xdr_dec_unlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_unlink *res)
12605  {
12606 -       uint32_t *p;
12607 +       struct xdr_stream xdr;
12608 +       struct compound_hdr hdr;
12609         int status;
12610 -
12611 -       status = decode_op_hdr(xdr, OP_WRITE);
12612 +       
12613 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12614 +       status = decode_compound_hdr(&xdr, &hdr);
12615         if (status)
12616 -               return status;
12617 -
12618 -       READ_BUF(16);
12619 -       READ32(res->count);
12620 -       READ32(res->verf->committed);
12621 -       COPYMEM(res->verf->verifier, 8);
12622 -       return 0;
12623 +               goto out;
12624 +       status = decode_putfh(&xdr);
12625 +       if (status)
12626 +               goto out;
12627 +       status = decode_remove(&xdr, &res->cinfo);
12628 +       if (status)
12629 +               goto out;
12630 +       status = decode_getfattr(&xdr, &res->attrs, res->server);
12631 +out:
12632 +       return status;
12633  }
12634  
12635 -/* FIXME: this sucks */
12636 +/*
12637 + * Decode RENAME response
12638 + */
12639  static int
12640 -decode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req)
12641 +nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_rename_res *res)
12642  {
12643 +       struct xdr_stream xdr;
12644         struct compound_hdr hdr;
12645 -       struct nfs4_op *op;
12646         int status;
12647 -
12648 -       status = decode_compound_hdr(xdr, &hdr);
12649 +       
12650 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12651 +       status = decode_compound_hdr(&xdr, &hdr);
12652         if (status)
12653                 goto out;
12654 -
12655 -       cp->toplevel_status = hdr.status;
12656 -
12657 -       /*
12658 -        * We need this if our zero-copy I/O is going to work.  Rumor has
12659 -        * it that the spec will soon mandate it...
12660 -        */
12661 -       if (hdr.taglen != cp->taglen)
12662 -               dprintk("nfs4: non-conforming server returns tag length mismatch!\n");
12663 -
12664 -       cp->resp_nops = hdr.nops;
12665 -       if (hdr.nops > cp->req_nops) {
12666 -               dprintk("nfs4: resp_nops > req_nops!\n");
12667 -               goto xdr_error;
12668 -       }
12669 -
12670 -       op = &cp->ops[0];
12671 -       for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++, op++) {
12672 -               switch (op->opnum) {
12673 -               case OP_ACCESS:
12674 -                       status = decode_access(xdr, &op->u.access);
12675 -                       break;
12676 -               case OP_CREATE:
12677 -                       status = decode_create(xdr, &op->u.create);
12678 -                       break;
12679 -               case OP_GETATTR:
12680 -                       status = decode_getattr(xdr, &op->u.getattr, cp->server);
12681 -                       break;
12682 -               case OP_GETFH:
12683 -                       status = decode_getfh(xdr, &op->u.getfh);
12684 -                       break;
12685 -               case OP_LINK:
12686 -                       status = decode_link(xdr, &op->u.link);
12687 -                       break;
12688 -               case OP_LOOKUP:
12689 -                       status = decode_lookup(xdr);
12690 -                       break;
12691 -               case OP_PUTFH:
12692 -                       status = decode_putfh(xdr);
12693 -                       break;
12694 -               case OP_PUTROOTFH:
12695 -                       status = decode_putrootfh(xdr);
12696 -                       break;
12697 -               case OP_READDIR:
12698 -                       status = decode_readdir(xdr, req, &op->u.readdir);
12699 -                       break;
12700 -               case OP_READLINK:
12701 -                       status = decode_readlink(xdr, req, &op->u.readlink);
12702 -                       break;
12703 -               case OP_RESTOREFH:
12704 -                       status = decode_restorefh(xdr);
12705 -                       break;
12706 -               case OP_REMOVE:
12707 -                       status = decode_remove(xdr, &op->u.remove);
12708 -                       break;
12709 -               case OP_RENAME:
12710 -                       status = decode_rename(xdr, &op->u.rename);
12711 -                       break;
12712 -               case OP_SAVEFH:
12713 -                       status = decode_savefh(xdr);
12714 -                       break;
12715 -               default:
12716 -                       BUG();
12717 -                       return -EIO;
12718 -               }
12719 -               if (status)
12720 -                       break;
12721 -       }
12722 -
12723 -       DECODE_TAIL;
12724 +       status = decode_putfh(&xdr);
12725 +       if (status)
12726 +               goto out;
12727 +       status = decode_savefh(&xdr);
12728 +       if (status)
12729 +               goto out;
12730 +       status = decode_putfh(&xdr);
12731 +       if (status)
12732 +               goto out;
12733 +       status = decode_rename(&xdr, res->old_cinfo, res->new_cinfo);
12734 +       if (status)
12735 +               goto out;
12736 +       status = decode_getfattr(&xdr, res->new_fattr, res->server);
12737 +       if (status)
12738 +               goto out;
12739 +       status = decode_restorefh(&xdr);
12740 +       if (status)
12741 +               goto out;
12742 +       status = decode_getfattr(&xdr, res->old_fattr, res->server);
12743 +out:
12744 +       return status;
12745  }
12746  
12747  /*
12748 - * Decode OPEN_DOWNGRADE response
12749 + * Decode LINK response
12750   */
12751  static int
12752 -nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
12753 +nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_link_res *res)
12754  {
12755 -        struct xdr_stream xdr;
12756 -        struct compound_hdr hdr;
12757 -        int status;
12758 -
12759 -        xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12760 -        status = decode_compound_hdr(&xdr, &hdr);
12761 -        if (status)
12762 -                goto out;
12763 -        status = decode_putfh(&xdr);
12764 -        if (status)
12765 -                goto out;
12766 -        status = decode_open_downgrade(&xdr, res);
12767 +       struct xdr_stream xdr;
12768 +       struct compound_hdr hdr;
12769 +       int status;
12770 +       
12771 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12772 +       status = decode_compound_hdr(&xdr, &hdr);
12773 +       if (status)
12774 +               goto out;
12775 +       status = decode_putfh(&xdr);
12776 +       if (status)
12777 +               goto out;
12778 +       status = decode_savefh(&xdr);
12779 +       if (status)
12780 +               goto out;
12781 +       status = decode_putfh(&xdr);
12782 +       if (status)
12783 +               goto out;
12784 +       status = decode_link(&xdr, res->dir_cinfo);
12785 +       if (status)
12786 +               goto out;
12787 +       status = decode_getfattr(&xdr, res->dir_attr, res->server);
12788 +       if (status)
12789 +               goto out;
12790 +       status = decode_restorefh(&xdr);
12791 +       if (status)
12792 +               goto out;
12793 +       status = decode_getfattr(&xdr, res->fattr, res->server);
12794  out:
12795 -        return status;
12796 +       return status;
12797  }
12798  
12799  /*
12800 - * END OF "GENERIC" DECODE ROUTINES.
12801 + * Decode CREATE response
12802   */
12803 +static int
12804 +nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
12805 +{
12806 +       struct xdr_stream xdr;
12807 +       struct compound_hdr hdr;
12808 +       int status;
12809 +       
12810 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12811 +       status = decode_compound_hdr(&xdr, &hdr);
12812 +       if (status)
12813 +               goto out;
12814 +       status = decode_putfh(&xdr);
12815 +       if (status)
12816 +               goto out;
12817 +       status = decode_savefh(&xdr);
12818 +       if (status)
12819 +               goto out;
12820 +       status = decode_create(&xdr,res->dir_cinfo);
12821 +       if (status)
12822 +               goto out;
12823 +       status = decode_getfattr(&xdr, res->fattr, res->server);
12824 +       if (status)
12825 +               goto out;
12826 +       status = decode_getfh(&xdr, res->fhandle);
12827 +       if (status)
12828 +               goto out;
12829 +       status = decode_restorefh(&xdr);
12830 +       if (status)
12831 +               goto out;
12832 +       status = decode_getfattr(&xdr, res->dir_attr, res->server);
12833 +out:
12834 +       return status;
12835 +}
12836  
12837  /*
12838 - * Decode COMPOUND response
12839 + * Decode GETATTR response
12840   */
12841  static int
12842 -nfs4_xdr_dec_compound(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_compound *cp)
12843 +nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res)
12844  {
12845         struct xdr_stream xdr;
12846 +       struct compound_hdr hdr;
12847         int status;
12848         
12849         xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12850 -       if ((status = decode_compound(&xdr, cp, rqstp)))
12851 +       status = decode_compound_hdr(&xdr, &hdr);
12852 +       if (status)
12853                 goto out;
12854 -       
12855 -       status = 0;
12856 -       if (cp->toplevel_status)
12857 -               status = -nfs_stat_to_errno(cp->toplevel_status);
12858 -
12859 +       status = decode_putfh(&xdr);
12860 +       if (status)
12861 +               goto out;
12862 +       status = decode_getfattr(&xdr, res->fattr, res->server);
12863  out:
12864         return status;
12865 +
12866  }
12867  
12868 +
12869  /*
12870   * Decode CLOSE response
12871   */
12872 @@ -2748,9 +3687,6 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp
12873  {
12874          struct xdr_stream xdr;
12875          struct compound_hdr hdr;
12876 -       struct nfs4_getfh gfh   = {
12877 -               .gf_fhandle = &res->fh,
12878 -       };
12879          int status;
12880  
12881          xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12882 @@ -2766,16 +3702,16 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp
12883          status = decode_open(&xdr, res);
12884          if (status)
12885                  goto out;
12886 -        status = decode_getattr(&xdr, res->f_getattr, res->server);
12887 +        status = decode_getfattr(&xdr, res->f_attr, res->server);
12888          if (status)
12889                  goto out;
12890 -        status = decode_getfh(&xdr, &gfh);
12891 +        status = decode_getfh(&xdr, &res->fh);
12892          if (status)
12893                  goto out;
12894          status = decode_restorefh(&xdr);
12895          if (status)
12896                  goto out;
12897 -        status = decode_getattr(&xdr, res->d_getattr, res->server);
12898 +        status = decode_getfattr(&xdr, res->d_attr, res->server);
12899          if (status)
12900                  goto out;
12901  out:
12902 @@ -2824,7 +3760,7 @@ nfs4_xdr_dec_open_reclaim(struct rpc_rqs
12903          status = decode_open(&xdr, res);
12904          if (status)
12905                  goto out;
12906 -        status = decode_getattr(&xdr, res->f_getattr, res->server);
12907 +        status = decode_getfattr(&xdr, res->f_attr, res->server);
12908  out:
12909          return status;
12910  }
12911 @@ -2846,10 +3782,10 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rq
12912          status = decode_putfh(&xdr);
12913          if (status)
12914                  goto out;
12915 -        status = decode_setattr(&xdr, res);
12916 +        status = decode_setattr(&xdr);
12917          if (status)
12918                  goto out;
12919 -        status = decode_getattr(&xdr, res->attr, res->server);
12920 +        status = decode_getfattr(&xdr, res->fattr, res->server);
12921  out:
12922          return status;
12923  }
12924 @@ -2921,6 +3857,50 @@ out:
12925  }
12926  
12927  /*
12928 + * Decode READLINK response
12929 + */
12930 +static int
12931 +nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res)
12932 +{
12933 +       struct xdr_stream xdr;
12934 +       struct compound_hdr hdr;
12935 +       int status;
12936 +
12937 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12938 +       status = decode_compound_hdr(&xdr, &hdr);
12939 +       if (status)
12940 +               goto out;
12941 +       status = decode_putfh(&xdr);
12942 +       if (status)
12943 +               goto out;
12944 +       status = decode_readlink(&xdr, rqstp);
12945 +out:
12946 +       return status;
12947 +}
12948 +
12949 +/*
12950 + * Decode READDIR response
12951 + */
12952 +static int
12953 +nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res)
12954 +{
12955 +       struct xdr_stream xdr;
12956 +       struct compound_hdr hdr;
12957 +       int status;
12958 +
12959 +       xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12960 +       status = decode_compound_hdr(&xdr, &hdr);
12961 +       if (status)
12962 +               goto out;
12963 +       status = decode_putfh(&xdr);
12964 +       if (status)
12965 +               goto out;
12966 +       status = decode_readdir(&xdr, rqstp, res);
12967 +out:
12968 +       return status;
12969 +}
12970 +
12971 +/*
12972   * Decode Read response
12973   */
12974  static int
12975 @@ -3033,6 +4013,44 @@ nfs4_xdr_dec_fsinfo(struct rpc_rqst *req
12976  }
12977  
12978  /*
12979 + * PATHCONF request
12980 + */
12981 +static int
12982 +nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf)
12983 +{
12984 +       struct xdr_stream xdr;
12985 +       struct compound_hdr hdr;
12986 +       int status;
12987 +
12988 +       xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
12989 +       status = decode_compound_hdr(&xdr, &hdr);
12990 +       if (!status)
12991 +               status = decode_putfh(&xdr);
12992 +       if (!status)
12993 +               status = decode_pathconf(&xdr, pathconf);
12994 +       return status;
12995 +}
12996 +
12997 +/*
12998 + * STATFS request
12999 + */
13000 +static int
13001 +nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat)
13002 +{
13003 +       struct xdr_stream xdr;
13004 +       struct compound_hdr hdr;
13005 +       int status;
13006 +
13007 +       xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
13008 +       status = decode_compound_hdr(&xdr, &hdr);
13009 +       if (!status)
13010 +               status = decode_putfh(&xdr);
13011 +       if (!status)
13012 +               status = decode_statfs(&xdr, fsstat);
13013 +       return status;
13014 +}
13015 +
13016 +/*
13017   * Decode RENEW response
13018   */
13019  static int
13020 @@ -3201,7 +4219,6 @@ nfs_stat_to_errno(int stat)
13021      }
13022  
13023  struct rpc_procinfo    nfs4_procedures[] = {
13024 -  PROC(COMPOUND,       enc_compound,   dec_compound),
13025    PROC(READ,           enc_read,       dec_read),
13026    PROC(WRITE,          enc_write,      dec_write),
13027    PROC(COMMIT,         enc_commit,     dec_commit),
13028 @@ -3218,6 +4235,24 @@ struct rpc_procinfo      nfs4_procedures[] = 
13029    PROC(LOCK,            enc_lock,       dec_lock),
13030    PROC(LOCKT,           enc_lockt,      dec_lockt),
13031    PROC(LOCKU,           enc_locku,      dec_locku),
13032 +#ifdef CONFIG_NFS_V4_ACL
13033 +  PROC(GETACL,          enc_getacl,     dec_getacl),
13034 +  PROC(SETACL,          enc_setacl,     dec_setacl),
13035 +#endif /* CONFIG_NFS_V4_ACL */
13036 +  PROC(ACCESS,         enc_access,     dec_access),
13037 +  PROC(GETATTR,                enc_getattr,    dec_getattr),
13038 +  PROC(LOOKUP,         enc_lookup,     dec_lookup),
13039 +  PROC(GETROOT_HEAD,   enc_getroot_head,       dec_getroot_head),
13040 +  PROC(GETROOT_PATH,   enc_getroot_path,       dec_getroot_path),
13041 +  PROC(REMOVE,         enc_remove,     dec_remove),
13042 +  PROC(RENAME,         enc_rename,     dec_rename),
13043 +  PROC(LINK,           enc_link,       dec_link),
13044 +  PROC(CREATE,         enc_create,     dec_create),
13045 +  PROC(PATHCONF,       enc_pathconf,   dec_pathconf),
13046 +  PROC(STATFS,         enc_statfs,     dec_statfs),
13047 +  PROC(UNLINK,         enc_unlink,     dec_unlink),
13048 +  PROC(READLINK,       enc_readlink,   dec_readlink),
13049 +  PROC(READDIR,                enc_readdir,    dec_readdir),
13050  };
13051  
13052  struct rpc_version             nfs_version4 = {
13053 diff -puN fs/nfsd/vfs.c~CITI_NFS4_ALL fs/nfsd/vfs.c
13054 --- linux-2.6.3/fs/nfsd/vfs.c~CITI_NFS4_ALL     2004-02-19 16:47:07.000000000 -0500
13055 +++ linux-2.6.3-bfields/fs/nfsd/vfs.c   2004-02-19 16:47:12.000000000 -0500
13056 @@ -44,6 +44,16 @@
13057  #include <linux/nfsd/nfsfh.h>
13058  #include <linux/quotaops.h>
13059  #include <linux/dnotify.h>
13060 +#ifdef CONFIG_NFSD_V4
13061 +#include <linux/posix_acl.h>
13062 +#include <linux/posix_acl_xattr.h>
13063 +#include <linux/xattr_acl.h>
13064 +#include <linux/xattr.h>
13065 +#include <linux/nfs4.h>
13066 +#include <linux/nfs4_acl.h>
13067 +#include <linux/nfsd_idmap.h>
13068 +#include <linux/security.h>
13069 +#endif /* CONFIG_NFSD_V4 */
13070  
13071  #include <asm/uaccess.h>
13072  
13073 @@ -341,6 +351,204 @@ out_nfserr:
13074         goto out;
13075  }
13076  
13077 +#ifdef CONFIG_NFS_V4_ACL
13078 +
13079 +static int
13080 +set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
13081 +{
13082 +       int len;
13083 +       size_t buflen;
13084 +       char *buf = NULL;
13085 +       int error = 0;
13086 +       struct inode *inode = dentry->d_inode;
13087 +
13088 +       buflen = posix_acl_xattr_size(pacl->a_count);
13089 +       buf = kmalloc(buflen, GFP_KERNEL);
13090 +       error = -ENOMEM;
13091 +       if (buf == NULL)
13092 +               goto out;
13093 +
13094 +       len = posix_acl_to_xattr(pacl, buf, buflen);
13095 +       if (len < 0) {
13096 +               error = len;
13097 +               goto out;
13098 +       }
13099 +
13100 +       error = -EOPNOTSUPP;
13101 +       if (inode->i_op && inode->i_op->setxattr) {
13102 +               down(&inode->i_sem);
13103 +               security_inode_setxattr(dentry, key, buf, len, 0);
13104 +               error = inode->i_op->setxattr(dentry, key, buf, len, 0);
13105 +               if (!error)
13106 +                       security_inode_post_setxattr(dentry, key, buf, len, 0);
13107 +               up(&inode->i_sem);
13108 +       }
13109 +out:
13110 +       kfree(buf);
13111 +       return (error);
13112 +}
13113 +
13114 +static inline int
13115 +nfsd_name_to_uid_wrapper(void *arg, const char *name, size_t len, __u32 *id)
13116 +{
13117 +               return nfsd_map_name_to_uid((struct svc_rqst *)arg, name, len, id);
13118 +}
13119 +
13120 +static inline int
13121 +nfsd_name_to_gid_wrapper(void *arg, const char *name, size_t len, __u32 *id)
13122 +{
13123 +               return nfsd_map_name_to_gid((struct svc_rqst *)arg, name, len, id);
13124 +}
13125 +
13126 +static inline int
13127 +nfsd_uid_to_name_wrapper(void *arg, __u32 id, char *name)
13128 +{
13129 +               return nfsd_map_uid_to_name((struct svc_rqst *)arg, id, name);
13130 +}
13131 +
13132 +static inline int
13133 +nfsd_gid_to_name_wrapper(void *arg, __u32 id, char *name)
13134 +{
13135 +               return nfsd_map_gid_to_name((struct svc_rqst *)arg, id, name);
13136 +}
13137 +
13138 +static struct nfs4_acl_idmapper nfsd_idmapper = {
13139 +       .name2uid = nfsd_name_to_uid_wrapper,
13140 +       .name2gid = nfsd_name_to_gid_wrapper,
13141 +       .uid2name = nfsd_uid_to_name_wrapper,
13142 +       .gid2name = nfsd_gid_to_name_wrapper,
13143 +};
13144 +
13145 +
13146 +int
13147 +nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
13148 +    struct nfs4_acl *acl)
13149 +{
13150 +       int error;
13151 +       struct dentry *dentry;
13152 +       struct inode *inode;
13153 +       struct posix_acl *pacl = NULL, *dpacl = NULL;
13154 +
13155 +       /* Get inode */
13156 +       error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
13157 +       if (error)
13158 +               goto out;
13159 +
13160 +       dentry = fhp->fh_dentry;
13161 +       inode = dentry->d_inode;
13162 +
13163 +       error = nfs4_acl_nfsv4_to_posix(&nfsd_idmapper, rqstp, acl, &pacl, &dpacl);
13164 +       if (error < 0)
13165 +               goto out_nfserr;
13166 +
13167 +       if (pacl) {
13168 +               error = set_nfsv4_acl_one(dentry, pacl, XATTR_NAME_ACL_ACCESS);
13169 +               if (error < 0)
13170 +                       goto out_nfserr;
13171 +       }
13172 +
13173 +       if (dpacl) {
13174 +               error = set_nfsv4_acl_one(dentry, dpacl, XATTR_NAME_ACL_DEFAULT);
13175 +               if (error < 0)
13176 +                       goto out_nfserr;
13177 +       }
13178 +
13179 +       error = nfs_ok;
13180 +
13181 +out:
13182 +       posix_acl_release(pacl);
13183 +       posix_acl_release(dpacl);
13184 +       return (error);
13185 +out_nfserr:
13186 +       error = nfserrno(error);
13187 +       goto out;
13188 +}
13189 +
13190 +static struct posix_acl *
13191 +_get_posix_acl(struct dentry *dentry, char *key)
13192 +{
13193 +       struct inode *inode = dentry->d_inode;
13194 +       char *buf = NULL;
13195 +       int buflen, error = 0;
13196 +       struct posix_acl *pacl = NULL;
13197 +
13198 +       down(&inode->i_sem);
13199 +
13200 +       buflen = inode->i_op->getxattr(dentry, key, NULL, 0);
13201 +       if (buflen <= 0) {
13202 +               error = buflen < 0 ? buflen : -ENODATA;
13203 +               goto out_sem;
13204 +       }
13205 +
13206 +       buf = kmalloc(buflen, GFP_KERNEL);
13207 +       if (buf == NULL) {
13208 +               error = -ENOMEM;
13209 +               goto out_sem;
13210 +       }
13211 +
13212 +       error = -EOPNOTSUPP;
13213 +       if (inode->i_op && inode->i_op->getxattr) {
13214 +               error = security_inode_getxattr(dentry, key);
13215 +               if (error)
13216 +                       goto out_sem;
13217 +               error = inode->i_op->getxattr(dentry, key, buf, buflen);
13218 +       }
13219 +       if (error < 0)
13220 +               goto out_sem;
13221 +
13222 +       error = 0;
13223 +       up(&inode->i_sem);
13224 +
13225 +       pacl = posix_acl_from_xattr(buf, buflen);
13226 + out:
13227 +       kfree(buf);
13228 +       return pacl;
13229 + out_sem:
13230 +       up(&inode->i_sem);
13231 +       pacl = ERR_PTR(error);
13232 +       goto out;
13233 +}
13234 +
13235 +int
13236 +nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl)
13237 +{
13238 +       struct inode *inode = dentry->d_inode;
13239 +       int error = 0;
13240 +       struct posix_acl *pacl = NULL, *dpacl = NULL;
13241 +
13242 +       pacl = _get_posix_acl(dentry, XATTR_NAME_ACL_ACCESS);
13243 +       if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA)
13244 +               pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
13245 +       if (IS_ERR(pacl)) {
13246 +               error = PTR_ERR(pacl);
13247 +               pacl = NULL;
13248 +               goto out;
13249 +       }
13250 +
13251 +       if (S_ISDIR(inode->i_mode)) {
13252 +               dpacl = _get_posix_acl(dentry, XATTR_NAME_ACL_DEFAULT);
13253 +               if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA)
13254 +                       dpacl = NULL; 
13255 +               else if (IS_ERR(dpacl)) {
13256 +                       error = PTR_ERR(dpacl);
13257 +                       dpacl = NULL;
13258 +                       goto out;
13259 +               }
13260 +       }
13261 +
13262 +       *acl = nfs4_acl_posix_to_nfsv4(&nfsd_idmapper, rqstp, pacl, dpacl);
13263 +       if (IS_ERR(*acl)) {
13264 +               error = PTR_ERR(*acl);
13265 +               *acl = NULL;
13266 +       }
13267 + out:
13268 +       posix_acl_release(pacl);
13269 +       posix_acl_release(dpacl);
13270 +       return error;
13271 +}
13272 +
13273 +#endif /* CONFIG_NFS_V4_ACL */
13274 +
13275  #ifdef CONFIG_NFSD_V3
13276  /*
13277   * Check server access rights to a file system object
13278 @@ -458,11 +666,15 @@ nfsd_open(struct svc_rqst *rqstp, struct
13279         int             flags = O_RDONLY|O_LARGEFILE, err;
13280  
13281         /*
13282 -        * If we get here, then the client has already done an "open",
13283 +        * If we get here, then for regular files, 
13284 +        * the client has already done an "open",
13285          * and (hopefully) checked permission - so allow OWNER_OVERRIDE
13286          * in case a chmod has now revoked permission.
13287          */
13288 -       err = fh_verify(rqstp, fhp, type, access | MAY_OWNER_OVERRIDE);
13289 +       if (type == S_IFDIR)
13290 +               err = fh_verify(rqstp, fhp, type, access);
13291 +        else
13292 +               err = fh_verify(rqstp, fhp, type, access | MAY_OWNER_OVERRIDE);
13293         if (err)
13294                 goto out;
13295  
13296 @@ -1494,7 +1706,7 @@ nfsd_readdir(struct svc_rqst *rqstp, str
13297                 err = cdp->err;
13298         *offsetp = file.f_pos;
13299  
13300 -       if (err == nfserr_eof || err == nfserr_readdir_nospc)
13301 +       if (err == nfserr_eof || err == nfserr_toosmall)
13302                 err = nfs_ok; /* can still be found in ->err */
13303  out_close:
13304         nfsd_close(&file);
13305 diff -puN include/linux/nfsd/nfsd.h~CITI_NFS4_ALL include/linux/nfsd/nfsd.h
13306 --- linux-2.6.3/include/linux/nfsd/nfsd.h~CITI_NFS4_ALL 2004-02-19 16:47:07.000000000 -0500
13307 +++ linux-2.6.3-bfields/include/linux/nfsd/nfsd.h       2004-02-19 16:47:11.000000000 -0500
13308 @@ -76,6 +76,11 @@ int          nfsd_lookup(struct svc_rqst *, stru
13309                                 const char *, int, struct svc_fh *);
13310  int            nfsd_setattr(struct svc_rqst *, struct svc_fh *,
13311                                 struct iattr *, int, time_t);
13312 +#ifdef CONFIG_NFSD_V4
13313 +int             nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
13314 +                    struct nfs4_acl *);
13315 +int             nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
13316 +#endif /* CONFIG_NFSD_V4 */
13317  int            nfsd_create(struct svc_rqst *, struct svc_fh *,
13318                                 char *name, int len, struct iattr *attrs,
13319                                 int type, dev_t rdev, struct svc_fh *res);
13320 @@ -190,9 +195,12 @@ void               nfsd_lockd_shutdown(void);
13321  #define nfserr_bad_seqid       __constant_htonl(NFSERR_BAD_SEQID)
13322  #define        nfserr_symlink          __constant_htonl(NFSERR_SYMLINK)
13323  #define        nfserr_not_same         __constant_htonl(NFSERR_NOT_SAME)
13324 -#define        nfserr_readdir_nospc    __constant_htonl(NFSERR_READDIR_NOSPC)
13325 +#define        nfserr_restorefh        __constant_htonl(NFSERR_RESTOREFH)
13326 +#define        nfserr_attrnotsupp      __constant_htonl(NFSERR_ATTRNOTSUPP)
13327  #define        nfserr_bad_xdr          __constant_htonl(NFSERR_BAD_XDR)
13328  #define        nfserr_openmode         __constant_htonl(NFSERR_OPENMODE)
13329 +#define        nfserr_locks_held       __constant_htonl(NFSERR_LOCKS_HELD)
13330 +#define        nfserr_op_illegal       __constant_htonl(NFSERR_OP_ILLEGAL)
13331  
13332  /* error codes for internal use */
13333  /* if a request fails due to kmalloc failure, it gets dropped.
13334 @@ -247,7 +255,6 @@ static inline int is_fsid(struct svc_fh 
13335  
13336  /*
13337   * The following attributes are currently not supported by the NFSv4 server:
13338 - *    ACL           (will be supported in a forthcoming patch)
13339   *    ARCHIVE       (deprecated anyway)
13340   *    FS_LOCATIONS  (will be supported eventually)
13341   *    HIDDEN        (unlikely to be supported any time soon)
13342 @@ -267,7 +274,7 @@ static inline int is_fsid(struct svc_fh 
13343   | FATTR4_WORD0_FILEHANDLE      | FATTR4_WORD0_FILEID       | FATTR4_WORD0_FILES_AVAIL      \
13344   | FATTR4_WORD0_FILES_FREE      | FATTR4_WORD0_FILES_TOTAL  | FATTR4_WORD0_HOMOGENEOUS      \
13345   | FATTR4_WORD0_MAXFILESIZE     | FATTR4_WORD0_MAXLINK      | FATTR4_WORD0_MAXNAME          \
13346 - | FATTR4_WORD0_MAXREAD         | FATTR4_WORD0_MAXWRITE)
13347 + | FATTR4_WORD0_MAXREAD         | FATTR4_WORD0_MAXWRITE     | FATTR4_WORD0_ACL)
13348  
13349  #define NFSD_SUPPORTED_ATTRS_WORD1                                                          \
13350  (FATTR4_WORD1_MODE              | FATTR4_WORD1_NO_TRUNC     | FATTR4_WORD1_NUMLINKS         \
13351 @@ -282,7 +289,8 @@ static inline int is_fsid(struct svc_fh 
13352  (FATTR4_WORD1_TIME_ACCESS_SET   | FATTR4_WORD1_TIME_MODIFY_SET)
13353  
13354  /* These are the only attrs allowed in CREATE/OPEN/SETATTR. */
13355 -#define NFSD_WRITEABLE_ATTRS_WORD0                            FATTR4_WORD0_SIZE
13356 +#define NFSD_WRITEABLE_ATTRS_WORD0                                                          \
13357 +(FATTR4_WORD0_SIZE              | FATTR4_WORD0_ACL                                         )
13358  #define NFSD_WRITEABLE_ATTRS_WORD1                                                          \
13359  (FATTR4_WORD1_MODE              | FATTR4_WORD1_OWNER         | FATTR4_WORD1_OWNER_GROUP     \
13360   | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_MODIFY_SET)
13361 diff -puN net/sunrpc/auth_gss/gss_krb5_crypto.c~CITI_NFS4_ALL net/sunrpc/auth_gss/gss_krb5_crypto.c
13362 --- linux-2.6.3/net/sunrpc/auth_gss/gss_krb5_crypto.c~CITI_NFS4_ALL     2004-02-19 16:47:07.000000000 -0500
13363 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/gss_krb5_crypto.c   2004-02-19 16:47:07.000000000 -0500
13364 @@ -58,14 +58,14 @@ krb5_encrypt(
13365          struct scatterlist sg[1];
13366         u8 local_iv[16] = {0};
13367  
13368 -       dprintk("RPC: krb5_encrypt: input data:\n");
13369 +       dprintk("RPC:      krb5_encrypt: input data:\n");
13370         print_hexl((u32 *)in, length, 0);
13371  
13372         if (length % crypto_tfm_alg_blocksize(tfm) != 0)
13373                 goto out;
13374  
13375         if (crypto_tfm_alg_ivsize(tfm) > 16) {
13376 -               dprintk("RPC: gss_k5encrypt: tfm iv size to large %d\n",
13377 +               dprintk("RPC:      gss_k5encrypt: tfm iv size to large %d\n",
13378                          crypto_tfm_alg_ivsize(tfm));
13379                 goto out;
13380         }
13381 @@ -80,10 +80,10 @@ krb5_encrypt(
13382  
13383         ret = crypto_cipher_encrypt_iv(tfm, sg, sg, length, local_iv);
13384  
13385 -       dprintk("RPC: krb5_encrypt: output data:\n");
13386 +       dprintk("RPC:      krb5_encrypt: output data:\n");
13387         print_hexl((u32 *)out, length, 0);
13388  out:
13389 -       dprintk("krb5_encrypt returns %d\n",ret);
13390 +       dprintk("RPC:      krb5_encrypt returns %d\n",ret);
13391         return(ret);
13392  }
13393  
13394 @@ -99,14 +99,14 @@ krb5_decrypt(
13395         struct scatterlist sg[1];
13396         u8 local_iv[16] = {0};
13397  
13398 -       dprintk("RPC: krb5_decrypt: input data:\n");
13399 +       dprintk("RPC:      krb5_decrypt: input data:\n");
13400         print_hexl((u32 *)in, length, 0);
13401  
13402         if (length % crypto_tfm_alg_blocksize(tfm) != 0)
13403                 goto out;
13404  
13405         if (crypto_tfm_alg_ivsize(tfm) > 16) {
13406 -               dprintk("RPC: gss_k5decrypt: tfm iv size to large %d\n",
13407 +               dprintk("RPC:      gss_k5decrypt: tfm iv size to large %d\n",
13408                         crypto_tfm_alg_ivsize(tfm));
13409                 goto out;
13410         }
13411 @@ -120,10 +120,10 @@ krb5_decrypt(
13412  
13413         ret = crypto_cipher_decrypt_iv(tfm, sg, sg, length, local_iv);
13414  
13415 -       dprintk("RPC: krb5_decrypt: output_data:\n");
13416 +       dprintk("RPC:      krb5_decrypt: output_data:\n");
13417         print_hexl((u32 *)out, length, 0);
13418  out:
13419 -       dprintk("gss_k5decrypt returns %d\n",ret);
13420 +       dprintk("RPC:      gss_k5decrypt returns %d\n",ret);
13421         return(ret);
13422  }
13423  
13424 @@ -152,7 +152,7 @@ krb5_make_checksum(s32 cksumtype, char *
13425                         cksumname = "md5";
13426                         break;
13427                 default:
13428 -                       dprintk("RPC: krb5_make_checksum:"
13429 +                       dprintk("RPC:      krb5_make_checksum:"
13430                                 " unsupported checksum %d", cksumtype);
13431                         goto out;
13432         }
13433 diff -puN net/sunrpc/auth_gss/gss_krb5_seqnum.c~CITI_NFS4_ALL net/sunrpc/auth_gss/gss_krb5_seqnum.c
13434 --- linux-2.6.3/net/sunrpc/auth_gss/gss_krb5_seqnum.c~CITI_NFS4_ALL     2004-02-19 16:47:07.000000000 -0500
13435 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/gss_krb5_seqnum.c   2004-02-19 16:47:07.000000000 -0500
13436 @@ -70,7 +70,7 @@ krb5_get_seq_num(struct crypto_tfm *key,
13437         s32 code;
13438         unsigned char plain[8];
13439  
13440 -       dprintk("krb5_get_seq_num: \n");
13441 +       dprintk("RPC:      krb5_get_seq_num:\n");
13442  
13443         if ((code = krb5_decrypt(key, cksum, buf, plain, 8)))
13444                 return code;
13445 diff -puN net/sunrpc/auth_gss/gss_pseudoflavors.c~CITI_NFS4_ALL net/sunrpc/auth_gss/gss_pseudoflavors.c
13446 --- linux-2.6.3/net/sunrpc/auth_gss/gss_pseudoflavors.c~CITI_NFS4_ALL   2004-02-19 16:47:07.000000000 -0500
13447 +++ linux-2.6.3-bfields/net/sunrpc/auth_gss/gss_pseudoflavors.c 2004-02-19 16:47:07.000000000 -0500
13448 @@ -82,12 +82,13 @@ gss_register_triple(u32 pseudoflavor, st
13449  
13450         spin_lock(&registered_triples_lock);
13451         if (do_lookup_triple_by_pseudoflavor(pseudoflavor)) {
13452 -               printk("Registered pseudoflavor %d again\n", pseudoflavor);
13453 +               printk(KERN_WARNING "RPC: Registered pseudoflavor %d again\n",
13454 +                               pseudoflavor);
13455                 goto err_unlock;
13456         }
13457         list_add(&triple->triples, &registered_triples);
13458         spin_unlock(&registered_triples_lock);
13459 -       dprintk("RPC: registered pseudoflavor %d\n", pseudoflavor);
13460 +       dprintk("RPC:      registered pseudoflavor %d\n", pseudoflavor);
13461  
13462         return 0;
13463  
13464 @@ -145,7 +146,7 @@ gss_cmp_triples(u32 oid_len, char *oid_d
13465         oid.len = oid_len;
13466         oid.data = oid_data;
13467  
13468 -       dprintk("RPC: gss_cmp_triples \n");
13469 +       dprintk("RPC:      gss_cmp_triples\n");
13470         print_sec_triple(&oid,qop,service);
13471  
13472         spin_lock(&registered_triples_lock);
13473 @@ -158,7 +159,7 @@ gss_cmp_triples(u32 oid_len, char *oid_d
13474                 }
13475         }
13476         spin_unlock(&registered_triples_lock);
13477 -       dprintk("RPC: gss_cmp_triples return %d\n", pseudoflavor);
13478 +       dprintk("RPC:      gss_cmp_triples return %d\n", pseudoflavor);
13479         return pseudoflavor;
13480  }
13481  
13482 @@ -193,8 +194,8 @@ gss_pseudoflavor_to_service(u32 pseudofl
13483         triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
13484         spin_unlock(&registered_triples_lock);
13485         if (!triple) {
13486 -               dprintk("RPC: gss_pseudoflavor_to_service called with"
13487 -                       " unsupported pseudoflavor %d\n", pseudoflavor);
13488 +               dprintk("RPC:      gss_pseudoflavor_to_service called with unsupported pseudoflavor %d\n",
13489 +                               pseudoflavor);
13490                 return 0;
13491         }
13492         return triple->service;
13493 @@ -211,8 +212,8 @@ gss_pseudoflavor_to_mech(u32 pseudoflavo
13494         if (triple)
13495                 mech = gss_mech_get(triple->mech);
13496         else
13497 -               dprintk("RPC: gss_pseudoflavor_to_mech called with"
13498 -                       " unsupported pseudoflavor %d\n", pseudoflavor);
13499 +               dprintk("RPC:      gss_pseudoflavor_to_mech called with unsupported pseudoflavor %d\n",
13500 +                               pseudoflavor);
13501         return mech;
13502  }
13503  
13504 @@ -223,8 +224,8 @@ gss_pseudoflavor_to_mechOID(u32 pseudofl
13505  
13506         mech = gss_pseudoflavor_to_mech(pseudoflavor);
13507         if (!mech)  {
13508 -               dprintk("RPC: gss_pseudoflavor_to_mechOID called with"
13509 -                       " unsupported pseudoflavor %d\n", pseudoflavor);
13510 +               dprintk("RPC:      gss_pseudoflavor_to_mechOID called with unsupported pseudoflavor %d\n",
13511 +                               pseudoflavor);
13512                         return -1;
13513         }
13514         oid->len = mech->gm_oid.len;
13515 diff -puN fs/nfsd/nfs4state.c~CITI_NFS4_ALL fs/nfsd/nfs4state.c
13516 --- linux-2.6.3/fs/nfsd/nfs4state.c~CITI_NFS4_ALL       2004-02-19 16:47:08.000000000 -0500
13517 +++ linux-2.6.3-bfields/fs/nfsd/nfs4state.c     2004-02-19 16:47:15.000000000 -0500
13518 @@ -43,6 +43,7 @@
13519  #include <linux/nfsd/cache.h>
13520  #include <linux/mount.h>
13521  #include <linux/workqueue.h>
13522 +#include <linux/smp_lock.h>
13523  #include <linux/nfs4.h>
13524  #include <linux/nfsd/state.h>
13525  #include <linux/nfsd/xdr4.h>
13526 @@ -135,12 +136,16 @@ static void release_file(struct nfs4_fil
13527   *
13528   * client_lru holds client queue ordered by nfs4_client.cl_time
13529   * for lease renewal.
13530 + *
13531 + * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
13532 + * for last close replay.
13533   */
13534  static struct list_head        conf_id_hashtbl[CLIENT_HASH_SIZE];
13535  static struct list_head        conf_str_hashtbl[CLIENT_HASH_SIZE];
13536  static struct list_head        unconf_str_hashtbl[CLIENT_HASH_SIZE];
13537  static struct list_head        unconf_id_hashtbl[CLIENT_HASH_SIZE];
13538  static struct list_head client_lru;
13539 +static struct list_head close_lru;
13540  
13541  static inline void
13542  renew_client(struct nfs4_client *clp)
13543 @@ -269,8 +274,7 @@ cmp_clid(clientid_t * cl1, clientid_t * 
13544  /* XXX what about NGROUP */
13545  static int
13546  cmp_creds(struct svc_cred *cr1, struct svc_cred *cr2){
13547 -       return((cr1->cr_uid == cr2->cr_uid) &&
13548 -               (cr1->cr_gid == cr2->cr_gid));
13549 +       return(cr1->cr_uid == cr2->cr_uid);
13550  
13551  }
13552  
13553 @@ -772,6 +776,9 @@ alloc_init_open_stateowner(unsigned int 
13554         INIT_LIST_HEAD(&sop->so_strhash);
13555         INIT_LIST_HEAD(&sop->so_perclient);
13556         INIT_LIST_HEAD(&sop->so_perfilestate);
13557 +       INIT_LIST_HEAD(&sop->so_perlockowner);  /* not used */
13558 +       INIT_LIST_HEAD(&sop->so_close_lru);
13559 +       sop->so_time = 0;
13560         list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
13561         list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
13562         list_add(&sop->so_perclient, &clp->cl_perclient);
13563 @@ -790,13 +797,29 @@ alloc_init_open_stateowner(unsigned int 
13564  }
13565  
13566  static void
13567 +release_stateid_lockowner(struct nfs4_stateid *open_stp)
13568 +{
13569 +       struct nfs4_stateowner *lock_sop;       
13570 +       
13571 +       while (!list_empty(&open_stp->st_perlockowner)) {
13572 +               lock_sop = list_entry(open_stp->st_perlockowner.next,
13573 +                               struct nfs4_stateowner, so_perlockowner);
13574 +               /* list_del(&open_stp->st_perlockowner);  */
13575 +               BUG_ON(lock_sop->so_is_open_owner);
13576 +               release_stateowner(lock_sop);
13577 +       }
13578 +}
13579 +
13580 +static void
13581  release_stateowner(struct nfs4_stateowner *sop)
13582  {
13583         struct nfs4_stateid *stp;
13584  
13585 -       list_del_init(&sop->so_idhash);
13586 -       list_del_init(&sop->so_strhash);
13587 -       list_del_init(&sop->so_perclient);
13588 +       list_del(&sop->so_idhash);
13589 +       list_del(&sop->so_strhash);
13590 +       list_del(&sop->so_perclient);
13591 +       list_del(&sop->so_perlockowner);
13592 +       list_del(&sop->so_close_lru);
13593         del_perclient++;
13594         while (!list_empty(&sop->so_perfilestate)) {
13595                 stp = list_entry(sop->so_perfilestate.next, 
13596 @@ -815,6 +838,7 @@ init_stateid(struct nfs4_stateid *stp, s
13597  
13598         INIT_LIST_HEAD(&stp->st_hash);
13599         INIT_LIST_HEAD(&stp->st_perfilestate);
13600 +       INIT_LIST_HEAD(&stp->st_perlockowner);
13601         INIT_LIST_HEAD(&stp->st_perfile);
13602         list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
13603         list_add(&stp->st_perfilestate, &sop->so_perfilestate);
13604 @@ -826,24 +850,30 @@ init_stateid(struct nfs4_stateid *stp, s
13605         stp->st_stateid.si_stateownerid = sop->so_id;
13606         stp->st_stateid.si_fileid = fp->fi_id;
13607         stp->st_stateid.si_generation = 0;
13608 -       stp->st_share_access = open->op_share_access;
13609 -       stp->st_share_deny = open->op_share_deny;
13610 +       stp->st_access_bmap = 0;
13611 +       stp->st_deny_bmap = 0;
13612 +       __set_bit(open->op_share_access, &stp->st_access_bmap);
13613 +       __set_bit(open->op_share_deny, &stp->st_deny_bmap);
13614  }
13615  
13616  static void
13617  release_stateid(struct nfs4_stateid *stp, int flags) {
13618  
13619 -       list_del_init(&stp->st_hash);
13620 +       list_del(&stp->st_hash);
13621         list_del_perfile++;
13622 -       list_del_init(&stp->st_perfile);
13623 -       list_del_init(&stp->st_perfilestate);
13624 +       list_del(&stp->st_perfile);
13625 +       list_del(&stp->st_perfilestate);
13626         if((stp->st_vfs_set) && (flags & OPEN_STATE)) {
13627 +               release_stateid_lockowner(stp);
13628                 nfsd_close(&stp->st_vfs_file);
13629                 vfsclose++;
13630                 dput(stp->st_vfs_file.f_dentry);
13631                 mntput(stp->st_vfs_file.f_vfsmnt);
13632 +       } else if ((stp->st_vfs_set) && (flags & LOCK_STATE)) {
13633 +               struct file *filp = &stp->st_vfs_file;
13634 +
13635 +               locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
13636         }
13637 -       /* should use a slab cache */
13638         kfree(stp);
13639         stp = NULL;
13640  }
13641 @@ -852,12 +882,25 @@ static void
13642  release_file(struct nfs4_file *fp)
13643  {
13644         free_file++;
13645 -       list_del_init(&fp->fi_hash);
13646 +       list_del(&fp->fi_hash);
13647         iput(fp->fi_inode);
13648         kfree(fp);
13649  }      
13650  
13651  void
13652 +move_to_close_lru(struct nfs4_stateowner *sop)
13653 +{
13654 +       dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
13655 +       /* remove stateowner from all other hash lists except perclient */
13656 +       list_del_init(&sop->so_idhash);
13657 +       list_del_init(&sop->so_strhash);
13658 +       list_del_init(&sop->so_perlockowner);
13659 +
13660 +        list_add_tail(&sop->so_close_lru, &close_lru);
13661 +        sop->so_time = get_seconds();
13662 +}
13663 +
13664 +void
13665  release_state_owner(struct nfs4_stateid *stp, struct nfs4_stateowner **sopp,
13666                 int flag)
13667  {
13668 @@ -866,16 +909,13 @@ release_state_owner(struct nfs4_stateid 
13669  
13670         dprintk("NFSD: release_state_owner\n");
13671         release_stateid(stp, flag);
13672 -       /*
13673 -        * release unused nfs4_stateowners.
13674 -        * XXX will need to be placed  on an  open_stateid_lru list to be
13675 +
13676 +       /* place unused nfs4_stateowners on so_close_lru list to be
13677          * released by the laundromat service after the lease period
13678          * to enable us to handle CLOSE replay
13679          */
13680 -       if (sop->so_confirmed && list_empty(&sop->so_perfilestate)) {
13681 -               release_stateowner(sop);
13682 -               *sopp = NULL;
13683 -       }
13684 +       if (sop->so_confirmed && list_empty(&sop->so_perfilestate))
13685 +               move_to_close_lru(sop);
13686         /* unused nfs4_file's are releseed. XXX slab cache? */
13687         if (list_empty(&fp->fi_perfile)) {
13688                 release_file(fp);
13689 @@ -940,15 +980,46 @@ find_file(unsigned int hashval, struct i
13690         return 0;
13691  }
13692  
13693 +#define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0)
13694 +#define TEST_DENY(x) ((x >= 0 || x < 5)?1:0)
13695 +
13696 +void
13697 +set_access(unsigned int *access, unsigned long bmap) {
13698 +       int i;
13699 +
13700 +       *access = 0;
13701 +       for (i = 1; i < 4; i++) {
13702 +               if(test_bit(i, &bmap))
13703 +                       *access |= i;
13704 +       }
13705 +}
13706 +
13707 +void
13708 +set_deny(unsigned int *deny, unsigned long bmap) {
13709 +       int i;
13710 +
13711 +       *deny = 0;
13712 +       for (i = 0; i < 4; i++) {
13713 +               if(test_bit(i, &bmap))
13714 +                       *deny |= i ;
13715 +       }
13716 +}
13717 +
13718  static int
13719  test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
13720 -       if ((stp->st_share_access & open->op_share_deny) ||
13721 -           (stp->st_share_deny & open->op_share_access)) {
13722 +       unsigned int access, deny;
13723 +       
13724 +       set_access(&access, stp->st_access_bmap);
13725 +       set_deny(&deny, stp->st_deny_bmap);
13726 +       if ((access & open->op_share_deny) || (deny & open->op_share_access)) 
13727                 return 0;
13728 -       }
13729         return 1;
13730  }
13731  
13732 +/*
13733 + * Called to check deny when READ with all zero stateid or 
13734 + * WRITE with all zero or all one stateid
13735 + */ 
13736  int
13737  nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
13738  {
13739 @@ -965,7 +1036,8 @@ nfs4_share_conflict(struct svc_fh *curre
13740         /* Search for conflicting share reservations */
13741                 list_for_each_safe(pos, next, &fp->fi_perfile) {
13742                         stp = list_entry(pos, struct nfs4_stateid, st_perfile);
13743 -                       if (stp->st_share_deny & deny_type)
13744 +                       if (test_bit(deny_type, &stp->st_deny_bmap) ||
13745 +                           test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
13746                                 return nfserr_share_denied;
13747                 }
13748         }
13749 @@ -1010,6 +1082,8 @@ nfs4_file_downgrade(struct file *filp, u
13750   *             notfound:
13751   *                     verify clientid
13752   *                     create new owner
13753 + *
13754 + * called with nfs4_lock_state() held.
13755   */
13756  int
13757  nfsd4_process_open1(struct nfsd4_open *open)
13758 @@ -1028,7 +1102,6 @@ nfsd4_process_open1(struct nfsd4_open *o
13759         if (STALE_CLIENTID(&open->op_clientid))
13760                 goto out;
13761  
13762 -       nfs4_lock_state();
13763         strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
13764         if (find_openstateowner_str(strhashval, open, &sop)) {
13765                 open->op_stateowner = sop;
13766 @@ -1086,10 +1159,11 @@ instantiate_new_owner:
13767  renew:
13768         renew_client(sop->so_client);
13769  out:
13770 -       nfs4_unlock_state();
13771         return status;
13772  }
13773 -
13774 +/*
13775 + * called with nfs4_lock_state() held.
13776 + */
13777  int
13778  nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
13779  {
13780 @@ -1108,7 +1182,10 @@ nfsd4_process_open2(struct svc_rqst *rqs
13781  
13782         ino = current_fh->fh_dentry->d_inode;
13783  
13784 -       nfs4_lock_state();
13785 +       status = nfserr_inval;
13786 +       if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
13787 +               goto out;
13788 +           
13789         fi_hashval = file_hashval(ino);
13790         if (find_file(fi_hashval, ino, &fp)) {
13791                 /* Search for conflicting share reservations */
13792 @@ -1119,6 +1196,9 @@ nfsd4_process_open2(struct svc_rqst *rqs
13793                                 stp = stq;
13794                                 continue;
13795                         }
13796 +                       /* ignore lock owners */
13797 +                       if (stq->st_stateowner->so_is_open_owner == 0) 
13798 +                               continue;
13799                         if (!test_share(stq,open))      
13800                                 goto out;
13801                 }
13802 @@ -1137,7 +1217,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
13803                                                 GFP_KERNEL)) == NULL)
13804                         goto out;
13805  
13806 -               if (open->op_share_access && NFS4_SHARE_ACCESS_WRITE)
13807 +               if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
13808                         flags = MAY_WRITE;
13809                 else
13810                         flags = MAY_READ;
13811 @@ -1156,15 +1236,18 @@ nfsd4_process_open2(struct svc_rqst *rqs
13812                 /* This is an upgrade of an existing OPEN. 
13813                  * OR the incoming share with the existing 
13814                  * nfs4_stateid share */
13815 -               int share_access = open->op_share_access;
13816 +               unsigned int share_access;
13817  
13818 -               share_access &= ~(stp->st_share_access);
13819 +               set_access(&share_access, stp->st_access_bmap);
13820 +               share_access = ~share_access;
13821 +               share_access &= open->op_share_access;
13822  
13823                 /* update the struct file */
13824                 if ((status = nfs4_file_upgrade(&stp->st_vfs_file, share_access)))
13825                         goto out;
13826 -               stp->st_share_access |= share_access;
13827 -               stp->st_share_deny |= open->op_share_deny;
13828 +               /* remember the open */
13829 +               set_bit(open->op_share_access, &stp->st_access_bmap);
13830 +               set_bit(open->op_share_deny, &stp->st_deny_bmap);
13831                 /* bump the stateid */
13832                 update_stateid(&stp->st_stateid);
13833         }
13834 @@ -1194,7 +1277,6 @@ out:
13835         if (!open->op_stateowner->so_confirmed)
13836                 open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
13837  
13838 -       nfs4_unlock_state();
13839         return status;
13840  out_free:
13841         kfree(stp);
13842 @@ -1250,9 +1332,11 @@ time_t
13843  nfs4_laundromat(void)
13844  {
13845         struct nfs4_client *clp;
13846 +       struct nfs4_stateowner *sop;
13847         struct list_head *pos, *next;
13848         time_t cutoff = get_seconds() - NFSD_LEASE_TIME;
13849 -       time_t t, return_val = NFSD_LEASE_TIME;
13850 +       time_t t, clientid_val = NFSD_LEASE_TIME;
13851 +       time_t u, close_val = NFSD_LEASE_TIME;
13852  
13853         nfs4_lock_state();
13854  
13855 @@ -1261,18 +1345,30 @@ nfs4_laundromat(void)
13856                 clp = list_entry(pos, struct nfs4_client, cl_lru);
13857                 if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
13858                         t = clp->cl_time - cutoff;
13859 -                       if (return_val > t)
13860 -                               return_val = t;
13861 +                       if (clientid_val > t)
13862 +                               clientid_val = t;
13863                         break;
13864                 }
13865                 dprintk("NFSD: purging unused client (clientid %08x)\n",
13866                         clp->cl_clientid.cl_id);
13867                 expire_client(clp);
13868         }
13869 -       if (return_val < NFSD_LAUNDROMAT_MINTIMEOUT)
13870 -               return_val = NFSD_LAUNDROMAT_MINTIMEOUT;
13871 +       list_for_each_safe(pos, next, &close_lru) {
13872 +               sop = list_entry(pos, struct nfs4_stateowner, so_close_lru);
13873 +               if (time_after((unsigned long)sop->so_time, (unsigned long)cutoff)) {
13874 +                       u = sop->so_time - cutoff;
13875 +                       if (close_val > u)
13876 +                               close_val = u;
13877 +                       break;
13878 +               }
13879 +               dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
13880 +                       sop->so_id);
13881 +               release_stateowner(sop);
13882 +       }
13883 +       if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
13884 +               clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
13885         nfs4_unlock_state();
13886 -       return return_val;
13887 +       return clientid_val;
13888  }
13889  
13890  void
13891 @@ -1285,17 +1381,22 @@ laundromat_main(void *not_used)
13892         schedule_delayed_work(&laundromat_work, t*HZ);
13893  }
13894  
13895 -/* search ownerid_hashtbl[] for stateid owner (stateid->si_stateownerid) */
13896 +/* search ownerid_hashtbl[] and close_lru for stateid owner 
13897 + * (stateid->si_stateownerid) 
13898 + */
13899  struct nfs4_stateowner *
13900 -find_openstateowner_id(u32 st_id) {
13901 +find_openstateowner_id(u32 st_id, int flags) {
13902         struct list_head *pos, *next;
13903         struct nfs4_stateowner *local = NULL;
13904 -       unsigned int hashval = ownerid_hashval(st_id);
13905  
13906 -       list_for_each_safe(pos, next, &ownerid_hashtbl[hashval]) {
13907 -               local = list_entry(pos, struct nfs4_stateowner, so_idhash);
13908 -               if(local->so_id == st_id)
13909 -                       return local;
13910 +       dprintk("NFSD: find_openstateowner_id %d\n", st_id);
13911 +       if (flags & CLOSE_STATE) {
13912 +               list_for_each_safe(pos, next, &close_lru) {
13913 +                       local = list_entry(pos, struct nfs4_stateowner, 
13914 +                                           so_close_lru);
13915 +                       if(local->so_id == st_id)
13916 +                               return local;
13917 +               }
13918         }
13919         return NULL;
13920  }
13921 @@ -1303,7 +1404,8 @@ find_openstateowner_id(u32 st_id) {
13922  static inline int
13923  nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
13924  {
13925 -       return (fhp->fh_dentry != stp->st_vfs_file.f_dentry);
13926 +       return (stp->st_vfs_set == 0 ||
13927 +               fhp->fh_dentry->d_inode->i_ino != stp->st_vfs_file.f_dentry->d_inode->i_ino);
13928  }
13929  
13930  static int
13931 @@ -1375,7 +1477,7 @@ out:
13932   * Checks for sequence id mutating operations. 
13933   */
13934  int
13935 -nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp)
13936 +nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid)
13937  {
13938         int status;
13939         struct nfs4_stateid *stp;
13940 @@ -1412,6 +1514,21 @@ nfs4_preprocess_seqid_op(struct svc_fh *
13941  
13942         status = nfserr_bad_stateid;
13943  
13944 +       /* for new lock stateowners, check that the lock->v.new.open_stateid
13945 +        * refers to an open stateowner, and that the lockclid 
13946 +        * (nfs4_lock->v.new.clientid) is the same as the 
13947 +        * open_stateid->st_stateowner->so_client->clientid
13948 +        */
13949 +       if (lockclid) {
13950 +               struct nfs4_stateowner *sop = stp->st_stateowner;       
13951 +               struct nfs4_client *clp = sop->so_client;
13952 +
13953 +               if (!sop->so_is_open_owner)
13954 +                       goto out;
13955 +               if (!cmp_clid(&clp->cl_clientid, lockclid))
13956 +                       goto out;
13957 +       }
13958 +
13959         if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
13960                 printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
13961                 goto out;
13962 @@ -1463,24 +1580,30 @@ no_nfs4_stateid:
13963         * starting by trying to look up the stateowner.
13964         * If stateowner is not found - stateid is bad.
13965         */
13966 -       if (!(sop = find_openstateowner_id(stateid->si_stateownerid))) {
13967 +       if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {
13968                 printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
13969                 status = nfserr_bad_stateid;
13970                 goto out;
13971         }
13972 +       *sopp = sop;
13973  
13974  check_replay:
13975         if (seqid == sop->so_seqid) {
13976                 printk("NFSD: preprocess_seqid_op: retransmission?\n");
13977                 /* indicate replay to calling function */
13978                 status = NFSERR_REPLAY_ME;
13979 -       } else 
13980 +       } else  {
13981                 printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
13982  
13983 +               *sopp = NULL;
13984                 status = nfserr_bad_seqid;
13985 +       }
13986         goto out;
13987  }
13988  
13989 +/*
13990 + * nfs4_unlock_state(); called in encode
13991 + */
13992  int
13993  nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
13994  {
13995 @@ -1491,13 +1614,17 @@ nfsd4_open_confirm(struct svc_rqst *rqst
13996         dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
13997                         (int)current_fh->fh_dentry->d_name.len,
13998                         current_fh->fh_dentry->d_name.name);
13999 +
14000 +       if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) 
14001 +               goto out;
14002 +
14003         oc->oc_stateowner = NULL;
14004         nfs4_lock_state();
14005  
14006         if ((status = nfs4_preprocess_seqid_op(current_fh, oc->oc_seqid,
14007                                         &oc->oc_req_stateid,
14008                                         CHECK_FH | CONFIRM | OPEN_STATE,
14009 -                                       &oc->oc_stateowner, &stp)))
14010 +                                       &oc->oc_stateowner, &stp, NULL)))
14011                 goto out; 
14012  
14013         sop = oc->oc_stateowner;
14014 @@ -1512,49 +1639,89 @@ nfsd4_open_confirm(struct svc_rqst *rqst
14015                          stp->st_stateid.si_generation);
14016         status = nfs_ok;
14017  out:
14018 -       nfs4_unlock_state();
14019         return status;
14020  }
14021 +
14022 +
14023 +/* 
14024 + * unset all bits in union bitmap (bmap) that
14025 + * do not exist in share (from successful OPEN_DOWNGRADE)
14026 + */
14027 +static void
14028 +reset_union_bmap_access(unsigned long access, unsigned long *bmap)
14029 +{
14030 +       int i;
14031 +       for (i = 1; i < 4; i++) {
14032 +               if ((i & access) != i)
14033 +                       __clear_bit(i, bmap);
14034 +       }
14035 +}
14036 +
14037 +static void
14038 +reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
14039 +{
14040 +       int i;
14041 +       for (i = 0; i < 4; i++) {
14042 +               if ((i & deny) != i)
14043 +                       __clear_bit(i, bmap);
14044 +       }
14045 +}
14046 +
14047 +/* 
14048 + * nfs4_unlock_state(); called in encode
14049 + */
14050 +
14051  int
14052  nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
14053  {
14054         int status;
14055         struct nfs4_stateid *stp;
14056 +       unsigned int share_access;
14057  
14058         dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", 
14059                         (int)current_fh->fh_dentry->d_name.len,
14060                         current_fh->fh_dentry->d_name.name);
14061  
14062 +       od->od_stateowner = NULL;
14063 +       status = nfserr_inval;
14064 +       if (!TEST_ACCESS(od->od_share_access) || !TEST_DENY(od->od_share_deny))
14065 +               goto out;
14066 +
14067         nfs4_lock_state();
14068         if ((status = nfs4_preprocess_seqid_op(current_fh, od->od_seqid, 
14069                                         &od->od_stateid, 
14070                                         CHECK_FH | OPEN_STATE, 
14071 -                                       &od->od_stateowner, &stp)))
14072 +                                       &od->od_stateowner, &stp, NULL)))
14073                 goto out; 
14074  
14075         status = nfserr_inval;
14076 -       if (od->od_share_access & ~stp->st_share_access) {
14077 -               dprintk("NFSD:access not a subset current=%08x, desired=%08x\n", 
14078 -                       stp->st_share_access, od->od_share_access); 
14079 +       if (!test_bit(od->od_share_access, &stp->st_access_bmap)) {
14080 +               dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n", 
14081 +                       stp->st_access_bmap, od->od_share_access); 
14082                 goto out;
14083         }
14084 -       if (od->od_share_deny & ~stp->st_share_deny) {
14085 -               dprintk("NFSD:deny not a subset current=%08x, desired=%08x\n", 
14086 -                       stp->st_share_deny, od->od_share_deny);
14087 +       if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) {
14088 +               dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n", 
14089 +                       stp->st_deny_bmap, od->od_share_deny);
14090                 goto out;
14091         }
14092 +       set_access(&share_access, stp->st_access_bmap);
14093         nfs4_file_downgrade(&stp->st_vfs_file, 
14094 -       stp->st_share_access & ~od->od_share_access);
14095 -       stp->st_share_access = od->od_share_access;
14096 -       stp->st_share_deny = od->od_share_deny;
14097 +                           share_access & ~od->od_share_access);
14098 +
14099 +       reset_union_bmap_access(od->od_share_access, &stp->st_access_bmap);
14100 +       reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);
14101 +
14102         update_stateid(&stp->st_stateid);
14103         memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
14104         status = nfs_ok;
14105  out:
14106 -       nfs4_unlock_state();
14107         return status;
14108  }
14109  
14110 +/* 
14111 + * nfs4_unlock_state() called after encode
14112 + */
14113  int
14114  nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
14115  {
14116 @@ -1565,11 +1732,13 @@ nfsd4_close(struct svc_rqst *rqstp, stru
14117                         (int)current_fh->fh_dentry->d_name.len,
14118                         current_fh->fh_dentry->d_name.name);
14119  
14120 +       close->cl_stateowner = NULL;
14121         nfs4_lock_state();
14122 +       /* check close_lru for replay */
14123         if ((status = nfs4_preprocess_seqid_op(current_fh, close->cl_seqid, 
14124                                         &close->cl_stateid, 
14125 -                                       CHECK_FH | OPEN_STATE, 
14126 -                                       &close->cl_stateowner, &stp)))
14127 +                                       CHECK_FH | OPEN_STATE | CLOSE_STATE, 
14128 +                                       &close->cl_stateowner, &stp, NULL)))
14129                 goto out; 
14130         /*
14131         *  Return success, but first update the stateid.
14132 @@ -1581,7 +1750,6 @@ nfsd4_close(struct svc_rqst *rqstp, stru
14133         /* release_state_owner() calls nfsd_close() if needed */
14134         release_state_owner(stp, &close->cl_stateowner, OPEN_STATE);
14135  out:
14136 -       nfs4_unlock_state();
14137         return status;
14138  }
14139  
14140 @@ -1717,7 +1885,7 @@ find_lockstateowner_str(unsigned int has
14141   */
14142  
14143  static struct nfs4_stateowner *
14144 -alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_lock *lock) {
14145 +alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_stateid *open_stp, struct nfsd4_lock *lock) {
14146         struct nfs4_stateowner *sop;
14147         struct nfs4_replay *rp;
14148         unsigned int idhashval;
14149 @@ -1729,9 +1897,13 @@ alloc_init_lock_stateowner(unsigned int 
14150         INIT_LIST_HEAD(&sop->so_strhash);
14151         INIT_LIST_HEAD(&sop->so_perclient);
14152         INIT_LIST_HEAD(&sop->so_perfilestate);
14153 +       INIT_LIST_HEAD(&sop->so_perlockowner);
14154 +       INIT_LIST_HEAD(&sop->so_close_lru); /* not used */
14155 +       sop->so_time = 0;
14156         list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
14157         list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
14158         list_add(&sop->so_perclient, &clp->cl_perclient);
14159 +       list_add(&sop->so_perlockowner, &open_stp->st_perlockowner);
14160         add_perclient++;
14161         sop->so_is_open_owner = 0;
14162         sop->so_id = current_ownerid++;
14163 @@ -1755,10 +1927,10 @@ alloc_init_lock_stateid(struct nfs4_stat
14164         if ((stp = kmalloc(sizeof(struct nfs4_stateid), 
14165                                         GFP_KERNEL)) == NULL)
14166                 goto out;
14167 -
14168         INIT_LIST_HEAD(&stp->st_hash);
14169         INIT_LIST_HEAD(&stp->st_perfile);
14170         INIT_LIST_HEAD(&stp->st_perfilestate);
14171 +       INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */
14172         list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]);
14173         list_add(&stp->st_perfile, &fp->fi_perfile);
14174         list_add_perfile++;
14175 @@ -1771,15 +1943,24 @@ alloc_init_lock_stateid(struct nfs4_stat
14176         stp->st_stateid.si_generation = 0;
14177         stp->st_vfs_file = open_stp->st_vfs_file;
14178         stp->st_vfs_set = open_stp->st_vfs_set;
14179 -       stp->st_share_access = -1; 
14180 -       stp->st_share_deny = -1;
14181 +       stp->st_access_bmap = open_stp->st_access_bmap;
14182 +       stp->st_deny_bmap = open_stp->st_deny_bmap;
14183  
14184  out:
14185         return stp;
14186  }
14187  
14188 +int
14189 +check_lock_length(u64 offset, u64 length)
14190 +{
14191 +       return ((length == 0)  || ((length != ~(u64)0) && 
14192 +            LOFF_OVERFLOW(offset, length)));
14193 +}
14194 +
14195  /*
14196   *  LOCK operation 
14197 + *  
14198 + * nfs4_unlock_state(); called in encode
14199   */
14200  int
14201  nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
14202 @@ -1795,6 +1976,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
14203         dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
14204                 lock->lk_offset, lock->lk_length);
14205  
14206 +       if (check_lock_length(lock->lk_offset, lock->lk_length))
14207 +                return nfserr_inval;
14208 +
14209         lock->lk_stateowner = NULL;
14210         nfs4_lock_state();
14211  
14212 @@ -1812,12 +1996,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
14213                         printk("NFSD: nfsd4_lock: clientid is stale!\n");
14214                         goto out;
14215                 }
14216 +               /* does the clientid in the lock owner own the open stateid? */
14217 +
14218                 /* validate and update open stateid and open seqid */
14219                 status = nfs4_preprocess_seqid_op(current_fh, 
14220                                         lock->lk_new_open_seqid,
14221                                         &lock->lk_new_open_stateid,
14222                                         CHECK_FH | OPEN_STATE,
14223 -                                       &open_sop, &open_stp);
14224 +                                       &open_sop, &open_stp,
14225 +                                       &lock->v.new.clientid);
14226                 if (status)
14227                         goto out;
14228                 /* create lockowner and lock stateid */
14229 @@ -1836,8 +2023,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
14230                                         &lock->v.new.clientid, &lock_sop))
14231                         goto out;
14232                 status = nfserr_resource;
14233 -               if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, 
14234 -                                               open_sop->so_client, lock)))
14235 +               if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
14236                         goto out;
14237                 if ((lock_stp = alloc_init_lock_stateid(lock->lk_stateowner, 
14238                                                 fp, open_stp)) == NULL)
14239 @@ -1850,7 +2036,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
14240                                        lock->lk_old_lock_seqid, 
14241                                        &lock->lk_old_lock_stateid, 
14242                                        CHECK_FH | LOCK_STATE, 
14243 -                                      &lock->lk_stateowner, &lock_stp);
14244 +                                      &lock->lk_stateowner, &lock_stp, NULL);
14245                 if (status)
14246                         goto out;
14247         }
14248 @@ -1938,7 +2124,6 @@ out_destroy_new_stateid:
14249                 release_state_owner(lock_stp, &lock->lk_stateowner, LOCK_STATE);
14250         }
14251  out:
14252 -       nfs4_unlock_state();
14253         return status;
14254  }
14255  
14256 @@ -1956,6 +2141,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
14257         unsigned int strhashval;
14258         int status;
14259  
14260 +       if (check_lock_length(lockt->lt_offset, lockt->lt_length))
14261 +                return nfserr_inval;
14262 +
14263         lockt->lt_stateowner = NULL;
14264         nfs4_lock_state();
14265  
14266 @@ -1967,6 +2155,8 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
14267  
14268         if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0))) {
14269                 printk("NFSD: nfsd4_lockt: fh_verify() failed!\n");
14270 +               if (status == nfserr_symlink)
14271 +                       status = nfserr_inval;
14272                 goto out;
14273         }
14274  
14275 @@ -1989,13 +2179,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
14276         strhashval = lock_ownerstr_hashval(inode, 
14277                         lockt->lt_clientid.cl_id, lockt->lt_owner);
14278  
14279 -       if (find_lockstateowner_str(strhashval, &lockt->lt_owner, 
14280 +       find_lockstateowner_str(strhashval, &lockt->lt_owner, 
14281                                         &lockt->lt_clientid, 
14282 -                                       &lockt->lt_stateowner)) {
14283 -               printk("NFSD: nsfd4_lockt: lookup_lockowner() failed!\n");
14284 -               goto out;
14285 -       }
14286 -
14287 +                                       &lockt->lt_stateowner);
14288         sop = lockt->lt_stateowner;
14289         if (sop) {
14290                 file_lock.fl_owner = (fl_owner_t) sop;
14291 @@ -2032,7 +2218,10 @@ out:
14292         nfs4_unlock_state();
14293         return status;
14294  }
14295 -
14296 +       
14297 +/* 
14298 + * nfs4_unlock_state(); called in encode
14299 + */
14300  int
14301  nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku)
14302  {
14303 @@ -2043,13 +2232,18 @@ nfsd4_locku(struct svc_rqst *rqstp, stru
14304                                                         
14305         dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
14306                 locku->lu_offset, locku->lu_length);
14307 +
14308 +       if (check_lock_length(locku->lu_offset, locku->lu_length))
14309 +                return nfserr_inval;
14310 +
14311 +       locku->lu_stateowner = NULL;
14312         nfs4_lock_state();
14313                                                                                 
14314         if ((status = nfs4_preprocess_seqid_op(current_fh, 
14315                                         locku->lu_seqid, 
14316                                         &locku->lu_stateid, 
14317                                         CHECK_FH | LOCK_STATE, 
14318 -                                       &locku->lu_stateowner, &stp)))
14319 +                                       &locku->lu_stateowner, &stp, NULL)))
14320                 goto out;
14321  
14322         filp = &stp->st_vfs_file;
14323 @@ -2085,7 +2279,6 @@ nfsd4_locku(struct svc_rqst *rqstp, stru
14324         memcpy(&locku->lu_stateid, &stp->st_stateid, sizeof(stateid_t));
14325  
14326  out:
14327 -       nfs4_unlock_state();
14328         return status;
14329  
14330  out_nfserr:
14331 @@ -2093,6 +2286,84 @@ out_nfserr:
14332         goto out;
14333  }
14334  
14335 +/*
14336 + * returns
14337 + *     1: locks held by lockowner
14338 + *     0: no locks held by lockowner
14339 + */    
14340 +static int
14341 +check_for_locks(struct file *filp, struct nfs4_stateowner *lowner)
14342 +{
14343 +       struct file_lock **flpp;
14344 +       struct inode *inode = filp->f_dentry->d_inode;
14345 +       int status = 0;
14346 +
14347 +       lock_kernel();
14348 +       for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
14349 +               if ((*flpp)->fl_owner == (fl_owner_t)lowner)
14350 +                       status = 1;
14351 +                       goto out;
14352 +       }
14353 +out:
14354 +       unlock_kernel();
14355 +       return status;
14356 +}
14357 +
14358 +int
14359 +nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
14360 +{
14361 +       clientid_t *clid = &rlockowner->rl_clientid;
14362 +       struct list_head *pos, *next;
14363 +       struct nfs4_stateowner *local = NULL;
14364 +       struct xdr_netobj *owner = &rlockowner->rl_owner;
14365 +       int status, i;
14366 +
14367 +       dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
14368 +               clid->cl_boot, clid->cl_id);
14369 +
14370 +       /* XXX check for lease expiration */
14371 +
14372 +       status = nfserr_stale_clientid;
14373 +       if (STALE_CLIENTID(clid)) {
14374 +               printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n");
14375 +               return status;
14376 +       }
14377 +
14378 +       nfs4_lock_state();
14379 +
14380 +       /* find the lockowner */
14381 +        status = nfs_ok;
14382 +       for (i=0; i < LOCK_HASH_SIZE; i++) {
14383 +               list_for_each_safe(pos, next, &lock_ownerstr_hashtbl[i]) {
14384 +                       local = list_entry(pos, struct nfs4_stateowner, 
14385 +                                               so_strhash);
14386 +                       if(cmp_owner_str(local, owner, clid))
14387 +                               break;
14388 +               }
14389 +       }
14390 +       if (local) {
14391 +               struct nfs4_stateid *stp;
14392 +
14393 +               /* check for any locks held by any stateid associated with the 
14394 +                * (lock) stateowner */
14395 +               status = nfserr_locks_held;
14396 +               list_for_each_safe(pos, next, &local->so_perfilestate) {
14397 +                       stp = list_entry(pos, struct nfs4_stateid, 
14398 +                                                           st_perfilestate);
14399 +                       if(stp->st_vfs_set) {
14400 +                               if (check_for_locks(&stp->st_vfs_file, local))
14401 +                                       goto out;
14402 +                       }
14403 +               }
14404 +               /* no locks held by (lock) stateowner */
14405 +               status = nfs_ok;
14406 +               release_stateowner(local);
14407 +       }
14408 +out:
14409 +       nfs4_unlock_state();
14410 +       return status;
14411 +}
14412 +
14413  /* 
14414   * Start and stop routines
14415   */
14416 @@ -2128,6 +2399,7 @@ nfs4_state_init(void)
14417         memset(&zerostateid, 0, sizeof(stateid_t));
14418         memset(&onestateid, ~0, sizeof(stateid_t));
14419  
14420 +       INIT_LIST_HEAD(&close_lru);
14421         INIT_LIST_HEAD(&client_lru);
14422         init_MUTEX(&client_sema);
14423         boot_time = get_seconds();
14424 diff -puN fs/nfsd/nfs3xdr.c~CITI_NFS4_ALL fs/nfsd/nfs3xdr.c
14425 --- linux-2.6.3/fs/nfsd/nfs3xdr.c~CITI_NFS4_ALL 2004-02-19 16:47:08.000000000 -0500
14426 +++ linux-2.6.3-bfields/fs/nfsd/nfs3xdr.c       2004-02-19 16:47:08.000000000 -0500
14427 @@ -796,7 +796,7 @@ encode_entry(struct readdir_cd *ccd, con
14428         elen = slen + NFS3_ENTRY_BAGGAGE
14429                 + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
14430         if (cd->buflen < elen) {
14431 -               cd->common.err = nfserr_readdir_nospc;
14432 +               cd->common.err = nfserr_toosmall;
14433                 return -EINVAL;
14434         }
14435         *p++ = xdr_one;                          /* mark entry present */
14436 diff -puN fs/nfsd/nfsxdr.c~CITI_NFS4_ALL fs/nfsd/nfsxdr.c
14437 --- linux-2.6.3/fs/nfsd/nfsxdr.c~CITI_NFS4_ALL  2004-02-19 16:47:08.000000000 -0500
14438 +++ linux-2.6.3-bfields/fs/nfsd/nfsxdr.c        2004-02-19 16:47:08.000000000 -0500
14439 @@ -484,7 +484,7 @@ nfssvc_encode_entry(struct readdir_cd *c
14440  
14441         slen = XDR_QUADLEN(namlen);
14442         if ((buflen = cd->buflen - slen - 4) < 0) {
14443 -               cd->common.err = nfserr_readdir_nospc;
14444 +               cd->common.err = nfserr_toosmall;
14445                 return -EINVAL;
14446         }
14447         *p++ = xdr_one;                         /* mark entry present */
14448 diff -puN include/linux/nfs.h~CITI_NFS4_ALL include/linux/nfs.h
14449 --- linux-2.6.3/include/linux/nfs.h~CITI_NFS4_ALL       2004-02-19 16:47:08.000000000 -0500
14450 +++ linux-2.6.3-bfields/include/linux/nfs.h     2004-02-19 16:47:08.000000000 -0500
14451 @@ -92,7 +92,7 @@
14452         NFSERR_NOT_SAME = 10027,        /*       v4 */
14453         NFSERR_LOCK_RANGE = 10028,      /*       v4 */
14454         NFSERR_SYMLINK = 10029,         /*       v4 */
14455 -       NFSERR_READDIR_NOSPC = 10030,   /*       v4 */
14456 +       NFSERR_RESTOREFH = 10030,       /*       v4 */
14457         NFSERR_LEASE_MOVED = 10031,     /*       v4 */
14458         NFSERR_ATTRNOTSUPP = 10032,     /*       v4 */
14459         NFSERR_NO_GRACE = 10033,        /*       v4 */
14460 diff -puN include/linux/nfsd/nfsfh.h~CITI_NFS4_ALL include/linux/nfsd/nfsfh.h
14461 --- linux-2.6.3/include/linux/nfsd/nfsfh.h~CITI_NFS4_ALL        2004-02-19 16:47:10.000000000 -0500
14462 +++ linux-2.6.3-bfields/include/linux/nfsd/nfsfh.h      2004-02-19 16:47:10.000000000 -0500
14463 @@ -209,14 +209,6 @@ fh_copy(struct svc_fh *dst, struct svc_f
14464         return dst;
14465  }
14466  
14467 -static __inline__ void
14468 -fh_dup2(struct svc_fh *dst, struct svc_fh *src)
14469 -{
14470 -       fh_put(dst);
14471 -       dget(src->fh_dentry);
14472 -       *dst = *src;
14473 -}
14474 -
14475  static __inline__ struct svc_fh *
14476  fh_init(struct svc_fh *fhp, int maxsize)
14477  {
14478 diff -puN include/linux/sunrpc/xdr.h~CITI_NFS4_ALL include/linux/sunrpc/xdr.h
14479 --- linux-2.6.3/include/linux/sunrpc/xdr.h~CITI_NFS4_ALL        2004-02-19 16:47:15.000000000 -0500
14480 +++ linux-2.6.3-bfields/include/linux/sunrpc/xdr.h      2004-02-19 16:47:15.000000000 -0500
14481 @@ -225,6 +225,9 @@ xdr_reserve_space(struct xdr_stream *xdr
14482  extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
14483                 unsigned int base, unsigned int len);
14484  extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
14485 +int read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len);
14486 +int read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj);
14487 +
14488  
14489  /*
14490   * Initialize an xdr_stream for decoding data.
14491 diff -puN net/sunrpc/xdr.c~CITI_NFS4_ALL net/sunrpc/xdr.c
14492 --- linux-2.6.3/net/sunrpc/xdr.c~CITI_NFS4_ALL  2004-02-19 16:47:15.000000000 -0500
14493 +++ linux-2.6.3-bfields/net/sunrpc/xdr.c        2004-02-19 16:47:15.000000000 -0500
14494 @@ -799,7 +799,7 @@ xdr_buf_subsegment(struct xdr_buf *buf, 
14495  }
14496  
14497  /* obj is assumed to point to allocated memory of size at least len: */
14498 -static int
14499 +int
14500  read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len)
14501  {
14502         struct xdr_buf subbuf;
14503 @@ -824,7 +824,7 @@ out:
14504         return status;
14505  }
14506  
14507 -static int
14508 +int
14509  read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
14510  {
14511         u32     raw;
14512
14513 _