2 The complete series of citi nfsv4 patches in a single patch
12 fs/nfs/inode.c | 586 +++++----
13 fs/nfs/nfs3proc.c | 43
14 fs/nfs/nfs4proc.c | 988 +++++++---------
15 fs/nfs/nfs4xdr.c | 1931 ++++++++++++++++++++++++--------
20 fs/nfs/write.c | 207 +--
21 fs/nfs4acl/Makefile | 3
22 fs/nfs4acl/acl.c | 921 +++++++++++++++
23 fs/nfs4acl/acl_syms.c | 51
26 fs/nfsd/nfs4idmap.c | 569 +++++++++
27 fs/nfsd/nfs4proc.c | 229 ++-
28 fs/nfsd/nfs4state.c | 440 +++++--
29 fs/nfsd/nfs4xdr.c | 495 +++++---
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
71 net/sunrpc/svcauth.c | 5
72 net/sunrpc/svcauth_unix.c | 13
74 net/sunrpc/xprt.c | 210 +--
75 include/linux/sunrpc/name_lookup.h | 38
76 71 files changed, 7194 insertions(+), 2308 deletions(-)
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
86 +EXTRAVERSION = -CITI_NFS4_ALL-1
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
97 + if (IS_NOCMTIME(inode))
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.
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
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.
122 bool "Provide NFSv4 client support (EXPERIMENTAL)"
123 depends on NFS_FS && EXPERIMENTAL
124 + select RPCSEC_GSS_KRB5
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.
131 + Note: Requires auxiliary userspace daemons which may be found on
132 + http://www.citi.umich.edu/projects/nfsv4/
137 bool "Allow direct I/O on NFS files (EXPERIMENTAL)"
138 depends on NFS_FS && EXPERIMENTAL
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
145 bool "Provide NFSv4 server support (EXPERIMENTAL)"
146 depends on NFSD_V3 && EXPERIMENTAL
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
156 + bool "Provide NFSv4 ACL support"
157 + depends on NFSD_V4 || NFS_V4
159 + This allows you to use POSIX ACLs with NFSv4.
164 @@ -1431,28 +1442,24 @@ config SUNRPC
168 - tristate "Provide RPCSEC_GSS authentication (EXPERIMENTAL)"
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
180 - Provides cryptographic authentication for NFS rpc requests. To
181 - make this useful, you must also select at least one rpcsec_gss
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
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
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/
200 - Note: If you select this option, please ensure that you also
201 - enable the MD5 and DES crypto ciphers.
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 */
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;
227 dfprintk(VFS, "NFS: nfs_readdir_filler() reading cookie %Lu into page %lu.\n", (long long)desc->entry->cookie, page->index);
230 + timestamp = jiffies;
231 error = NFS_PROTO(inode)->readdir(file->f_dentry, cred, desc->entry->cookie, page,
232 NFS_SERVER(inode)->dtsize, desc->plus);
234 @@ -157,18 +163,21 @@ int nfs_readdir_filler(nfs_readdir_descr
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.
243 - if (page->index == 0)
244 + if (page->index == 0) {
245 invalidate_inode_pages(inode->i_mapping);
246 + NFS_I(inode)->readdir_timestamp = timestamp;
253 - invalidate_inode_pages(inode->i_mapping);
254 + nfs_zap_caches(inode);
258 @@ -381,6 +390,7 @@ int uncached_readdir(nfs_readdir_descrip
260 NFS_SERVER(inode)->dtsize,
262 + NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
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
270 - } else if (res < 0)
272 + if (res == -ETOOSMALL && desc->plus) {
273 + NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
274 + nfs_zap_caches(inode);
276 + desc->entry->eof = 0;
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.
288 -int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
289 +static inline int nfs_check_verifier(struct inode *dir, struct dentry *dentry)
293 - if (nfs_revalidate_inode(NFS_SERVER(dir), dir))
294 + if ((NFS_FLAGS(dir) & NFS_INO_INVALID_ATTR) != 0
295 + || nfs_attribute_timeout(dir))
297 - return time_after(dentry->d_time, NFS_MTIME_UPDATE(dir));
298 + return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata);
301 +static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf)
303 + dentry->d_fsdata = (void *)verf;
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))
311 - if (!nfs_check_verifier(dir, dentry))
313 - return time_after(jiffies, dentry->d_time + NFS_ATTRTIMEO(dir));
314 + return !nfs_check_verifier(dir, dentry);
318 @@ -552,6 +573,7 @@ static int nfs_lookup_revalidate(struct
320 struct nfs_fh fhandle;
321 struct nfs_fattr fattr;
322 + unsigned long verifier;
325 parent = dget_parent(dentry);
326 @@ -574,6 +596,9 @@ static int nfs_lookup_revalidate(struct
330 + /* Revalidate parent directory attribute cache */
331 + nfs_revalidate_inode(NFS_SERVER(dir), dir);
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
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.
345 + verifier = nfs_save_change_attribute(dir);
346 error = nfs_cached_lookup(dir, dentry, &fhandle, &fattr);
348 if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0)
349 @@ -603,6 +634,7 @@ static int nfs_lookup_revalidate(struct
352 nfs_renew_times(dentry);
353 + nfs_set_verifier(dentry, verifier);
357 @@ -638,6 +670,11 @@ static int nfs_dentry_delete(struct dent
358 /* Unhash it, so that ->d_iput() would be called */
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 */
369 @@ -693,6 +730,8 @@ static struct dentry *nfs_lookup(struct
370 dentry->d_op = NFS_PROTO(dir)->dentry_ops;
373 + /* Revalidate parent directory attribute cache */
374 + nfs_revalidate_inode(NFS_SERVER(dir), dir);
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:
380 d_add(dentry, inode);
381 nfs_renew_times(dentry);
382 + nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
386 @@ -768,7 +808,15 @@ static struct dentry *nfs_atomic_lookup(
388 /* Open the file on the server */
390 - inode = nfs4_atomic_open(dir, dentry, nd);
391 + /* Revalidate parent directory attribute cache */
392 + nfs_revalidate_inode(NFS_SERVER(dir), dir);
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);
399 + inode = nfs4_atomic_open(dir, dentry, nd);
402 error = PTR_ERR(inode);
403 @@ -790,6 +838,7 @@ static struct dentry *nfs_atomic_lookup(
405 d_add(dentry, inode);
406 nfs_renew_times(dentry);
407 + nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
410 return ERR_PTR(error);
411 @@ -801,13 +850,16 @@ static int nfs_open_revalidate(struct de
413 struct dentry *parent = NULL;
414 struct inode *inode = dentry->d_inode;
416 + unsigned long verifier;
417 int openflags, ret = 0;
419 /* NFS only supports OPEN for regular files */
420 if (inode && !S_ISREG(inode->i_mode))
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))
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);
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.
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);
443 + nfs_set_verifier(dentry, verifier);
447 @@ -869,15 +929,20 @@ int nfs_cached_lookup(struct inode *dir,
448 struct nfs_server *server;
449 struct nfs_entry entry;
451 - unsigned long timestamp = NFS_MTIME_UPDATE(dir);
452 + unsigned long timestamp;
455 if (!NFS_USE_READDIRPLUS(dir))
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))
464 - nfs_revalidate_inode(server, dir);
465 + if ((NFS_FLAGS(dir) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA)) != 0)
467 + timestamp = NFS_I(dir)->readdir_timestamp;
471 @@ -931,6 +996,7 @@ static int nfs_instantiate(struct dentry
473 d_instantiate(dentry, inode);
474 nfs_renew_times(dentry);
475 + nfs_set_verifier(dentry, nfs_save_change_attribute(dentry->d_parent->d_inode));
479 @@ -969,11 +1035,13 @@ static int nfs_create(struct inode *dir,
480 * does not pass the create flags.
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));
493 error = PTR_ERR(inode);
494 @@ -1004,9 +1072,10 @@ nfs_mknod(struct inode *dir, struct dent
495 attr.ia_valid = ATTR_MODE;
498 - nfs_zap_caches(dir);
499 + nfs_begin_data_update(dir);
500 error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev,
502 + nfs_end_data_update(dir);
504 error = nfs_instantiate(dentry, &fhandle, &fattr);
506 @@ -1041,9 +1110,10 @@ static int nfs_mkdir(struct inode *dir,
510 - nfs_zap_caches(dir);
511 + nfs_begin_data_update(dir);
512 error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
514 + nfs_end_data_update(dir);
516 error = nfs_instantiate(dentry, &fhandle, &fattr);
518 @@ -1060,10 +1130,12 @@ static int nfs_rmdir(struct inode *dir,
519 dir->i_ino, dentry->d_name.name);
522 - nfs_zap_caches(dir);
523 + nfs_begin_data_update(dir);
524 error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
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);
533 @@ -1119,12 +1191,21 @@ dentry->d_parent->d_name.name, dentry->d
535 } while(sdentry->d_inode != NULL); /* need negative lookup */
537 - nfs_zap_caches(dir);
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,
546 + nfs_end_data_update(dentry->d_inode);
548 + error = NFS_PROTO(dir)->rename(dir, &dentry->d_name,
550 + nfs_end_data_update(dir);
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
561 - nfs_zap_caches(dir);
563 - NFS_CACHEINV(inode);
564 - error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
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 */
576 + nfs_end_data_update(inode);
578 + error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
579 + nfs_end_data_update(dir);
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);
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)
596 @@ -1247,9 +1332,10 @@ dentry->d_parent->d_name.name, dentry->d
597 qsymname.len = strlen(symname);
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);
606 error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
608 @@ -1281,9 +1367,12 @@ nfs_link(struct dentry *old_dentry, stru
612 - nfs_zap_caches(dir);
613 - NFS_CACHEINV(inode);
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);
623 @@ -1388,16 +1477,23 @@ go_ahead:
625 d_delete(new_dentry);
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);
640 - if (!error && !S_ISDIR(old_inode->i_mode))
641 - d_move(old_dentry, new_dentry);
642 - nfs_renew_times(new_dentry);
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));
650 /* new dentry created? */
652 @@ -1451,7 +1547,8 @@ nfs_permission(struct inode *inode, int
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;
669 + nfs_begin_data_update(inode);
673 @@ -334,6 +335,8 @@ retry:
677 + nfs_end_data_update(inode);
678 + NFS_FLAGS(inode) |= NFS_INO_INVALID_DATA;
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,
689 +#ifdef CONFIG_NFS_V4
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 */
701 +#endif /* CONFIG_NFS_V4 */
703 /* Hack for future NFS swap support */
705 # define IS_SWAPFILE(inode) (0)
706 @@ -104,11 +118,16 @@ nfs_file_flush(struct file *file)
708 dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
710 + if ((file->f_mode & FMODE_WRITE) == 0)
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);
717 status = file->f_error;
720 + __nfs_revalidate_inode(NFS_SERVER(inode), inode);
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);
728 - status = nfs_wb_file(inode, file);
729 + status = nfs_wb_all(inode);
731 status = file->f_error;
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
738 #define NFS_MAX_READAHEAD RPC_MAXREQS
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);
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
748 int flags = sync ? FLUSH_WAIT : 0;
750 - nfs_commit_file(inode, NULL, 0, 0, flags);
751 + nfs_commit_inode(inode, 0, 0, flags);
755 @@ -136,21 +136,24 @@ nfs_delete_inode(struct inode * inode)
760 - * For the moment, the only task for the NFS clear_inode method is to
761 - * release the mmap credential
764 nfs_clear_inode(struct inode *inode)
766 struct nfs_inode *nfsi = NFS_I(inode);
767 struct rpc_cred *cred = nfsi->mm_cred;
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 */
777 cred = nfsi->cache_access.cred;
780 + BUG_ON(atomic_read(&nfsi->data_updates) != 0);
784 @@ -230,50 +233,23 @@ nfs_block_size(unsigned long bsize, unsi
786 * Obtain the root inode of the file system.
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)
793 struct nfs_server *server = NFS_SB(sb);
794 - struct nfs_fattr fattr = { };
795 + struct inode *rooti;
798 - error = server->rpc_ops->getroot(server, rootfh, &fattr);
799 - if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
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()).
805 - * We still want the mount to succeed.
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.
811 - dfprintk(VFS, "NFS: faking root inode\n");
814 - fattr.nlink = 2; /* minimum for a dir */
815 - fattr.type = NFDIR;
816 - fattr.mode = S_IFDIR|S_IRUGO|S_IXUGO;
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);
823 printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
824 - *rooti = NULL; /* superfluous ... but safe */
826 + return ERR_PTR(error);
829 - *rooti = nfs_fhget(sb, rootfh, &fattr);
830 - if (error == -EACCES && authflavor > RPC_AUTH_MAXFLAVOR) {
832 - NFS_FLAGS(*rooti) |= NFS_INO_FAKE_ROOT;
833 - NFS_CACHEINV((*rooti));
838 + rooti = nfs_fhget(sb, rootfh, fsinfo->fattr);
840 + return ERR_PTR(-ENOMEM);
845 @@ -283,7 +259,7 @@ static int
846 nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
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 = {
854 @@ -299,8 +275,9 @@ nfs_sb_init(struct super_block *sb, rpc_
856 sb->s_magic = NFS_SUPER_MAGIC;
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))
863 sb->s_root = d_alloc_root(root_inode);
865 @@ -309,10 +286,6 @@ nfs_sb_init(struct super_block *sb, rpc_
866 sb->s_root->d_op = server->rpc_ops->dentry_ops;
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");
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);
879 /* Yargs. It didn't work out. */
885 printk("nfs_read_super: get root inode failed\n");
887 + if (!IS_ERR(root_inode))
893 @@ -627,13 +598,17 @@ static int nfs_show_options(struct seq_f
895 nfs_zap_caches(struct inode *inode)
897 + struct nfs_inode *nfsi = NFS_I(inode);
898 + int mode = inode->i_mode;
900 NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
901 NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
903 - invalidate_remote_inode(inode);
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;
910 + nfsi->flags |= NFS_INO_INVALID_ATTR;
914 @@ -673,9 +648,6 @@ nfs_find_actor(struct inode *inode, void
916 if (is_bad_inode(inode))
918 - /* Force an attribute cache update if inode->i_count == 0 */
919 - if (!atomic_read(&inode->i_count))
920 - NFS_CACHEINV(inode);
924 @@ -729,12 +701,12 @@ nfs_fhget(struct super_block *sb, struct
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.
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;
955 unlock_new_inode(inode);
957 nfs_refresh_inode(inode, fattr);
958 @@ -804,70 +771,50 @@ nfs_setattr(struct dentry *dentry, struc
959 struct nfs_fattr fattr;
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;
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)
975 - * Make sure the inode is up-to-date.
977 - error = nfs_revalidate_inode(NFS_SERVER(inode),inode);
980 -printk("nfs_setattr: revalidate failed, error=%d\n", error);
985 - if (!S_ISREG(inode->i_mode)) {
986 - attr->ia_valid &= ~ATTR_SIZE;
987 - if (attr->ia_valid == 0)
990 - filemap_fdatawrite(inode->i_mapping);
991 - error = nfs_wb_all(inode);
992 - filemap_fdatawait(inode->i_mapping);
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);
1005 - if (!attr->ia_valid)
1008 error = NFS_PROTO(inode)->setattr(dentry, &fattr, attr);
1012 - * If we changed the size or mtime, update the inode
1013 - * now to avoid invalidating the page cache.
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);
1021 + nfs_refresh_inode(inode, &fattr);
1022 + if ((attr->ia_valid & ATTR_MODE) != 0) {
1024 + mode = inode->i_mode & ~S_IALLUGO;
1025 + mode |= attr->ia_mode & S_IALLUGO;
1026 + inode->i_mode = mode;
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);
1039 - * If we changed the size or mtime, update the inode
1040 - * now to avoid invalidating the page cache.
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;
1049 - /* Force an attribute cache update */
1050 - NFS_CACHEINV(inode);
1051 - error = nfs_refresh_inode(inode, &fattr);
1053 + if ((attr->ia_valid & (ATTR_MODE|ATTR_UID|ATTR_GID)) != 0) {
1054 + struct rpc_cred **cred = &NFS_I(inode)->cache_access.cred;
1056 + put_rpccred(*cred);
1060 + nfs_end_data_update(inode);
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)
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;
1073 + if (__IS_FLG(inode, MS_NOATIME))
1075 + else if (__IS_FLG(inode, MS_NODIRATIME) && S_ISDIR(inode->i_mode))
1077 + /* We may force a getattr if the user cares about atime */
1079 + err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
1081 + err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
1083 generic_fillattr(inode, stat);
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);
1097 @@ -940,6 +901,8 @@ int nfs_release(struct inode *inode, str
1098 struct rpc_cred *cred;
1101 + if ((filp->f_mode & FMODE_WRITE) != 0)
1102 + nfs_end_data_update(inode);
1103 cred = nfs_file_cred(filp);
1106 @@ -956,6 +919,9 @@ __nfs_revalidate_inode(struct nfs_server
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;
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
1118 if (NFS_STALE(inode) && inode != inode->i_sb->s_root->d_inode)
1120 - if (NFS_FAKE_ROOT(inode)) {
1121 - dfprintk(VFS, "NFS: not revalidating fake root\n");
1126 while (NFS_REVALIDATING(inode)) {
1127 status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
1130 - if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode))) {
1131 - status = NFS_STALE(inode) ? -ESTALE : 0;
1134 + if (NFS_SERVER(inode)->flags & NFS_MOUNT_NOAC)
1136 + if (NFS_FLAGS(inode) & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ATIME))
1138 + status = NFS_STALE(inode) ? -ESTALE : 0;
1141 NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
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);
1147 dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
1148 @@ -995,13 +960,36 @@ __nfs_revalidate_inode(struct nfs_server
1152 - status = nfs_refresh_inode(inode, &fattr);
1153 + status = nfs_update_inode(inode, &fattr, verifier);
1155 dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
1157 (long long)NFS_FILEID(inode), status);
1160 + flags = nfsi->flags;
1162 + * We may need to keep the attributes marked as invalid if
1163 + * we raced with nfs_end_attr_update().
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);
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++;
1183 dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
1185 (long long)NFS_FILEID(inode));
1186 @@ -1009,41 +997,104 @@ __nfs_revalidate_inode(struct nfs_server
1187 NFS_FLAGS(inode) &= ~NFS_INO_STALE;
1189 NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
1190 - wake_up(&NFS_I(inode)->nfs_i_wait);
1191 + wake_up(&nfsi->nfs_i_wait);
1198 - * nfs_fattr_obsolete - Test if attribute data is newer than cached data
1200 - * @fattr: attributes to test
1202 + * nfs_begin_data_update
1203 + * @inode - pointer to inode
1204 + * Declare that a set of operations will update file data on the server
1206 +void nfs_begin_data_update(struct inode *inode)
1208 + atomic_inc(&NFS_I(inode)->data_updates);
1212 + * nfs_end_data_update
1213 + * @inode - pointer to inode
1214 + * Declare end of the operations that will update file data
1216 +void nfs_end_data_update(struct inode *inode)
1218 + struct nfs_inode *nfsi = NFS_I(inode);
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;
1231 + * nfs_refresh_inode - verify consistency of the inode attribute cache
1232 + * @inode - pointer to inode
1233 + * @fattr - updated attributes
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.
1245 -int nfs_fattr_obsolete(struct inode *inode, struct nfs_fattr *fattr)
1246 +int nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
1248 struct nfs_inode *nfsi = NFS_I(inode);
1250 + loff_t cur_size, new_isize;
1251 + int data_unstable;
1253 + /* Are we in the process of updating data on the server? */
1254 + data_unstable = nfs_caches_unstable(inode);
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;
1264 + if ((fattr->valid & NFS_ATTR_FATTR) == 0)
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))
1272 - if (time_after(jiffies, nfsi->read_cache_jiffies + nfsi->attrtimeo))
1274 - cdif = fattr->ctime.tv_sec - nfsi->read_cache_ctime.tv_sec;
1276 - cdif = fattr->ctime.tv_nsec - nfsi->read_cache_ctime.tv_nsec;
1280 - if (cdif == 0 && fattr->size > nfsi->read_cache_isize)
1284 + cur_size = i_size_read(inode);
1285 + new_isize = nfs_size_to_loff_t(fattr->size);
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));
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;
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;
1309 + if (!timespec_equal(&inode->i_atime, &fattr->atime))
1310 + nfsi->flags |= NFS_INO_INVALID_ATIME;
1312 + nfsi->read_cache_jiffies = fattr->timestamp;
1316 @@ -1059,20 +1110,22 @@ int nfs_fattr_obsolete(struct inode *ino
1318 * A very similar scenario holds for the dir cache.
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)
1324 struct nfs_inode *nfsi = NFS_I(inode);
1328 - int mtime_update = 0;
1329 + unsigned int invalid = 0;
1331 + int data_unstable;
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);
1339 + if ((fattr->valid & NFS_ATTR_FATTR) == 0)
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,
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",
1353 inode->i_sb->s_id, (long long)nfsi->fileid,
1354 inode->i_sb->s_id, (long long)fattr->fileid);
1358 - /* Throw out obsolete READDIRPLUS attributes */
1359 - if (time_before(fattr->timestamp, NFS_READTIME(inode)))
1362 * Make sure the inode's type hasn't changed.
1364 if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
1367 - new_size = fattr->size;
1368 - new_isize = nfs_size_to_loff_t(fattr->size);
1371 - if (nfs_fattr_obsolete(inode, fattr))
1372 - goto out_nochange;
1375 * Update the read time so we don't revalidate too often.
1377 nfsi->read_cache_jiffies = fattr->timestamp;
1380 - * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache.
1381 - * NOT inode->i_size!!!
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);
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);
1397 + * If we have pending writebacks, things can get
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;
1406 + i_size_write(inode, new_isize);
1407 + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
1412 @@ -1125,12 +1184,13 @@ __nfs_refresh_inode(struct inode *inode,
1413 * can change this value in VFS without requiring a
1414 * cache revalidation.
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);
1424 + if (!data_unstable)
1425 + invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
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);
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.
1441 - if ((fattr->valid & NFS_ATTR_PRE_CHANGE)
1442 - && nfsi->change_attr == fattr->pre_change_attr) {
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)) {
1452 - * If we have pending writebacks, things can get
1455 - cur_isize = i_size_read(inode);
1456 - if (nfs_have_writebacks(inode) && new_isize < cur_isize)
1457 - new_isize = cur_isize;
1459 - nfsi->read_cache_ctime = fattr->ctime;
1460 - inode->i_ctime = fattr->ctime;
1461 - inode->i_atime = fattr->atime;
1463 - if (mtime_update) {
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;
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));
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,
1487 + invalid |= NFS_INO_INVALID_ATTR;
1490 - if (fattr->valid & NFS_ATTR_FATTR_V4)
1491 - nfsi->change_attr = fattr->change_attr;
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 */
1502 if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) {
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;
1509 - /* Update attrtimeo value */
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;
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;
1531 - if (!timespec_equal(&fattr->atime, &inode->i_atime))
1532 - inode->i_atime = fattr->atime;
1536 * Big trouble! The inode has become a different object.
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);
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,
1550 +#ifdef CONFIG_NFS_V4_ACL
1553 +nfs_setxattr(struct dentry *dentry, const char *key, const void *buf,
1554 + size_t buflen, int flags)
1556 + struct posix_acl *acl;
1558 + struct inode *inode = dentry->d_inode;
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;
1571 + if (!S_ISREG(inode->i_mode) &&
1572 + (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
1575 + if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
1578 + acl = posix_acl_from_xattr(buf, buflen);
1580 + return (PTR_ERR(acl));
1582 + return (-ENODATA);
1584 + error = posix_acl_valid(acl);
1588 + error = nfs4_proc_set_posix_acl(inode, type, acl);
1590 + posix_acl_release(acl);
1595 +nfs_getxattr(struct dentry *dentry, const char *key, void *buf,
1599 + struct inode *inode = dentry->d_inode;
1600 + struct posix_acl *acl;
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;
1614 + acl = nfs4_proc_get_posix_acl(inode, type);
1616 + return (PTR_ERR(acl));
1618 + ret = posix_acl_to_xattr(acl, buf, buflen);
1620 + posix_acl_release(acl);
1624 +#endif /* CONFIG_NFS_V4_ACL */
1626 #ifdef CONFIG_NFS_V4
1628 static void nfs4_clear_inode(struct inode *);
1629 @@ -1601,7 +1706,7 @@ static struct super_block *nfs4_get_sb(s
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");
1637 p = nfs_copy_user_string(NULL, &data->hostname, 256);
1638 @@ -1699,6 +1804,10 @@ static struct inode *nfs_alloc_inode(str
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;
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);
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
1665 -nfs3_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
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;
1674 - nfs_refresh_inode(inode, fattr);
1678 static struct rpc_cred *
1679 nfs_cred(struct inode *inode, struct file *filp)
1681 @@ -99,14 +85,18 @@ nfs_cred(struct inode *inode, struct fil
1684 nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
1685 - struct nfs_fattr *fattr)
1686 + struct nfs_fsinfo *info)
1690 - dprintk("NFS call getroot\n");
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);
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);
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;
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);
1718 - nfs3_write_refresh_inode(inode, fattr);
1719 + nfs_refresh_inode(inode, fattr);
1720 dprintk("NFS reply commit: %d\n", status);
1723 @@ -777,12 +767,13 @@ nfs3_proc_read_setup(struct nfs_read_dat
1725 nfs3_write_done(struct rpc_task *task)
1727 - struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
1728 + struct nfs_write_data *data;
1730 if (nfs3_async_handle_jukebox(task))
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);
1739 @@ -835,12 +826,13 @@ nfs3_proc_write_setup(struct nfs_write_d
1741 nfs3_commit_done(struct rpc_task *task)
1743 - struct nfs_write_data *data = (struct nfs_write_data *) task->tk_calldata;
1744 + struct nfs_write_data *data;
1746 if (nfs3_async_handle_jukebox(task))
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);
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>
1773 #define NFSDBG_FACILITY NFSDBG_PROC
1775 #define NFS4_POLL_RETRY_TIME (15*HZ)
1777 -#define GET_OP(cp,name) &cp->ops[cp->req_nops].u.name
1778 -#define OPNUM(cp) cp->ops[cp->req_nops].opnum
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[];
1785 extern nfs4_stateid zero_stateid;
1788 -nfs4_setup_compound(struct nfs4_compound *cp, struct nfs4_op *ops,
1789 - struct nfs_server *server, char *tag)
1791 - memset(cp, 0, sizeof(*cp));
1793 - cp->server = server;
1797 -nfs4_setup_access(struct nfs4_compound *cp, u32 req_access, u32 *resp_supported, u32 *resp_access)
1799 - struct nfs4_access *access = GET_OP(cp, access);
1801 - access->ac_req_access = req_access;
1802 - access->ac_resp_supported = resp_supported;
1803 - access->ac_resp_access = resp_access;
1805 - OPNUM(cp) = OP_ACCESS;
1810 -nfs4_setup_create_dir(struct nfs4_compound *cp, struct qstr *name,
1811 - struct iattr *sattr, struct nfs4_change_info *info)
1813 - struct nfs4_create *create = GET_OP(cp, create);
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;
1821 - OPNUM(cp) = OP_CREATE;
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)
1830 - struct nfs4_create *create = GET_OP(cp, create);
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;
1840 - OPNUM(cp) = OP_CREATE;
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)
1849 - int mode = sattr->ia_mode;
1850 - struct nfs4_create *create = GET_OP(cp, create);
1852 - BUG_ON(!(sattr->ia_valid & ATTR_MODE));
1853 - BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
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);
1862 - else if (S_ISCHR(mode)) {
1863 - create->cr_ftype = NF4CHR;
1864 - create->cr_specdata1 = MAJOR(dev);
1865 - create->cr_specdata2 = MINOR(dev);
1868 - create->cr_ftype = NF4SOCK;
1870 - create->cr_namelen = name->len;
1871 - create->cr_name = name->name;
1872 - create->cr_attrs = sattr;
1873 - create->cr_cinfo = info;
1875 - OPNUM(cp) = OP_CREATE;
1880 * This is our standard bitmap for GETATTR requests.
1882 @@ -181,126 +89,15 @@ u32 nfs4_statfs_bitmap[2] = {
1883 | FATTR4_WORD1_SPACE_TOTAL
1886 -u32 nfs4_pathconf_bitmap[2] = {
1887 - FATTR4_WORD0_MAXLINK
1888 - | FATTR4_WORD0_MAXNAME,
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)
1898 - struct nfs4_getattr *getattr = GET_OP(cp, getattr);
1900 - getattr->gt_bmval = bitmap;
1901 - getattr->gt_attrs = fattr;
1902 - getattr->gt_fsstat = fsstat;
1903 - getattr->gt_pathconf = pathconf;
1905 - OPNUM(cp) = OP_GETATTR;
1910 -nfs4_setup_getattr(struct nfs4_compound *cp,
1911 - struct nfs_fattr *fattr)
1913 - __nfs4_setup_getattr(cp, nfs4_fattr_bitmap, fattr,
1918 -nfs4_setup_statfs(struct nfs4_compound *cp,
1919 - struct nfs_fsstat *fsstat)
1921 - __nfs4_setup_getattr(cp, nfs4_statfs_bitmap,
1922 - NULL, fsstat, NULL);
1926 -nfs4_setup_pathconf(struct nfs4_compound *cp,
1927 - struct nfs_pathconf *pathconf)
1929 - __nfs4_setup_getattr(cp, nfs4_pathconf_bitmap,
1930 - NULL, NULL, pathconf);
1934 -nfs4_setup_getfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
1936 - struct nfs4_getfh *getfh = GET_OP(cp, getfh);
1938 - getfh->gf_fhandle = fhandle;
1940 - OPNUM(cp) = OP_GETFH;
1945 -nfs4_setup_link(struct nfs4_compound *cp, struct qstr *name,
1946 - struct nfs4_change_info *info)
1948 - struct nfs4_link *link = GET_OP(cp, link);
1950 - link->ln_namelen = name->len;
1951 - link->ln_name = name->name;
1952 - link->ln_cinfo = info;
1954 - OPNUM(cp) = OP_LINK;
1959 -nfs4_setup_lookup(struct nfs4_compound *cp, struct qstr *q)
1961 - struct nfs4_lookup *lookup = GET_OP(cp, lookup);
1963 - lookup->lo_name = q;
1965 - OPNUM(cp) = OP_LOOKUP;
1970 -nfs4_setup_putfh(struct nfs4_compound *cp, struct nfs_fh *fhandle)
1972 - struct nfs4_putfh *putfh = GET_OP(cp, putfh);
1974 - putfh->pf_fhandle = fhandle;
1976 - OPNUM(cp) = OP_PUTFH;
1981 -nfs4_setup_putrootfh(struct nfs4_compound *cp)
1983 - OPNUM(cp) = OP_PUTROOTFH;
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)
1993 - struct nfs4_readdir *readdir = GET_OP(cp, readdir);
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));
2007 - OPNUM(cp) = OP_READDIR;
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.
2017 - start = p = (u32 *)kmap_atomic(*pages, KM_USER0);
2018 + start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0);
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));
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);
2034 -nfs4_setup_readlink(struct nfs4_compound *cp, int count, struct page **pages)
2036 - struct nfs4_readlink *readlink = GET_OP(cp, readlink);
2038 - readlink->rl_count = count;
2039 - readlink->rl_pages = pages;
2041 - OPNUM(cp) = OP_READLINK;
2046 -nfs4_setup_remove(struct nfs4_compound *cp, struct qstr *name, struct nfs4_change_info *cinfo)
2048 - struct nfs4_remove *remove = GET_OP(cp, remove);
2050 - remove->rm_namelen = name->len;
2051 - remove->rm_name = name->name;
2052 - remove->rm_cinfo = cinfo;
2054 - OPNUM(cp) = OP_REMOVE;
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)
2062 - struct nfs4_rename *rename = GET_OP(cp, rename);
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;
2071 - OPNUM(cp) = OP_RENAME;
2076 -nfs4_setup_restorefh(struct nfs4_compound *cp)
2078 - OPNUM(cp) = OP_RESTOREFH;
2083 -nfs4_setup_savefh(struct nfs4_compound *cp)
2085 - OPNUM(cp) = OP_SAVEFH;
2090 renew_lease(struct nfs_server *server, unsigned long timestamp)
2092 struct nfs4_client *clp = server->nfs4_state;
2093 @@ -409,47 +150,6 @@ renew_lease(struct nfs_server *server, u
2097 -process_lease(struct nfs4_compound *cp)
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
2108 - * (1) renewd doesn't acquire the spinlock when messing with
2109 - * server->last_renewal; this is OK since rpciod always runs
2111 - * (2) cp->timestamp was set at the end of XDR encode.
2113 - if (!cp->renew_index)
2115 - if (!cp->toplevel_status || cp->resp_nops > cp->renew_index)
2116 - renew_lease(cp->server, cp->timestamp);
2120 -nfs4_call_compound(struct nfs4_compound *cp, struct rpc_cred *cred, int flags)
2123 - struct rpc_message msg = {
2124 - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COMPOUND],
2130 - status = rpc_call_sync(cp->server->client, &msg, flags);
2132 - process_lease(cp);
2138 process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr)
2140 BUG_ON((fattr->valid & NFS_ATTR_FATTR) == 0);
2141 @@ -476,11 +176,6 @@ nfs4_open_reclaim(struct nfs4_state_owne
2144 struct nfs4_change_info d_cinfo;
2145 - struct nfs4_getattr f_getattr = {
2146 - .gt_bmval = nfs4_fattr_bitmap,
2147 - .gt_attrs = &fattr,
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,
2159 struct nfs_openres o_res = {
2160 - .cinfo = &d_cinfo,
2161 - .f_getattr = &f_getattr,
2162 + .cinfo = &d_cinfo,
2164 .server = server, /* Grrr */
2166 struct rpc_message msg = {
2167 @@ -528,28 +222,18 @@ nfs4_do_open(struct inode *dir, struct q
2168 struct nfs_fattr f_attr = {
2171 - struct nfs4_getattr f_getattr = {
2172 - .gt_bmval = nfs4_fattr_bitmap,
2173 - .gt_attrs = &f_attr,
2175 - struct nfs4_getattr d_getattr = {
2176 - .gt_bmval = nfs4_fattr_bitmap,
2177 - .gt_attrs = &d_attr,
2179 struct nfs_openargs o_arg = {
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,
2185 - .f_getattr = &f_getattr,
2186 - .d_getattr = &d_getattr,
2189 struct nfs_openres o_res = {
2191 - .f_getattr = &f_getattr,
2192 - .d_getattr = &d_getattr,
2193 + .f_attr = &f_attr,
2194 + .d_attr = &d_attr,
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)
2202 - struct nfs4_getattr getattr = {
2203 - .gt_bmval = nfs4_fattr_bitmap,
2204 - .gt_attrs = fattr,
2206 struct nfs_setattrargs arg = {
2213 struct nfs_setattrres res = {
2218 struct rpc_message msg = {
2219 @@ -822,27 +502,43 @@ nfs4_open_revalidate(struct inode *dir,
2222 nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
2223 - struct nfs_fattr *fattr)
2224 + struct nfs_fsinfo *info)
2226 - struct nfs4_compound compound;
2227 - struct nfs4_op ops[4];
2228 + struct nfs_fattr * fattr = info->fattr;
2232 + struct nfs4_getroot_arg args = {
2233 + .fhandle = fhandle,
2236 + struct nfs4_getroot_res res = {
2239 + .fhandle = fhandle,
2241 + struct rpc_message msg_head = {
2242 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETROOT_HEAD],
2246 + struct rpc_message msg_path = {
2247 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETROOT_PATH],
2248 + .rpc_argp = &args,
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...
2257 - p = server->mnt_path;
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);
2268 + p = server->mnt_path;
2272 @@ -854,12 +550,7 @@ nfs4_proc_get_root(struct nfs_server *se
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);
2285 if (status == -ENOENT) {
2286 @@ -869,21 +560,27 @@ nfs4_proc_get_root(struct nfs_server *se
2293 + return nfs4_proc_fsinfo(server, fhandle, info);
2297 nfs4_proc_getattr(struct inode *inode, struct nfs_fattr *fattr)
2299 - struct nfs4_compound compound;
2300 - struct nfs4_op ops[2];
2302 + struct nfs4_getattr_res res = {
2304 + .server = NFS_SERVER(inode),
2306 + struct rpc_message msg = {
2307 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR],
2308 + .rpc_argp = NFS_FH(inode),
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);
2322 @@ -945,26 +642,218 @@ out:
2326 +#ifdef CONFIG_NFS_V4_ACL
2329 +nfs_name_to_uid_wrapper(void *arg, const char *name, size_t len, __u32 *id)
2331 + return nfs_map_name_to_uid((struct nfs4_client *)arg, name, len, id);
2335 +nfs_name_to_gid_wrapper(void *arg, const char *name, size_t len, __u32 *id)
2337 + return nfs_map_group_to_gid((struct nfs4_client*)arg, name, len, id);
2341 +nfs_uid_to_name_wrapper(void *arg, __u32 id, char *name)
2343 + return nfs_map_uid_to_name((struct nfs4_client *)arg, id, name);
2347 +nfs_gid_to_name_wrapper(void *arg, __u32 id, char *name)
2349 + return nfs_map_gid_to_group((struct nfs4_client *)arg, id, name);
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,
2359 +/* From fs/ext2/acl.c: */
2361 +static inline struct posix_acl *
2362 +nfs4_iget_acl(struct inode *inode, struct posix_acl **i_acl)
2364 + struct posix_acl *acl = NFS4_ACL_NOT_CACHED;
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);
2374 +nfs4_iset_acl(struct inode *inode, struct posix_acl **i_acl,
2375 + struct posix_acl *acl)
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);
2385 +nfs4_izap_acl(struct inode *inode, struct posix_acl **i_acl)
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);
2395 +nfs4_proc_get_posix_acl(struct inode *inode, int type)
2397 + struct nfs4_acl *acl = NULL;
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),
2407 + error = nfs_revalidate_inode(NFS_SERVER(inode), inode);
2410 + return ERR_PTR(error);
2412 + if (type == ACL_TYPE_ACCESS)
2413 + ret = nfs4_iget_acl(inode, &NFS_I(inode)->acl);
2415 + ret = nfs4_iget_acl(inode, &NFS_I(inode)->default_acl);
2417 + if (ret != NFS4_ACL_NOT_CACHED) {
2419 + ret = ERR_PTR(-ENODATA);
2424 + error = rpc_call_sync(NFS_CLIENT(inode), &msg, 0);
2434 + error = nfs4_acl_nfsv4_to_posix(&nfs4_idmapper, NFS_SERVER(inode)->nfs4_state, acl, &pacl, &dpacl);
2439 + if (pacl && pacl->a_count > NFS_ACL_MAX_ENTRIES)
2441 + if (dpacl && dpacl->a_count > NFS_ACL_MAX_ENTRIES)
2444 + nfs4_iset_acl(inode, &NFS_I(inode)->acl, pacl);
2445 + nfs4_iset_acl(inode, &NFS_I(inode)->default_acl, dpacl);
2447 + ret = (type == ACL_TYPE_ACCESS) ? pacl : dpacl;
2454 + ret = ERR_PTR(error);
2455 + nfs4_acl_free(acl);
2460 +nfs4_proc_set_posix_acl(struct inode *inode, int type, struct posix_acl *pacl)
2463 + struct nfs4_acl *acl;
2464 + struct nfs_fattr fattr;
2466 + struct nfs_setaclargs arg = {
2467 + .fh = NFS_FH(inode),
2469 + struct rpc_message msg = {
2470 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETACL],
2478 + if (pacl && pacl->a_count > NFS_ACL_MAX_ENTRIES)
2481 + if (type == ACL_TYPE_ACCESS)
2482 + acl = nfs4_acl_posix_to_nfsv4(&nfs4_idmapper, NFS_SERVER(inode)->nfs4_state, pacl, NULL);
2484 + acl = nfs4_acl_posix_to_nfsv4(&nfs4_idmapper, NFS_SERVER(inode)->nfs4_state, NULL, pacl);
2486 + return PTR_ERR(acl);
2490 + error = rpc_call_sync(NFS_SERVER(inode)->client, &msg, 0);
2493 + nfs4_acl_free(acl);
2498 + if (type == ACL_TYPE_ACCESS)
2499 + nfs4_iset_acl(inode, &NFS_I(inode)->acl, pacl);
2501 + nfs4_iset_acl(inode, &NFS_I(inode)->default_acl, pacl);
2503 + if (type == ACL_TYPE_ACCESS)
2504 + posix_acl_equiv_mode(pacl, &inode->i_mode);
2509 +#endif /* CONFIG_NFS_V4_ACL */
2512 nfs4_proc_lookup(struct inode *dir, struct qstr *name,
2513 struct nfs_fh *fhandle, struct nfs_fattr *fattr)
2515 - struct nfs4_compound compound;
2516 - struct nfs4_op ops[5];
2517 - struct nfs_fattr dir_attr;
2520 + struct nfs_fattr dir_attr;
2522 + struct nfs4_lookupargs args = {
2523 + .dir_fh = NFS_FH(dir),
2526 + struct nfs4_lookupres res = {
2527 + .server = NFS_SERVER(dir),
2528 + .dirattr = &dir_attr,
2530 + .fhandle = fhandle,
2532 + struct rpc_message msg = {
2533 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
2534 + .rpc_argp = &args,
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);
2553 @@ -975,11 +864,24 @@ nfs4_proc_lookup(struct inode *dir, stru
2555 nfs4_proc_access(struct inode *inode, struct rpc_cred *cred, int mode)
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;
2562 + struct nfs4_accessargs args = {
2563 + .fhandle = NFS_FH(inode),
2565 + struct nfs4_accessres res = {
2566 + .server = NFS_SERVER(inode),
2568 + .resp_supported = &resp_supported,
2569 + .resp_access = &resp_access,
2571 + struct rpc_message msg = {
2572 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ACCESS],
2573 + .rpc_argp = &args,
2580 @@ -1000,12 +902,9 @@ nfs4_proc_access(struct inode *inode, st
2581 if (mode & MAY_EXEC)
2582 req_access |= NFS4_ACCESS_EXECUTE;
2584 + res.req_access = args.req_access = req_access;
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);
2595 @@ -1046,13 +945,18 @@ nfs4_proc_access(struct inode *inode, st
2597 nfs4_proc_readlink(struct inode *inode, struct page *page)
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,
2606 + struct rpc_message msg = {
2607 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READLINK],
2608 + .rpc_argp = &args,
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);
2620 @@ -1088,12 +992,8 @@ nfs4_proc_read(struct nfs_read_data *rda
2623 status = rpc_call_sync(server->client, &msg, flags);
2626 renew_lease(server, timestamp);
2627 - /* Check cache consistency */
2628 - if (fattr->change_attr != NFS_CHANGE_ATTR(inode))
2629 - nfs_zap_caches(inode);
2631 dprintk("NFS reply read: %d\n", status);
2634 @@ -1130,7 +1030,6 @@ nfs4_proc_write(struct nfs_write_data *w
2637 status = rpc_call_sync(server->client, &msg, rpcflags);
2638 - NFS_CACHEINV(inode);
2639 dprintk("NFS reply write: %d\n", status);
2642 @@ -1217,18 +1116,26 @@ nfs4_proc_create(struct inode *dir, stru
2644 nfs4_proc_remove(struct inode *dir, struct qstr *name)
2646 - struct nfs4_compound compound;
2647 - struct nfs4_op ops[3];
2648 struct nfs4_change_info dir_cinfo;
2649 struct nfs_fattr dir_attr;
2651 + struct nfs4_remove_arg args = {
2652 + .fhandle = NFS_FH(dir),
2655 + struct nfs4_remove_res res = {
2656 + .server = NFS_SERVER(dir),
2657 + .dir_cinfo = &dir_cinfo,
2658 + .dir_attr = &dir_attr,
2660 + struct rpc_message msg = {
2661 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_REMOVE],
2662 + .rpc_argp = &args,
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);
2675 process_cinfo(&dir_cinfo, &dir_attr);
2676 @@ -1237,32 +1144,22 @@ nfs4_proc_remove(struct inode *dir, stru
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;
2688 nfs4_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name)
2690 - struct unlink_desc * up;
2691 - struct nfs4_compound * cp;
2692 + struct nfs4_unlink *up;
2694 - up = (struct unlink_desc *) kmalloc(sizeof(*up), GFP_KERNEL);
2695 + up = (struct nfs4_unlink *) kmalloc(sizeof(*up), GFP_KERNEL);
2698 - cp = &up->compound;
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);
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);
2712 + msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_UNLINK];
2713 + msg->rpc_argp = up;
2714 + msg->rpc_resp = up;
2718 @@ -1270,11 +1167,10 @@ static int
2719 nfs4_proc_unlink_done(struct dentry *dir, struct rpc_task *task)
2721 struct rpc_message *msg = &task->tk_msg;
2722 - struct unlink_desc *up;
2723 + struct nfs4_unlink *up;
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);
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)
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;
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,
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,
2755 + struct rpc_message msg = {
2756 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME],
2761 old_dir_attr.valid = 0;
2762 new_dir_attr.valid = 0;
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);
2776 process_cinfo(&old_cinfo, &old_dir_attr);
2777 @@ -1318,24 +1222,30 @@ nfs4_proc_rename(struct inode *old_dir,
2779 nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
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;
2787 + struct nfs4_link_arg arg = {
2788 + .fh = NFS_FH(inode),
2789 + .dir_fh = NFS_FH(dir),
2792 + struct nfs4_link_res res = {
2793 + .server = NFS_SERVER(inode),
2795 + .dir_attr = &dir_attr,
2796 + .dir_cinfo = &dir_cinfo,
2798 + struct rpc_message msg = {
2799 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LINK],
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);
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)
2824 - struct nfs4_compound compound;
2825 - struct nfs4_op ops[7];
2826 struct nfs_fattr dir_attr;
2827 struct nfs4_change_info dir_cinfo;
2829 + struct nfs4_create_arg arg = {
2830 + .dir_fh = NFS_FH(dir),
2831 + .server = NFS_SERVER(dir),
2833 + .u.symlink = path,
2837 + struct nfs4_create_res res = {
2838 + .server = NFS_SERVER(dir),
2839 + .fhandle = fhandle,
2841 + .dir_attr = &dir_attr,
2842 + .dir_cinfo = &dir_cinfo,
2844 + struct rpc_message msg = {
2845 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
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);
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)
2870 - struct nfs4_compound compound;
2871 - struct nfs4_op ops[7];
2872 struct nfs_fattr dir_attr;
2873 struct nfs4_change_info dir_cinfo;
2875 + struct nfs4_create_arg arg = {
2876 + .dir_fh = NFS_FH(dir),
2877 + .server = NFS_SERVER(dir),
2882 + struct nfs4_create_res res = {
2883 + .server = NFS_SERVER(dir),
2884 + .fhandle = fhandle,
2886 + .dir_attr = &dir_attr,
2887 + .dir_cinfo = &dir_cinfo,
2889 + struct rpc_message msg = {
2890 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
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);
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)
2914 struct inode *dir = dentry->d_inode;
2915 - struct nfs4_compound compound;
2916 - struct nfs4_op ops[2];
2918 + struct nfs4_readdir_arg args = {
2919 + .fh = NFS_FH(dir),
2924 + struct nfs4_readdir_res res;
2925 + struct rpc_message msg = {
2926 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READDIR],
2927 + .rpc_argp = &args,
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);
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);
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)
2949 - struct nfs4_compound compound;
2950 - struct nfs4_op ops[7];
2951 struct nfs_fattr dir_attr;
2952 struct nfs4_change_info dir_cinfo;
2954 + int mode = sattr->ia_mode;
2955 + struct nfs4_create_arg arg = {
2956 + .dir_fh = NFS_FH(dir),
2957 + .server = NFS_SERVER(dir),
2961 + struct nfs4_create_res res = {
2962 + .server = NFS_SERVER(dir),
2965 + .dir_attr = &dir_attr,
2966 + .dir_cinfo = &dir_cinfo,
2968 + struct rpc_message msg = {
2969 + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
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);
2986 + else if (S_ISCHR(mode)) {
2987 + arg.ftype = NF4CHR;
2988 + arg.u.device.specdata1 = MAJOR(rdev);
2989 + arg.u.device.specdata2 = MINOR(rdev);
2992 + arg.ftype = NF4SOCK;
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);
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)
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,
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);
3028 @@ -1480,7 +1442,6 @@ nfs4_proc_fsinfo(struct nfs_server *serv
3032 - memset(fsinfo, 0, sizeof(*fsinfo));
3033 return rpc_call_sync(server->client, &msg, 0);
3036 @@ -1488,14 +1449,13 @@ static int
3037 nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
3038 struct nfs_pathconf *pathconf)
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,
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);
3057 @@ -1517,7 +1477,6 @@ nfs4_read_done(struct rpc_task *task)
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;
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)
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);
3077 @@ -1577,21 +1531,6 @@ nfs4_proc_read_setup(struct nfs_read_dat
3081 -nfs4_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
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;
3096 nfs4_restart_write(struct rpc_task *task)
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)
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);
3107 @@ -1684,7 +1622,6 @@ nfs4_commit_done(struct rpc_task *task)
3108 task->tk_action = nfs4_restart_write;
3111 - nfs4_write_refresh_inode(inode, data->res.fattr);
3112 /* Call back common NFS writeback processing */
3113 nfs_commit_done(task);
3115 @@ -1807,6 +1744,7 @@ nfs4_proc_file_open(struct inode *inode,
3116 if (filp->f_mode & FMODE_WRITE) {
3118 nfs_set_mmcred(inode, state->owner->so_cred);
3119 + nfs_begin_data_update(inode);
3122 filp->private_data = state;
3123 @@ -1823,6 +1761,11 @@ nfs4_proc_file_release(struct inode *ino
3126 nfs4_close_state(state, filp->f_mode);
3127 + if (filp->f_mode & FMODE_WRITE) {
3129 + nfs_end_data_update(inode);
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.
3154 @@ -258,7 +257,6 @@ nfs_coalesce_requests(struct list_head *
3157 nfs_scan_list(struct list_head *head, struct list_head *dst,
3158 - struct file *file,
3159 unsigned long idx_start, unsigned int npages)
3161 struct list_head *pos, *tmp;
3162 @@ -276,9 +274,6 @@ nfs_scan_list(struct list_head *head, st
3164 req = nfs_list_entry(pos);
3166 - if (file && req->wb_file != file)
3169 if (req->wb_index < idx_start)
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
3177 extern struct rpc_procinfo nfs_procedures[];
3180 -nfs_write_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
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;
3188 - nfs_refresh_inode(inode, fattr);
3191 static struct rpc_cred *
3192 nfs_cred(struct inode *inode, struct file *filp)
3194 @@ -78,15 +66,33 @@ nfs_cred(struct inode *inode, struct fil
3197 nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
3198 - struct nfs_fattr *fattr)
3199 + struct nfs_fsinfo *info)
3202 + struct nfs_fattr *fattr = info->fattr;
3203 + struct nfs2_fsstat fsinfo;
3206 - dprintk("NFS call getroot\n");
3207 + dprintk("%s: call getattr\n", __FUNCTION__);
3209 - status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
3210 - dprintk("NFS reply getroot\n");
3212 + status = rpc_call(server->client_sys, NFSPROC_GETATTR, fhandle, fattr, 0);
3213 + dprintk("%s: reply getattr %d\n", __FUNCTION__, 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);
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;
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);
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;
3243 @@ -331,10 +337,8 @@ nfs_proc_unlink_done(struct dentry *dir,
3245 struct rpc_message *msg = &task->tk_msg;
3247 - if (msg->rpc_argp) {
3248 - NFS_CACHEINV(dir->d_inode);
3249 + if (msg->rpc_argp)
3250 kfree(msg->rpc_argp);
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;
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);
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 */
3279 + NFS_FLAGS(inode) |= NFS_INO_INVALID_ATIME;
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);
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);
3298 + nfs_begin_data_update(dir->d_inode);
3299 rpc_call_setup(task, &msg, 0);
3302 @@ -126,7 +127,7 @@ nfs_async_unlink_done(struct rpc_task *t
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))
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
3315 static struct nfs_page * nfs_update_request(struct file*, struct inode *,
3317 unsigned int, unsigned int);
3318 -static void nfs_strategy(struct inode *inode);
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);
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)
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;
3333 + if (i_size > 0 && page->index < end_index)
3335 + end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count);
3336 + if (i_size >= end)
3338 + i_size_write(inode, end);
3341 +/* We can set the PG_uptodate flag if we see that a write request
3342 + * covers the full page.
3344 +static void nfs_mark_uptodate(struct page *page, unsigned int base, unsigned int count)
3348 + if (PageUptodate(page))
3352 + if (count == PAGE_CACHE_SIZE) {
3353 + SetPageUptodate(page);
3357 + end_offs = i_size_read(page->mapping->host) - 1;
3360 + /* Is this the last page? */
3361 + if (page->index != (unsigned long)(end_offs >> PAGE_CACHE_SHIFT))
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.
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);
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));
3379 + nfs_begin_data_update(inode);
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;
3389 - * If we've extended the file, update the inode
3390 - * now so we don't invalidate the cache.
3392 - if (wdata.args.offset > i_size_read(inode))
3393 - i_size_write(inode, wdata.args.offset);
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);
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)
3406 struct nfs_page *req;
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;
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);
3428 @@ -286,7 +331,7 @@ nfs_writepages(struct address_space *map
3429 err = generic_writepages(mapping, wbc);
3432 - err = nfs_flush_file(inode, NULL, 0, 0, 0);
3433 + err = nfs_flush_inode(inode, 0, 0, 0);
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);
3441 - nfs_commit_file(inode, NULL, 0, 0, 0);
3442 + nfs_commit_inode(inode, 0, 0, 0);
3446 @@ -312,8 +357,10 @@ nfs_inode_add_request(struct inode *inod
3447 BUG_ON(error == -EEXIST);
3450 - if (!nfsi->npages)
3451 + if (!nfsi->npages) {
3453 + nfs_begin_data_update(inode);
3458 @@ -336,6 +383,7 @@ nfs_inode_remove_request(struct nfs_page
3460 if (!nfsi->npages) {
3461 spin_unlock(&nfs_wreq_lock);
3462 + nfs_end_data_update(inode);
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.
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)
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
3478 next = req->wb_index + 1;
3479 - if (file && req->wb_file != file)
3481 if (!NFS_WBACK_BUSY(req))
3484 @@ -453,7 +499,6 @@ nfs_wait_on_requests(struct inode *inode
3487 spin_lock(&nfs_wreq_lock);
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.
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.
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)
3507 struct nfs_inode *nfsi = NFS_I(inode);
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.
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.
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)
3529 struct nfs_inode *nfsi = NFS_I(inode);
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
3541 - * This is the strategy routine for NFS.
3542 - * It is called by nfs_updatepage whenever the user wrote up to the end
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
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.
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.
3557 - * FIXME: Different servers may have different sweet spots.
3558 - * Record the average congestion window in server struct?
3560 -#define NFS_STRATEGY_PAGES 8
3562 -nfs_strategy(struct inode *inode)
3564 - unsigned int dirty, wpages;
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);
3575 - if (dirty >= NFS_STRATEGY_PAGES * wpages)
3576 - nfs_flush_file(inode, NULL, 0, 0, 0);
3581 nfs_flush_incompatible(struct file *file, struct page *page)
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;
3590 dprintk("NFS: nfs_updatepage(%s/%s %d@%Ld)\n",
3591 @@ -696,6 +698,30 @@ nfs_updatepage(struct file *file, struct
3595 + nfs_begin_data_update(inode);
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.
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;
3608 + if (end_offs < 0) {
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)
3615 + } else if (page->index < end_index)
3616 + count = PAGE_CACHE_SIZE;
3620 * Try to find an NFS request corresponding to this page
3622 @@ -714,21 +740,14 @@ nfs_updatepage(struct file *file, struct
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);
3630 - /* If we wrote past the end of the page.
3631 - * Call the strategy routine so it can send out a bunch
3634 - if (req->wb_pgbase == 0 && req->wb_bytes == PAGE_CACHE_SIZE) {
3635 - SetPageUptodate(page);
3636 - nfs_unlock_request(req);
3637 - nfs_strategy(inode);
3639 - nfs_unlock_request(req);
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);
3647 + nfs_end_data_update(inode);
3648 dprintk("NFS: nfs_updatepage returns %d (isize %Ld)\n",
3649 status, (long long)i_size_read(inode));
3651 @@ -891,10 +910,7 @@ nfs_writeback_done(struct rpc_task *task
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
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)
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)
3672 @@ -1069,7 +1085,7 @@ int nfs_flush_file(struct inode *inode,
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);
3680 error = nfs_flush_list(&head, NFS_SERVER(inode)->wpages, how);
3681 @@ -1079,7 +1095,7 @@ int nfs_flush_file(struct inode *inode,
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)
3690 @@ -1087,9 +1103,9 @@ int nfs_commit_file(struct inode *inode,
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);
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);
3702 @@ -1100,7 +1116,7 @@ int nfs_commit_file(struct inode *inode,
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)
3711 @@ -1109,18 +1125,15 @@ int nfs_sync_file(struct inode *inode, s
3712 wait = how & FLUSH_WAIT;
3715 - if (!inode && file)
3716 - inode = file->f_dentry->d_inode;
3721 - error = nfs_wait_on_requests(inode, file, idx_start, npages);
3722 + error = nfs_wait_on_requests(inode, idx_start, npages);
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)
3728 - error = nfs_commit_file(inode, file, idx_start, npages, how);
3729 + error = nfs_commit_inode(inode, idx_start, npages, how);
3731 } while (error > 0);
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 */
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)
3747 #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD)
3748 +#define IS_NOCMTIME(inode) ((inode)->i_flags & S_NOCMTIME)
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
3756 #include <linux/sunrpc/auth.h>
3757 #include <linux/sunrpc/clnt.h>
3759 +#ifdef CONFIG_NFS_V4
3760 +#include <linux/xattr_acl.h>
3761 +#endif /* CONFIG_NFS_V4 */
3763 #include <linux/nfs.h>
3764 #include <linux/nfs2.h>
3765 #include <linux/nfs3.h>
3766 @@ -99,7 +103,7 @@ struct nfs_inode {
3770 - unsigned short flags;
3771 + unsigned int flags;
3774 * read_cache_jiffies is when we started read-caching this inode,
3775 @@ -118,19 +122,22 @@ struct nfs_inode {
3777 * mtime != read_cache_mtime
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 */
3788 + /* "Generation counter" for the attribute cache. This is
3789 + * bumped whenever we update the metadata on the
3792 + unsigned long cache_change_attribute;
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.
3799 - unsigned long cache_mtime_jiffies;
3800 + atomic_t data_updates;
3802 struct nfs_access_cache cache_access;
3804 @@ -160,7 +167,10 @@ struct nfs_inode {
3806 struct list_head open_states;
3807 #endif /* CONFIG_NFS_V4*/
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;
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 */
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) \
3838 - NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
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 { \
3845 #define NFS_FILEID(inode) (NFS_I(inode)->fileid)
3847 +static inline int nfs_caches_unstable(struct inode *inode)
3849 + return atomic_read(&NFS_I(inode)->data_updates) != 0;
3852 +static inline void NFS_CACHEINV(struct inode *inode)
3854 + if (!nfs_caches_unstable(inode))
3855 + NFS_FLAGS(inode) |= NFS_INO_INVALID_ATTR;
3858 static inline int nfs_server_capable(struct inode *inode, int cap)
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;
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.
3871 +static inline long nfs_save_change_attribute(struct inode *inode)
3873 + return NFS_I(inode)->cache_change_attribute;
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.
3883 +static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long chattr)
3885 + return !nfs_caches_unstable(inode)
3886 + && chattr == NFS_I(inode)->cache_change_attribute;
3890 * linux/fs/nfs/inode.c
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 *);
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
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);
3926 @@ -333,7 +376,7 @@ nfs_have_writebacks(struct inode *inode)
3928 nfs_wb_all(struct inode *inode)
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;
3935 @@ -343,21 +386,11 @@ nfs_wb_all(struct inode *inode)
3937 nfs_wb_page(struct inode *inode, struct page* page)
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;
3946 - * Write back all pending writes for one user..
3949 -nfs_wb_file(struct inode *inode, struct file *file)
3951 - int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT);
3952 - return (error < 0) ? error : 0;
3955 /* Hack for future NFS swap support */
3957 # define IS_SWAPFILE(inode) (0)
3958 @@ -383,20 +416,27 @@ extern int nfsroot_mount(struct sockadd
3963 -nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
3965 +static inline int nfs_attribute_timeout(struct inode *inode)
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);
3972 + return time_after(jiffies, nfsi->read_cache_jiffies+nfsi->attrtimeo);
3976 -nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
3978 + * nfs_revalidate_inode - Revalidate the inode attributes
3979 + * @server - pointer to nfs_server struct
3980 + * @inode - pointer to inode struct
3982 + * Updates inode attribute information by retrieving the data from the server.
3984 +static inline int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
3986 - if ((fattr->valid & NFS_ATTR_FATTR) == 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);
3995 static inline loff_t
3996 @@ -590,6 +630,15 @@ struct nfs4_state {
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;
4002 +#define NFS_ACL_MAX_ENTRIES 32
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);
4008 +#define NFS4_ACL_NOT_CACHED ((void *)-1)
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);
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 *);
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 *,
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 */
4046 #define NFS_ATTR_WCC 0x0001 /* pre-op WCC data */
4047 @@ -103,8 +106,6 @@ struct nfs_openargs {
4048 nfs4_verifier verifier; /* EXCLUSIVE */
4051 - struct nfs4_getattr * f_getattr;
4052 - struct nfs4_getattr * d_getattr;
4053 struct nfs_server * server; /* Needed for ID mapping */
4056 @@ -113,8 +114,8 @@ struct nfs_openres {
4058 struct nfs4_change_info * cinfo;
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;
4067 @@ -141,7 +142,6 @@ struct nfs_open_reclaimargs {
4071 - struct nfs4_getattr * f_getattr;
4075 @@ -319,12 +319,22 @@ struct nfs_setattrargs {
4077 nfs4_stateid stateid;
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 */
4087 +#ifdef CONFIG_NFS_V4
4088 +struct nfs_setaclargs {
4089 + struct nfs_fh * fh;
4090 + struct nfs4_acl * acl;
4092 +#endif /* CONFIG_NFS_V4 */
4094 struct nfs_setattrres {
4095 - struct nfs4_getattr * attr;
4096 + struct nfs_fattr * fattr;
4097 struct nfs_server * server;
4100 @@ -482,118 +492,127 @@ struct nfs4_change_info {
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;
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;
4120 + u32 * resp_supported;
4121 + u32 * resp_access;
4124 -struct nfs4_create {
4125 - u32 cr_ftype; /* request */
4126 - union { /* request */
4129 - const char * text;
4130 - } symlink; /* NF4LNK */
4131 +struct nfs4_create_arg {
4134 + struct qstr * symlink; /* NF4LNK */
4138 } device; /* NF4BLK, NF4CHR */
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;
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
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;
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;
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;
4184 -struct nfs4_lookup {
4185 - struct qstr * lo_name; /* request */
4186 +struct nfs4_getroot_arg {
4187 + struct nfs_fh * fhandle;
4188 + struct qstr * name;
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 */
4200 - struct qstr * op_name; /* request */
4201 - char * op_stateid; /* response */
4202 - struct nfs4_change_info * op_cinfo; /* response */
4203 - u32 * op_rflags; /* response */
4205 -#define op_attrs u.attrs
4206 -#define op_verifier u.verifier
4208 -struct nfs4_open_confirm {
4209 - char * oc_stateid; /* request */
4212 -struct nfs4_putfh {
4213 - struct nfs_fh * pf_fhandle; /* request */
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;
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;
4237 +struct nfs4_lookupargs {
4238 + struct nfs_fh * dir_fh;
4239 + struct qstr * name;
4242 +struct nfs4_lookupres {
4243 + struct nfs_server * server;
4244 + struct nfs_fattr * dirattr;
4245 + struct nfs_fattr * fattr;
4246 + struct nfs_fh * fhandle;
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 */
4258 +struct nfs4_readdir_res {
4259 + nfs4_verifier resp_verifier;
4260 + unsigned int pgbase;
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 */
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;
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;
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;
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;
4311 struct nfs4_setclientid {
4312 @@ -606,52 +625,12 @@ struct nfs4_setclientid {
4313 struct nfs4_client * sc_state; /* response */
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;
4338 -struct nfs4_compound {
4339 - unsigned int flags; /* defined below */
4340 - struct nfs_server * server;
4342 - /* RENEW information */
4344 - unsigned long timestamp;
4346 - /* scratch variables for XDR encode/decode */
4351 - /* the individual COMPOUND operations */
4352 - struct nfs4_op *ops;
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 */
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;
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 *,
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. */
4395 struct list_head rq_list;
4397 struct xdr_buf rq_private_buf; /* The receive buffer
4398 * used in the softirq.
4402 * For authentication (e.g. auth_des)
4404 @@ -155,6 +156,11 @@ struct rpc_xprt {
4405 stream : 1; /* TCP */
4410 + __u32 xid; /* Next XID value to use */
4413 * State of TCP reply receive stuff
4415 u32 tcp_recm, /* Fragment header */
4416 @@ -164,6 +170,11 @@ struct rpc_xprt {
4417 unsigned long tcp_copied, /* copied to request */
4420 + * Connection of sockets
4422 + struct work_struct sock_connect;
4423 + unsigned short port;
4425 * Disconnection of idle sockets
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
4432 #include <linux/sunrpc/clnt.h>
4433 #include <linux/file.h>
4434 #include <linux/workqueue.h>
4435 +#include <linux/random.h>
4437 #include <net/sock.h>
4438 #include <net/checksum.h>
4441 #define XPRT_MAX_BACKOFF (8)
4442 #define XPRT_IDLE_TIMEOUT (5*60*HZ)
4443 +#define XPRT_MAX_RESVPORT (800)
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 *);
4456 @@ -455,6 +457,68 @@ out_abort:
4457 spin_unlock(&xprt->sock_lock);
4461 +xprt_socket_connect(void *args)
4463 + struct rpc_xprt *xprt = (struct rpc_xprt *)args;
4464 + struct socket *sock = xprt->sock;
4465 + int status = -EIO;
4467 + if (xprt->shutdown) {
4468 + rpc_wake_up_status(&xprt->pending, -EIO);
4471 + if (!xprt->addr.sin_port)
4475 + * Start by resetting any existing state
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 */
4485 + xprt_bind_socket(xprt, sock);
4486 + xprt_sock_setbufsize(xprt);
4488 + if (!xprt->stream)
4492 + * Tell the socket layer to start connecting...
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);
4501 + case -EINPROGRESS:
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);
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);
4519 + spin_unlock_bh(&xprt->sock_lock);
4523 * Attempt to connect a TCP socket.
4525 @@ -463,9 +527,6 @@ void
4526 xprt_connect(struct rpc_task *task)
4528 struct rpc_xprt *xprt = task->tk_xprt;
4529 - struct socket *sock = xprt->sock;
4530 - struct sock *inet;
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)
4537 task->tk_rqstp->rq_bytes_sent = 0;
4540 - * We're here because the xprt was marked disconnected.
4541 - * Start by resetting any existing state.
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;
4550 - xprt_bind_socket(xprt, sock);
4551 - xprt_sock_setbufsize(xprt);
4553 - if (!xprt->stream)
4559 - * Tell the socket layer to start connecting...
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);
4570 - case -EINPROGRESS:
4572 - /* Protect against TCP socket state changes */
4574 - if (inet->sk_state != TCP_ESTABLISHED) {
4575 - dprintk("RPC: %4d waiting for connection\n",
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,
4585 - release_sock(inet);
4587 - case -ECONNREFUSED:
4590 - if (!RPC_IS_SOFT(task)) {
4591 - rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
4592 - task->tk_status = -ENOTCONN;
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;
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;
4612 + task->tk_timeout = RPC_CONNECT_TIMEOUT;
4613 + rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL);
4614 + schedule_work(&xprt->sock_connect);
4617 xprt_release_write(xprt, task);
4618 @@ -583,6 +574,8 @@ xprt_connect_status(struct rpc_task *tas
4619 task->tk_status = -EIO;
4621 switch (task->tk_status) {
4622 + case -ECONNREFUSED:
4625 rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
4627 @@ -1333,22 +1326,14 @@ do_xprt_reserve(struct rpc_task *task)
4629 * Allocate a 'unique' XID
4632 -xprt_alloc_xid(void)
4633 +static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
4635 + return xprt->xid++;
4638 +static inline void xprt_init_xid(struct rpc_xprt *xprt)
4640 - static spinlock_t xid_lock = SPIN_LOCK_UNLOCKED;
4641 - static int need_init = 1;
4645 - spin_lock(&xid_lock);
4646 - if (unlikely(need_init)) {
4647 - xid = get_seconds() << 12;
4651 - spin_unlock(&xid_lock);
4653 + get_random_bytes(&xprt->xid, sizeof(xprt->xid));
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,
4667 @@ -1457,11 +1443,13 @@ xprt_setup(int proto, struct sockaddr_in
4668 init_waitqueue_head(&xprt->cong_wait);
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;
4679 /* Set timeout parameters */
4681 @@ -1481,6 +1469,8 @@ xprt_setup(int proto, struct sockaddr_in
4682 req->rq_next = NULL;
4683 xprt->free = xprt->slot;
4685 + xprt_init_xid(xprt);
4687 /* Check whether we want to use a reserved port */
4688 xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
4690 @@ -1493,30 +1483,28 @@ xprt_setup(int proto, struct sockaddr_in
4691 * Bind to a reserved port
4694 -xprt_bindresvport(struct socket *sock)
4695 +xprt_bindresvport(struct rpc_xprt *xprt, struct socket *sock)
4697 - struct sockaddr_in myaddr;
4698 + struct sockaddr_in myaddr = {
4699 + .sin_family = AF_INET,
4702 - kernel_cap_t saved_cap = current->cap_effective;
4704 - /* Override capabilities.
4705 - * They were checked in xprt_create_proto i.e. at mount time
4707 - cap_raise(current->cap_effective, CAP_NET_BIND_SERVICE);
4709 - memset(&myaddr, 0, sizeof(myaddr));
4710 - myaddr.sin_family = AF_INET;
4712 + /* Were we already bound to a given port? Try to reuse it */
4713 + port = xprt->port;
4715 myaddr.sin_port = htons(port);
4716 err = sock->ops->bind(sock, (struct sockaddr *) &myaddr,
4718 - } while (err == -EADDRINUSE && --port > 0);
4719 - current->cap_effective = saved_cap;
4722 - printk("RPC: Can't bind to reserved port (%d).\n", -err);
4724 + xprt->port = port;
4728 + port = XPRT_MAX_RESVPORT;
4729 + } while (err == -EADDRINUSE && port != xprt->port);
4731 + printk("RPC: Can't bind to reserved port (%d).\n", -err);
4735 @@ -1580,7 +1568,7 @@ xprt_sock_setbufsize(struct rpc_xprt *xp
4736 * and connect stream sockets.
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)
4742 struct socket *sock;
4744 @@ -1596,7 +1584,7 @@ xprt_create_socket(int proto, struct rpc
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");
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)
4758 if (current_detail && current_index < current_detail->hash_size) {
4759 struct cache_head *ch, **cp;
4760 + struct cache_detail *d;
4762 write_lock(¤t_detail->hash_lock);
4764 @@ -354,12 +355,14 @@ int cache_clean(void)
4767 write_unlock(¤t_detail->hash_lock);
4769 - current_detail->cache_put(ch, current_detail);
4771 + d = current_detail;
4775 - spin_unlock(&cache_list_lock);
4776 + spin_unlock(&cache_list_lock);
4778 + d->cache_put(ch, d);
4780 + spin_unlock(&cache_list_lock);
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 {
4789 * If an entry is found, it is returned
4790 * If no entry is found, a new non-VALID entry is created.
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
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.
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; \
4809 head = &(DETAIL)->hash_table[HASHFN]; \
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) \
4820 cache_get(&tmp->MEMBER); \
4822 if (!INPLACE && test_bit(CACHE_VALID, &tmp->MEMBER.flags))\
4823 @@ -203,6 +207,7 @@ RTN *FNAME ARGS \
4825 /* Didn't find anything */ \
4828 new->MEMBER.next = *head; \
4829 *head = &new->MEMBER; \
4830 (DETAIL)->entries ++; \
4831 @@ -224,8 +229,6 @@ RTN *FNAME ARGS \
4833 cache_init(&new->MEMBER); \
4834 cache_get(&new->MEMBER); \
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,
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);
4852 new=item; atomic_inc(&new->h.refcnt),
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
4860 static inline void ip_map_init(struct ip_map *new, struct ip_map *item)
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;
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
4872 - ipm.m_class = class;
4873 + ipm.m_class = strdup(class);
4874 + if (ipm.m_class == NULL)
4877 htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4);
4879 @@ -207,6 +210,7 @@ static int ip_map_parse(struct cache_det
4880 ip_map_put(&ipmp->h, &ip_map_cache);
4882 auth_domain_put(dom);
4883 + if (ipm.m_class) kfree(ipm.m_class);
4887 @@ -266,7 +270,9 @@ int auth_unix_add_addr(struct in_addr ad
4888 if (dom->flavour != RPC_AUTH_UNIX)
4890 udom = container_of(dom, struct unix_domain, h);
4891 - ip.m_class = "nfsd";
4892 + ip.m_class = strdup("nfsd");
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;
4901 ipmp = ip_map_lookup(&ip, 1);
4902 + if (ip.m_class) kfree(ip.m_class);
4904 ip_map_put(&ipmp->h, &ip_map_cache);
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
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>
4917 @@ -39,14 +40,11 @@ struct svc_stat nfsd_svcstats = {
4918 .program = &nfsd_program,
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)
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",
4934 nfsdstats.rcnocache,
4935 @@ -58,57 +56,42 @@ nfsd_proc_read(char *buffer, char **star
4937 nfsdstats.io_write);
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);
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');
4957 + /* show my rpc info */
4958 + svc_seq_show(seq, &nfsd_svcstats);
4960 - /* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
4964 - * Append generic nfsd RPC statistics if there's room for it.
4966 - if (len <= offset) {
4967 - len = svc_proc_read(buffer, start, offset - len, count,
4972 - if (len < count) {
4973 - len += svc_proc_read(buffer + len, start, 0, count - len,
4977 - if (offset >= len) {
4984 - *start = buffer + offset;
4985 - if ((len -= offset) > count)
4988 +static int nfsd_proc_open(struct inode *inode, struct file *file)
4990 + return single_open(file, nfsd_proc_show, NULL);
4993 +static struct file_operations nfsd_proc_fops = {
4994 + .owner = THIS_MODULE,
4995 + .open = nfsd_proc_open,
4997 + .llseek = seq_lseek,
4998 + .release = single_release,
5002 nfsd_stat_init(void)
5004 - struct proc_dir_entry *ent;
5006 - if ((ent = svc_proc_register(&nfsd_svcstats)) != 0) {
5007 - ent->read_proc = nfsd_proc_read;
5008 - ent->owner = THIS_MODULE;
5010 + svc_proc_register(&nfsd_svcstats, &nfsd_proc_fops);
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,
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,
5030 -void svc_proc_zero(struct svc_program *);
5032 +void svc_seq_show(struct seq_file *,
5033 + const struct svc_stat *);
5035 extern struct proc_dir_entry *proc_net_rpc;
5037 @@ -63,13 +62,14 @@ extern struct proc_dir_entry *proc_net_r
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) {}
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) {}
5051 +static inline void svc_seq_show(struct seq_file *seq,
5052 + const struct svc_stat *st) {}
5054 #define proc_net_rpc NULL
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
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>
5067 @@ -28,70 +29,66 @@ struct proc_dir_entry *proc_net_rpc = NU
5069 * Get RPC client stats
5072 -rpc_proc_read(char *buffer, char **start, off_t offset, int count,
5073 - int *eof, void *data)
5075 - struct rpc_stat *statp = (struct rpc_stat *) data;
5076 - struct rpc_program *prog = statp->program;
5077 - struct rpc_version *vers;
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;
5084 - len = sprintf(buffer,
5086 "net %d %d %d %d\n",
5091 - len += sprintf(buffer + len,
5096 statp->rpcauthrefresh);
5098 for (i = 0; i < prog->nrvers; i++) {
5099 - if (!(vers = prog->version[i]))
5100 + const struct rpc_version *vers = prog->version[i];
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');
5116 - if (offset >= len) {
5121 - *start = buffer + offset;
5122 - if ((len -= offset) > count)
5126 +static int rpc_proc_open(struct inode *inode, struct file *file)
5128 + return single_open(file, rpc_proc_show, PDE(inode)->data);
5131 +static struct file_operations rpc_proc_fops = {
5132 + .owner = THIS_MODULE,
5133 + .open = rpc_proc_open,
5135 + .llseek = seq_lseek,
5136 + .release = single_release,
5140 * Get RPC server stats
5143 -svc_proc_read(char *buffer, char **start, off_t offset, int count,
5144 - int *eof, void *data)
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;
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;
5157 - len = sprintf(buffer,
5159 "net %d %d %d %d\n",
5164 - len += sprintf(buffer + len,
5166 "rpc %d %d %d %d %d\n",
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))
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');
5182 - if (offset >= len) {
5187 - *start = buffer + offset;
5188 - if ((len -= offset) > count)
5195 * Register/unregister RPC proc files
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)
5201 + struct proc_dir_entry *ent;
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,
5209 + ent = create_proc_entry(name, 0, proc_net_rpc);
5211 + ent->proc_fops = fops;
5217 struct proc_dir_entry *
5218 rpc_proc_register(struct rpc_stat *statp)
5220 - return do_register(statp->program->name, statp, 0);
5221 + return do_register(statp->program->name, statp, &rpc_proc_fops);
5225 @@ -146,9 +138,9 @@ rpc_proc_unregister(const char *name)
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)
5232 - return do_register(statp->program->pg_name, statp, 1);
5233 + return do_register(statp->program->pg_name, statp, fops);
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);
5244 ent->owner = THIS_MODULE;
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);
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);
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;
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);
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",
5286 @@ -151,7 +151,7 @@ krb5_make_token(struct krb5_ctx *ctx, in
5287 md5cksum.data + md5cksum.len - KRB5_CKSUM_LENGTH,
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);
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);
5298 if (md5cksum.data) kfree(md5cksum.data);
5299 - if (token->data) kfree(token->data);
5302 return GSS_S_FAILURE;
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 */
5311 -#define GSS_SEQ_WIN 5
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 *);
5323 +/* Similar, but get by name like "krb5", "spkm", etc., instead of OID. */
5324 +struct gss_api_mech *gss_mech_get_by_name(char *);
5326 /* Just increments the mechanism's reference count and returns its input: */
5327 struct gss_api_mech * gss_mech_get(struct gss_api_mech *);
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
5334 + * linux/include/linux/svcauth_gss.h
5336 + * Bruce Fields <bfields@umich.edu>
5337 + * Copyright (c) 2002 The Regents of the Unviersity of Michigan
5339 + * Id: linux-2.6.3-CITI_NFS4_ALL.patch,v 1.2.4.1 2004/03/17 23:55:23 adilger Exp $
5343 +#ifndef _LINUX_SUNRPC_SVCAUTH_GSS_H
5344 +#define _LINUX_SUNRPC_SVCAUTH_GSS_H
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>
5354 +int gss_svc_init(void);
5355 +int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
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: */
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
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
5384 #define SVC_DENIED 7
5385 #define SVC_PENDING 8
5386 +#define SVC_COMPLETE 9
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 {
5395 void * rq_argp; /* decoded arguments */
5396 void * rq_resp; /* xdr'd results */
5397 + void * rq_auth_data; /* flavor-specific data */
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
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:
5416 - dprintk("RPC: gss_parse_init_downcall returning %d\n", err);
5417 + dprintk("RPC: gss_parse_init_downcall returning %d\n", err);
5421 @@ -310,8 +311,10 @@ __gss_find_upcall(struct gss_auth *gss_a
5422 if (pos->uid != uid)
5424 atomic_inc(&pos->count);
5425 + dprintk("RPC: gss_find_upcall found msg %p\n", pos);
5428 + dprintk("RPC: gss_find_upcall found nothing\n");
5432 @@ -349,6 +352,8 @@ gss_upcall(struct rpc_clnt *clnt, struct
5433 uid_t uid = cred->cr_uid;
5436 + dprintk("RPC: %4u gss_upcall for uid %u\n", task->tk_pid, uid);
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);
5447 + dprintk("RPC: %4u gss_upcall -ENOMEM\n", task->tk_pid);
5453 @@ -388,10 +395,12 @@ retry:
5454 spin_unlock(&gss_auth->lock);
5456 gss_release_msg(gss_msg);
5457 + dprintk("RPC: %4u gss_upcall for uid %u result %d", task->tk_pid,
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);
5468 @@ -476,12 +485,13 @@ gss_pipe_downcall(struct file *filp, con
5470 spin_unlock(&gss_auth->lock);
5471 rpc_release_client(clnt);
5472 + dprintk("RPC: gss_pipe_downcall returning length %u\n", mlen);
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);
5483 @@ -519,6 +529,8 @@ gss_pipe_destroy_msg(struct rpc_pipe_msg
5484 static unsigned long ratelimit;
5486 if (msg->errno < 0) {
5487 + dprintk("RPC: gss_pipe_destroy_msg releasing msg %p\n",
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;
5496 - dprintk("RPC: creating GSS authenticator for client %p\n",clnt);
5497 + dprintk("RPC: creating GSS authenticator for client %p\n",clnt);
5499 if (!(gss_auth = kmalloc(sizeof(*gss_auth), GFP_KERNEL)))
5501 gss_auth->mech = gss_pseudoflavor_to_mech(flavor);
5502 @@ -581,7 +594,8 @@ static void
5503 gss_destroy(struct rpc_auth *auth)
5505 struct gss_auth *gss_auth;
5506 - dprintk("RPC: destroying GSS authenticator %p flavor %d\n",
5508 + dprintk("RPC: destroying GSS authenticator %p flavor %d\n",
5509 auth, auth->au_flavor);
5511 gss_auth = container_of(auth, struct gss_auth, rpc_auth);
5512 @@ -596,8 +610,7 @@ gss_destroy(struct rpc_auth *auth)
5514 gss_destroy_ctx(struct gss_cl_ctx *ctx)
5517 - dprintk("RPC: gss_destroy_ctx\n");
5518 + dprintk("RPC: gss_destroy_ctx\n");
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)
5524 struct gss_cred *cred = (struct gss_cred *)rc;
5526 - dprintk("RPC: gss_destroy_cred \n");
5527 + dprintk("RPC: gss_destroy_cred \n");
5530 gss_put_ctx(cred->gc_ctx);
5531 @@ -628,7 +641,7 @@ gss_create_cred(struct rpc_auth *auth, s
5533 struct gss_cred *cred = NULL;
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);
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;
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);
5549 @@ -659,6 +672,15 @@ gss_match(struct auth_cred *acred, struc
5550 return (rc->cr_uid == acred->uid);
5554 +shift_seqnos(u32 *seqnos)
5558 + for (i=1; i < GSS_SEQNO_CACHE; i++)
5559 + seqnos[i] = seqnos[i-1];
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;
5569 - dprintk("RPC: gss_marshal\n");
5570 + dprintk("RPC: %4u gss_marshal\n", task->tk_pid);
5572 *p++ = htonl(RPC_AUTH_GSS);
5575 service = gss_pseudoflavor_to_service(gss_cred->gc_flavor);
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);
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);
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)
5601 +verify_checksum(struct gss_ctx *ctx, struct xdr_netobj *mic, u32 *seqnos)
5603 + u32 seq, qop_state;
5604 + struct xdr_buf verf_buf;
5608 + for (i=0; i < GSS_SEQNO_CACHE; i++) {
5609 + if (i && !seqnos[i])
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))
5621 + /* So unwrap knows which seqno we used: */
5622 + seqnos[0] = seqnos[i];
5627 gss_validate(struct rpc_task *task, u32 *p)
5629 @@ -752,28 +801,21 @@ gss_validate(struct rpc_task *task, u32
5630 struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
5632 struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
5633 - u32 seq, qop_state;
5635 - struct xdr_buf verf_buf;
5636 struct xdr_netobj mic;
5640 - dprintk("RPC: gss_validate\n");
5641 + dprintk("RPC: %4u gss_validate\n", task->tk_pid);
5644 if ((len = ntohl(*p++)) > RPC_MAX_AUTH_SIZE)
5646 if (flav != RPC_AUTH_GSS)
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);
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))
5659 service = gss_pseudoflavor_to_service(gss_cred->gc_flavor);
5661 @@ -789,9 +831,12 @@ gss_validate(struct rpc_task *task, u32
5665 + dprintk("RPC: %4u GSS gss_validate: gss_verify_mic succeeded.\n",
5667 return p + XDR_QUADLEN(len);
5670 + dprintk("RPC: %4u gss_validate failed.\n", task->tk_pid);
5674 @@ -814,7 +859,7 @@ gss_wrap_req(struct rpc_task *task,
5678 - dprintk("RPC: gss_wrap_body\n");
5679 + dprintk("RPC: %4u gss_wrap_req\n", task->tk_pid);
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,
5686 offset = (u8 *)p - (u8 *)snd_buf->head[0].iov_base;
5687 - *p++ = htonl(req->rq_seqno);
5688 + *p++ = htonl(req->rq_seqnos[0]);
5690 status = encode(rqstp, p, obj);
5692 @@ -871,7 +916,7 @@ gss_wrap_req(struct rpc_task *task,
5696 - dprintk("RPC: gss_wrap_req returning %d\n", status);
5697 + dprintk("RPC: %4u gss_wrap_req returning %d\n", task->tk_pid, status);
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)
5705 - if (ntohl(*p++) != req->rq_seqno)
5706 + if (ntohl(*p++) != req->rq_seqnos[0])
5709 if (xdr_buf_subsegment(rcv_buf, &integ_buf, data_offset,
5710 @@ -932,7 +977,8 @@ out_decode:
5711 status = decode(rqstp, p, obj);
5714 - dprintk("RPC: gss_unwrap_resp returning %d\n", status);
5715 + dprintk("RPC: %4u gss_unwrap_resp returning %d\n", task->tk_pid,
5720 @@ -972,6 +1018,15 @@ static int __init init_rpcsec_gss(void)
5723 err = rpcauth_register(&authgss_ops);
5726 + err = gss_svc_init();
5728 + goto out_unregister;
5731 + rpcauth_unregister(&authgss_ops);
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
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;
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;
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;
5760 ctx_id->internal_ctx_id = ctx;
5761 - dprintk("Succesfully imported new context.\n");
5762 + dprintk("RPC: Succesfully imported new context.\n");
5766 @@ -195,7 +197,7 @@ gss_verify_mic_kerberos(struct gss_ctx
5767 if (!maj_stat && qop_state)
5768 *qstate = qop_state;
5770 - dprintk("RPC: gss_verify_mic_kerberos returning %d\n", maj_stat);
5771 + dprintk("RPC: gss_verify_mic_kerberos returning %d\n", maj_stat);
5775 @@ -209,7 +211,7 @@ gss_get_mic_kerberos(struct gss_ctx *ctx
5777 err = krb5_make_token(kctx, qop, message, mic_token, KG_TOK_MIC_MSG);
5779 - dprintk("RPC: gss_get_mic_kerberos returning %d\n",err);
5780 + dprintk("RPC: gss_get_mic_kerberos returning %d\n",err);
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");
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
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>
5805 # define RPCDBG_FACILITY RPCDBG_AUTH
5806 @@ -82,7 +81,7 @@ gss_mech_register(struct xdr_netobj * me
5807 spin_lock(®istered_mechs_lock);
5808 list_add(&gm->gm_list, ®istered_mechs);
5809 spin_unlock(®istered_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);
5815 @@ -94,11 +93,10 @@ do_gss_mech_unregister(struct gss_api_me
5817 list_del(&gm->gm_list);
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");
5829 @@ -146,7 +144,7 @@ gss_mech_get_by_OID(struct xdr_netobj *m
5831 struct gss_api_mech *pos, *gm = NULL;
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(®istered_mechs_lock);
5837 list_for_each_entry(pos, ®istered_mechs, gm_list) {
5838 @@ -158,10 +156,27 @@ gss_mech_get_by_OID(struct xdr_netobj *m
5841 spin_unlock(®istered_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");
5847 +struct gss_api_mech *
5848 +gss_mech_get_by_name(char *name)
5850 + struct gss_api_mech *pos, *gm = NULL;
5852 + spin_lock(®istered_mechs_lock);
5853 + list_for_each_entry(pos, ®istered_mechs, gm_list) {
5854 + if (0 == strcmp(name, pos->gm_ops->name)) {
5855 + gm = gss_mech_get(pos);
5859 + spin_unlock(®istered_mechs_lock);
5865 gss_mech_put(struct gss_api_mech * gm)
5867 @@ -228,7 +243,8 @@ gss_verify_mic(struct gss_ctx *context_
5869 gss_delete_sec_context(struct gss_ctx **context_handle)
5871 - dprintk("gss_delete_sec_context deleting %p\n",*context_handle);
5872 + dprintk("RPC: gss_delete_sec_context deleting %p\n",
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
5881 obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o
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
5887 obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
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
5893 #include <linux/unistd.h>
5895 #include <linux/sunrpc/auth_gss.h>
5896 +#include <linux/sunrpc/svcauth_gss.h>
5897 #include <linux/sunrpc/gss_asn1.h>
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);
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
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>
5918 + * RPCSEC_GSS server authentication.
5919 + * This implements RPCSEC_GSS as defined in rfc2203 (rpcsec_gss) and rfc2078
5922 + * The RPCSEC_GSS involves three stages:
5923 + * 1/ context creation
5924 + * 2/ data exchange
5925 + * 3/ context destruction
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
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.
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
5947 + * mechanism specific information, such as a key
5951 +#include <linux/types.h>
5952 +#include <linux/module.h>
5953 +#include <linux/pagemap.h>
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>
5963 +# define RPCDBG_FACILITY RPCDBG_AUTH
5966 +/* The rpcsec_init cache is used for mapping RPCSEC_GSS_{,CONT_}INIT requests
5969 + * Key is context handle (\x if empty) and gss_token.
5970 + * Content is major_status minor_status (integers) context_handle, reply_token.
5974 +static int netobj_equal(struct xdr_netobj *a, struct xdr_netobj *b)
5976 + return a->len == b->len && 0 == memcmp(a->data, b->data, a->len);
5979 +#define RSI_HASHBITS 6
5980 +#define RSI_HASHMAX (1<<RSI_HASHBITS)
5981 +#define RSI_HASHMASK (RSI_HASHMAX-1)
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;
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);
5994 +static void rsi_free(struct rsi *rsii)
5996 + kfree(rsii->in_handle.data);
5997 + kfree(rsii->in_token.data);
5998 + kfree(rsii->out_handle.data);
5999 + kfree(rsii->out_token.data);
6002 +static void rsi_put(struct cache_head *item, struct cache_detail *cd)
6004 + struct rsi *rsii = container_of(item, struct rsi, h);
6005 + if (cache_put(item, cd)) {
6011 +static inline int rsi_hash(struct rsi *item)
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);
6017 +static inline int rsi_match(struct rsi *item, struct rsi *tmp)
6019 + return netobj_equal(&item->in_handle, &tmp->in_handle)
6020 + && netobj_equal(&item->in_token, &tmp->in_token);
6023 +static int dup_to_netobj(struct xdr_netobj *dst, char *src, int len)
6026 + dst->data = (len ? kmalloc(len, GFP_KERNEL) : NULL);
6028 + memcpy(dst->data, src, len);
6029 + if (len && !dst->data)
6034 +static inline int dup_netobj(struct xdr_netobj *dst, struct xdr_netobj *src)
6036 + return dup_to_netobj(dst, src->data, src->len);
6039 +static inline void rsi_init(struct rsi *new, struct rsi *item)
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;
6056 +static inline void rsi_update(struct rsi *new, struct rsi *item)
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;
6068 + new->major_status = item->major_status;
6069 + new->minor_status = item->minor_status;
6072 +static void rsi_request(struct cache_detail *cd,
6073 + struct cache_head *h,
6074 + char **bpp, int *blen)
6076 + struct rsi *rsii = container_of(h, struct rsi, h);
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';
6084 +static int rsi_parse(struct cache_detail *cd,
6085 + char *mesg, int mlen)
6087 + /* context token expiry major minor context token */
6091 + struct rsi rsii, *rsip = NULL;
6093 + int status = -EINVAL;
6095 + memset(&rsii, 0, sizeof(rsii));
6097 + len = qword_get(&mesg, buf, mlen);
6101 + if (dup_to_netobj(&rsii.in_handle, buf, len))
6105 + len = qword_get(&mesg, buf, mlen);
6110 + if (dup_to_netobj(&rsii.in_token, buf, len))
6115 + expiry = get_expiry(&mesg);
6121 + len = qword_get(&mesg, buf, mlen);
6127 + rsii.major_status = simple_strtoul(buf, &ep, 10);
6130 + len = qword_get(&mesg, buf, mlen);
6133 + rsii.minor_status = simple_strtoul(buf, &ep, 10);
6138 + len = qword_get(&mesg, buf, mlen);
6142 + if (dup_to_netobj(&rsii.out_handle, buf, len))
6146 + len = qword_get(&mesg, buf, mlen);
6151 + if (dup_to_netobj(&rsii.out_token, buf, len))
6154 + rsii.h.expiry_time = expiry;
6155 + rsip = rsi_lookup(&rsii, 1);
6160 + rsi_put(&rsip->h, &rsi_cache);
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,
6173 +static DefineSimpleCacheLookup(rsi, 0)
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
6182 +#define RSC_HASHBITS 10
6183 +#define RSC_HASHMAX (1<<RSC_HASHBITS)
6184 +#define RSC_HASHMASK (RSC_HASHMAX-1)
6186 +#define GSS_SEQ_WIN 128
6188 +struct gss_svc_seq_data {
6189 + /* highest seq number seen so far: */
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;
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;
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);
6209 +static void rsc_free(struct rsc *rsci)
6211 + kfree(rsci->handle.data);
6212 + if (rsci->mechctx)
6213 + gss_delete_sec_context(&rsci->mechctx);
6216 +static void rsc_put(struct cache_head *item, struct cache_detail *cd)
6218 + struct rsc *rsci = container_of(item, struct rsc, h);
6220 + if (cache_put(item, cd)) {
6227 +rsc_hash(struct rsc *rsci)
6229 + return hash_mem(rsci->handle.data, rsci->handle.len, RSC_HASHBITS);
6233 +rsc_match(struct rsc *new, struct rsc *tmp)
6235 + return netobj_equal(&new->handle, &tmp->handle);
6239 +rsc_init(struct rsc *new, struct rsc *tmp)
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;
6249 +rsc_update(struct rsc *new, struct rsc *tmp)
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;
6258 +static int rsc_parse(struct cache_detail *cd,
6259 + char *mesg, int mlen)
6261 + /* contexthandle expiry [ uid gid N <n gids> mechname ...mechdata... ] */
6264 + struct rsc rsci, *rscp = NULL;
6266 + int status = -EINVAL;
6268 + memset(&rsci, 0, sizeof(rsci));
6269 + /* context handle */
6270 + len = qword_get(&mesg, buf, mlen);
6271 + if (len < 0) goto out;
6273 + if (dup_to_netobj(&rsci.handle, buf, len))
6278 + expiry = get_expiry(&mesg);
6283 + /* uid, or NEGATIVE */
6284 + rv = get_int(&mesg, &rsci.cred.cr_uid);
6285 + if (rv == -EINVAL)
6287 + if (rv == -ENOENT)
6288 + set_bit(CACHE_NEGATIVE, &rsci.h.flags);
6291 + struct gss_api_mech *gm;
6292 + struct xdr_netobj tmp_buf;
6295 + if (get_int(&mesg, &rsci.cred.cr_gid))
6298 + /* number of additional gid's */
6299 + if (get_int(&mesg, &N))
6305 + for (i=0; i<N; i++) {
6306 + if (get_int(&mesg, &rsci.cred.cr_groups[i]))
6310 + rsci.cred.cr_groups[N] = NOGROUP;
6313 + len = qword_get(&mesg, buf, mlen);
6316 + gm = gss_mech_get_by_name(buf);
6317 + status = -EOPNOTSUPP;
6322 + /* mech-specific data: */
6323 + len = qword_get(&mesg, buf, mlen);
6328 + tmp_buf.len = len;
6329 + tmp_buf.data = buf;
6330 + if (gss_import_sec_context(&tmp_buf, gm, &rsci.mechctx)) {
6336 + rsci.h.expiry_time = expiry;
6337 + rscp = rsc_lookup(&rsci, 1);
6342 + rsc_put(&rscp->h, &rsc_cache);
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,
6354 +static DefineSimpleCacheLookup(rsc, 0);
6357 +gss_svc_searchbyctx(struct xdr_netobj *handle)
6360 + struct rsc *found;
6362 + rsci.handle = *handle;
6363 + found = rsc_lookup(&rsci, 0);
6366 + if (cache_check(&rsc_cache, &found->h, NULL))
6371 +/* Implements sequence number algorithm as specified in RFC 2203. */
6373 +gss_check_seq_num(struct rsc *rsci, int seq_num)
6375 + struct gss_svc_seq_data *sd = &rsci->seqdata;
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) {
6384 + __clear_bit(sd->sd_max % GSS_SEQ_WIN, sd->sd_win);
6386 + __set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win);
6388 + } else if (seq_num <= sd->sd_max - GSS_SEQ_WIN) {
6391 + /* sd_max - GSS_SEQ_WIN < seq_num <= sd_max */
6392 + if (__test_and_set_bit(seq_num % GSS_SEQ_WIN, sd->sd_win))
6395 + spin_unlock(&sd->sd_lock);
6398 + spin_unlock(&sd->sd_lock);
6402 +static inline u32 round_up_to_quad(u32 i)
6404 + return (i + 3 ) & ~3;
6408 +svc_safe_getnetobj(struct iovec *argv, struct xdr_netobj *o)
6412 + if (argv->iov_len < 4)
6414 + o->len = ntohl(svc_getu32(argv));
6415 + l = round_up_to_quad(o->len);
6416 + if (argv->iov_len < l)
6418 + o->data = argv->iov_base;
6419 + argv->iov_base += l;
6420 + argv->iov_len -= l;
6425 +svc_safe_putnetobj(struct iovec *resv, struct xdr_netobj *o)
6429 + if (resv->iov_len + 4 > PAGE_SIZE)
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)
6436 + memcpy(p, o->data, o->len);
6437 + memset((u8 *)p + o->len, 0, round_up_to_quad(o->len) - o->len);
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.
6446 +gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
6447 + u32 *rpcstart, struct rpc_gss_wire_cred *gc, u32 *authp)
6449 + struct gss_ctx *ctx_id = rsci->mechctx;
6450 + struct xdr_buf rpchdr;
6451 + struct xdr_netobj checksum;
6453 + struct iovec *argv = &rqstp->rq_arg.head[0];
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);
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;
6470 + if (rqstp->rq_deferred) /* skip verification of revisited request */
6472 + if (gss_verify_mic(ctx_id, &rpchdr, &checksum, NULL)
6473 + != GSS_S_COMPLETE) {
6474 + *authp = rpcsec_gsserr_credproblem;
6475 + return SVC_DENIED;
6478 + if (gc->gc_seq > MAXSEQ) {
6479 + dprintk("RPC: svcauth_gss: discarding request with large sequence number %d\n",
6481 + *authp = rpcsec_gsserr_ctxproblem;
6482 + return SVC_DENIED;
6484 + if (!gss_check_seq_num(rsci, gc->gc_seq)) {
6485 + dprintk("RPC: svcauth_gss: discarding request with old sequence number %d\n",
6493 +gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
6497 + struct xdr_buf verf_data;
6498 + struct xdr_netobj mic;
6502 + svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_GSS));
6503 + xdr_seq = htonl(seq);
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)
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))
6521 +struct gss_domain {
6522 + struct auth_domain h;
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)
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");
6542 +svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
6544 + struct gss_domain *new;
6545 + struct auth_domain *test;
6546 + static char *prefix = "gss/";
6549 + new = kmalloc(sizeof(*new), GFP_KERNEL);
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);
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;
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);
6579 +/* It would be nice if this bit of code could be shared with the client.
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. */
6585 +unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
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;
6593 + integ_len = ntohl(svc_getu32(&buf->head[0]));
6594 + if (integ_len & 3)
6596 + if (integ_len > buf->len)
6598 + if (xdr_buf_subsegment(buf, &integ_buf, 0, integ_len))
6600 + /* copy out mic... */
6601 + if (read_u32_from_xdr_buf(buf, integ_len, &mic.len))
6603 + if (mic.len > 256) /* XXX: maximum mic length? */
6605 + mic.data = kmalloc(mic.len, GFP_KERNEL);
6606 + if (read_bytes_from_xdr_buf(buf, integ_len + 4, mic.data, mic.len))
6608 + maj_stat = gss_verify_mic(ctx, &integ_buf, &mic, NULL);
6609 + if (maj_stat != GSS_S_COMPLETE)
6611 + if (ntohl(svc_getu32(&buf->head[0])) != seq)
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.
6627 +svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
6629 + struct iovec *argv = &rqstp->rq_arg.head[0];
6630 + struct iovec *resv = &rqstp->rq_res.head[0];
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;
6638 + u32 *reject_stat = resv->iov_base;
6641 + dprintk("RPC: svcauth_gss: argv->iov_len = %d\n", argv->iov_len);
6643 + *authp = rpc_autherr_badcred;
6645 + svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL);
6648 + rqstp->rq_auth_data = svcdata;
6649 + gc = &svcdata->clcred;
6651 + /* start of rpc packet is 7 u32's back from here:
6652 + * xid direction rpcversion prog vers proc flavour
6654 + rpcstart = argv->iov_base;
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.
6662 + if (argv->iov_len < 5 * 4)
6664 + crlen = ntohl(svc_getu32(argv));
6665 + if (ntohl(svc_getu32(argv)) != RPC_GSS_VERSION)
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))
6672 + if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)
6675 + if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0))
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.
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.
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)
6695 + if (ntohl(svc_getu32(argv)) != RPC_AUTH_NULL)
6697 + if (ntohl(svc_getu32(argv)) != 0)
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);
6706 + switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) {
6716 + *authp = rpc_autherr_rejectedcred;
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)
6727 + memset(&rsikey, 0, sizeof(rsikey));
6728 + if (dup_netobj(&rsikey.in_handle, &gc->gc_ctx))
6730 + *authp = rpc_autherr_badverf;
6731 + if (svc_safe_getnetobj(argv, &tmpobj)) {
6732 + kfree(rsikey.in_handle.data);
6735 + if (dup_netobj(&rsikey.in_token, &tmpobj)) {
6736 + kfree(rsikey.in_handle.data);
6740 + rsip = rsi_lookup(&rsikey, 0);
6741 + rsi_free(&rsikey);
6745 + switch(cache_check(&rsi_cache, &rsip->h, &rqstp->rq_chandle)) {
6751 + rsci = gss_svc_searchbyctx(&rsip->out_handle);
6755 + if (gss_write_verf(rqstp, rsci->mechctx, GSS_SEQ_WIN))
6757 + if (resv->iov_len + 4 > PAGE_SIZE)
6759 + svc_putu32(resv, rpc_success);
6760 + if (svc_safe_putnetobj(resv, &rsip->out_handle))
6762 + if (resv->iov_len + 3 * 4 > PAGE_SIZE)
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))
6769 + rqstp->rq_client = NULL;
6772 + case RPC_GSS_PROC_DESTROY:
6773 + set_bit(CACHE_NEGATIVE, &rsci->h.flags);
6774 + if (resv->iov_len + 4 > PAGE_SIZE)
6776 + svc_putu32(resv, rpc_success);
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)
6783 + *authp = rpcsec_gsserr_ctxproblem;
6784 + if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
6787 + rqstp->rq_cred = rsci->cred;
6789 + *authp = rpc_autherr_badcred;
6790 + switch (gc->gc_svc) {
6791 + case RPC_GSS_SVC_NONE:
6793 + case RPC_GSS_SVC_INTEGRITY:
6794 + if (unwrap_integ_data(&rqstp->rq_arg,
6795 + gc->gc_seq, rsci->mechctx))
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);
6802 + case RPC_GSS_SVC_PRIVACY:
6803 + /* currently unsupported */
6811 + /* Restore write pointer to original value: */
6812 + xdr_ressize_check(rqstp, reject_stat);
6816 + ret = SVC_COMPLETE;
6822 + rsc_put(&rsci->h, &rsc_cache);
6827 +svcauth_gss_release(struct svc_rqst *rqstp)
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;
6836 + int integ_offset, integ_len;
6838 + int stat = -EINVAL;
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:
6846 + case RPC_GSS_SVC_INTEGRITY:
6847 + p = gsd->body_start;
6848 + /* move accept_stat to right place: */
6849 + memcpy(p, p + 2, 4);
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,
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];
6872 + resv = &resbuf->tail[0];
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? */
6881 + /* XXX Whoops, we might overflow here: */
6882 + if (gss_get_mic(rsci->mechctx, 0, &integ_buf, &mic))
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)
6891 + case RPC_GSS_SVC_PRIVACY:
6898 + if (rqstp->rq_client)
6899 + auth_domain_put(rqstp->rq_client);
6900 + rqstp->rq_client = NULL;
6906 +svcauth_gss_domain_release(struct auth_domain *dom)
6908 + struct gss_domain *gd = container_of(dom, struct gss_domain, h);
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,
6925 + cache_register(&rsc_cache);
6926 + cache_register(&rsi_cache);
6927 + svc_auth_register(RPC_AUTH_GSS, &svcauthops_gss);
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);
6936 kfree(rqstp->rq_argp);
6937 + if (rqstp->rq_auth_data)
6938 + kfree(rqstp->rq_auth_data);
6941 /* Release the server */
6942 @@ -322,6 +324,8 @@ svc_process(struct svc_serv *serv, struc
6946 + case SVC_COMPLETE:
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
6955 # Makefile for Linux kernel SUN RPC
6958 -obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
6960 obj-$(CONFIG_SUNRPC) += sunrpc.o
6961 +obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
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
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>
6976 #define NFSDDBG_FACILITY NFSDDBG_PROC
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.
6985 +fh_dup2(struct svc_fh *dst, struct svc_fh *src)
6988 + dget(src->fh_dentry);
6989 + if (src->fh_export)
6990 + cache_get(&src->fh_export->h);
6995 do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
6997 @@ -89,12 +96,19 @@ do_open_lookup(struct svc_rqst *rqstp, s
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);
7009 if (open->op_share_access & NFS4_SHARE_ACCESS_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);
7017 @@ -102,19 +116,39 @@ do_open_lookup(struct svc_rqst *rqstp, s
7022 + * nfs4_unlock_state() called in encode
7025 nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
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);
7034 /* This check required by spec. */
7035 if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
7036 return nfserr_inval;
7038 + open->op_stateowner = NULL;
7039 + nfs4_lock_state();
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(¤t_fh->fh_handle.fh_base, rp->rp_openfh,
7048 + rp->rp_openfh_len);
7049 + status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
7051 + dprintk("nfsd4_open: replay failed"
7052 + " restoring previous filehandle\n");
7054 + status = NFSERR_REPLAY_ME;
7059 @@ -172,7 +206,7 @@ static inline int
7060 nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
7062 if (!save_fh->fh_dentry)
7063 - return nfserr_nofilehandle;
7064 + return nfserr_restorefh;
7066 fh_dup2(current_fh, save_fh);
7068 @@ -204,11 +238,16 @@ nfsd4_access(struct svc_rqst *rqstp, str
7070 nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit)
7074 u32 *p = (u32 *)commit->co_verf.data;
7075 *p++ = nfssvc_boot.tv_sec;
7076 *p++ = nfssvc_boot.tv_usec;
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;
7086 @@ -221,6 +260,8 @@ nfsd4_create(struct svc_rqst *rqstp, str
7087 fh_init(&resfh, NFS4_FHSIZE);
7089 status = fh_verify(rqstp, current_fh, S_IFDIR, MAY_CREATE);
7090 + if (status == nfserr_symlink)
7091 + status = nfserr_notdir;
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)
7100 + int status = nfserr_nofilehandle;
7102 + if (!save_fh->fh_dentry)
7104 status = nfsd_link(rqstp, current_fh, link->li_name, link->li_namelen, save_fh);
7106 set_change_info(&link->li_cinfo, current_fh);
7107 @@ -327,14 +370,18 @@ nfsd4_link(struct svc_rqst *rqstp, struc
7109 nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
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.
7119 + struct svc_fh tmp_fh;
7122 + fh_init(&tmp_fh, NFS4_FHSIZE);
7123 + if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh,
7124 + &rqstp->rq_chandle)) != 0)
7126 + if (tmp_fh.fh_dentry == current_fh->fh_dentry) {
7128 + return nfserr_noent;
7131 return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh);
7134 @@ -345,6 +392,20 @@ nfsd4_lookup(struct svc_rqst *rqstp, str
7138 +access_bits_permit_read(unsigned long access_bmap)
7140 + return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) ||
7141 + test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
7145 +access_bits_permit_write(unsigned long access_bmap)
7147 + return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) ||
7148 + test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
7152 nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
7154 struct nfs4_stateid *stp;
7155 @@ -382,7 +443,7 @@ nfsd4_read(struct svc_rqst *rqstp, struc
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");
7164 @@ -397,6 +458,11 @@ out:
7166 nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir)
7168 + u64 cookie = readdir->rd_cookie;
7169 + static const nfs4_verifier zeroverf = {
7173 /* no need to check permission - this will be done in nfsd_readdir() */
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;
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;
7185 readdir->rd_rqstp = rqstp;
7186 @@ -427,6 +494,8 @@ nfsd4_remove(struct svc_rqst *rqstp, str
7189 status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen);
7190 + if (status == nfserr_symlink)
7191 + return nfserr_notdir;
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)
7200 + int status = nfserr_nofilehandle;
7202 + if (!save_fh->fh_dentry)
7204 status = nfsd_rename(rqstp, save_fh, rename->rn_sname,
7205 rename->rn_snamelen, current_fh,
7206 rename->rn_tname, rename->rn_tnamelen);
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;
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)
7225 struct nfs4_stateid *stp;
7226 - int status = nfs_ok;
7227 + int status = nfserr_nofilehandle;
7229 + if (!current_fh->fh_dentry)
7233 if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
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");
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");
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");
7257 nfs4_unlock_state();
7259 - return (nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr, 0, (time_t)0));
7260 +#ifdef CONFIG_NFS_V4_ACL
7262 + if (setattr->sa_acl != NULL)
7263 + status = nfsd4_set_nfs4_acl(rqstp, current_fh, setattr->sa_acl);
7266 +#endif /* CONFIG_NFS_V4_ACL */
7267 + status = nfsd_setattr(rqstp, current_fh, &setattr->sa_iattr,
7272 nfs4_unlock_state();
7275 @@ -513,7 +610,7 @@ nfsd4_write(struct svc_rqst *rqstp, stru
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");
7284 @@ -526,9 +623,12 @@ zero_stateid:
7285 *p++ = nfssvc_boot.tv_sec;
7286 *p++ = nfssvc_boot.tv_usec;
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;
7297 nfs4_unlock_state();
7299 @@ -552,8 +652,9 @@ nfsd4_verify(struct svc_rqst *rqstp, str
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
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,
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
7325 + /* All operations except RENEW, SETCLIENTID, RESTOREFH
7326 + * SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH
7327 + * require a valid current filehandle
7329 + * SETATTR NOFILEHANDLE error handled in nfsd4_setattr
7330 + * due to required returned bitmap argument
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;
7342 switch (op->opnum) {
7344 op->status = nfsd4_access(rqstp, ¤t_fh, &op->u.access);
7347 op->status = nfsd4_close(rqstp, ¤t_fh, &op->u.close);
7348 - op->replay = &op->u.close.cl_stateowner->so_replay;
7349 + if (op->u.close.cl_stateowner)
7351 + &op->u.close.cl_stateowner->so_replay;
7354 op->status = nfsd4_commit(rqstp, ¤t_fh, &op->u.commit);
7355 @@ -683,12 +804,18 @@ nfsd4_proc_compound(struct svc_rqst *rqs
7358 op->status = nfsd4_lock(rqstp, ¤t_fh, &op->u.lock);
7359 + if (op->u.lock.lk_stateowner)
7361 + &op->u.lock.lk_stateowner->so_replay;
7364 op->status = nfsd4_lockt(rqstp, ¤t_fh, &op->u.lockt);
7367 op->status = nfsd4_locku(rqstp, ¤t_fh, &op->u.locku);
7368 + if (op->u.locku.lu_stateowner)
7370 + &op->u.locku.lu_stateowner->so_replay;
7373 op->status = nfsd4_lookup(rqstp, ¤t_fh, &op->u.lookup);
7374 @@ -703,15 +830,21 @@ nfsd4_proc_compound(struct svc_rqst *rqs
7377 op->status = nfsd4_open(rqstp, ¤t_fh, &op->u.open);
7378 - op->replay = &op->u.open.op_stateowner->so_replay;
7379 + if (op->u.open.op_stateowner)
7381 + &op->u.open.op_stateowner->so_replay;
7383 case OP_OPEN_CONFIRM:
7384 op->status = nfsd4_open_confirm(rqstp, ¤t_fh, &op->u.open_confirm);
7385 - op->replay = &op->u.open_confirm.oc_stateowner->so_replay;
7386 + if (op->u.open_confirm.oc_stateowner)
7388 + &op->u.open_confirm.oc_stateowner->so_replay;
7390 case OP_OPEN_DOWNGRADE:
7391 op->status = nfsd4_open_downgrade(rqstp, ¤t_fh, &op->u.open_downgrade);
7392 - op->replay = &op->u.open_downgrade.od_stateowner->so_replay;
7393 + if (op->u.open_downgrade.od_stateowner)
7395 + &op->u.open_downgrade.od_stateowner->so_replay;
7398 op->status = nfsd4_putfh(rqstp, ¤t_fh, &op->u.putfh);
7399 @@ -760,6 +893,9 @@ nfsd4_proc_compound(struct svc_rqst *rqs
7401 op->status = nfsd4_write(rqstp, ¤t_fh, &op->u.write);
7403 + case OP_RELEASE_LOCKOWNER:
7404 + op->status = nfsd4_release_lockowner(rqstp, &op->u.release_lockowner);
7407 BUG_ON(op->status == nfs_ok);
7409 @@ -768,7 +904,7 @@ nfsd4_proc_compound(struct svc_rqst *rqs
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;
7416 nfsd4_encode_operation(resp, op);
7417 status = op->status;
7418 @@ -776,20 +912,7 @@ encode_op:
7422 - if (args->ops != args->iops) {
7424 - args->ops = args->iops;
7427 - kfree(args->tmpp);
7428 - args->tmpp = NULL;
7430 - while (args->to_free) {
7431 - struct tmpbuf *tb = args->to_free;
7432 - args->to_free = tb->next;
7436 + nfsd4_release_compoundargs(args);
7437 fh_put(¤t_fh);
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>
7455 #define NFSDDBG_FACILITY NFSDDBG_XDR
7458 - * From Peter Astrand <peter@cendio.se>: The following routines check
7459 - * whether a filename supplied by the client is valid.
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
7480 -is_legal_iso_utf8_sequence(unsigned char *source, int length)
7481 +is_legal_utf8_sequence(unsigned char *source, int length)
7484 - unsigned char *srcptr;
7485 + unsigned char *ptr;
7488 - srcptr = source + length;
7489 + if (length==1) return 1;
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;
7499 + case 0xF0: /* 4 bytes */
7500 + if ( c < 0x90 ) return 0;
7502 + case 0xF8: /* 5 bytes */
7503 + if ( c < 0xC8 ) return 0;
7505 + case 0xFC: /* 6 bytes */
7506 + if ( c < 0x84 ) return 0;
7509 - /* Sequences with more than 6 bytes are invalid */
7511 + if ( (c & 0xC0) != 0x80) return 0;
7515 - Byte 3-6 must be 80..BF
7518 - if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
7520 - if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
7522 - if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
7524 - if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
7531 - /* 2nd byte may never be > 0xBF */
7533 + /* Check that trailing bytes look like 10xxxxxx */
7534 + for (ptr = source++ + length - 1; ptr>source; ptr--)
7535 + if ( ((*ptr) & 0xC0) != 0x80 ) return 0;
7540 - Lower limits checks, to detect non-shortest forms.
7541 - No fall-through in this inner switch.
7543 - switch (*source) {
7544 - case 0xE0: /* 3 bytes */
7545 - if (a < 0xA0) return 0;
7547 - case 0xF0: /* 4 bytes */
7548 - if (a < 0x90) return 0;
7550 - case 0xF8: /* 5 bytes */
7551 - if (a < 0xC8) return 0;
7553 - case 0xFC: /* 6 bytes */
7554 - if (a < 0x84) return 0;
7557 - /* In all cases, 2nd byte must be >= 0x80 (because leading
7559 - if (a < 0x80) return 0;
7561 +/* This does some screening on disallowed unicode characters. It is NOT
7565 +is_allowed_utf8_char(unsigned char *source, int length)
7567 + /* We assume length and source point to a valid utf8 sequence */
7571 - /* Invalid ranges */
7572 - if (*source >= 0x80 && *source < 0xC2)
7573 - /* Multibyte char with value < 0xC2, non-shortest */
7575 - if (*source > 0xFD)
7576 - /* Leading byte starting with 11111110 is illegal */
7580 + /* Disallow F0000 and up (in utf8, F3B08080) */
7581 + if (*source > 0xF3 ) return 0;
7582 + c = *(source + 1);
7583 + switch (*source) {
7585 + if (c >= 0xB0) return 0;
7587 + /* Disallow D800-F8FF (in utf8, EDA080-EFA3BF */
7589 + if (c >= 0xA0) return 0;
7595 + if (c <= 0xA3) return 0;
7596 + /* Disallow FFF9-FFFF (EFBFB9-EFBFBF) */
7598 + /* Don't need to check <=0xBF, since valid utf8 */
7599 + if ( *(source+2) >= 0xB9) return 0;
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.
7614 + * Note - currently calling routines ignore return value except as boolean.
7617 check_utf8(char *str, int len)
7619 @@ -155,11 +158,17 @@ check_utf8(char *str, int len)
7620 sourceend = str + len;
7622 while (chunk < sourceend) {
7623 - chunklen = trailing_bytes_for_utf8[*chunk]+1;
7624 + chunklen = utf8_byte_len[*chunk];
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 */
7639 @@ -280,27 +289,40 @@ u32 *read_buf(struct nfsd4_compoundargs
7643 -char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
7645 +defer_free(struct nfsd4_compoundargs *argp,
7646 + void (*release)(const void *), void *p)
7650 + tb = kmalloc(sizeof(*tb), GFP_KERNEL);
7654 + tb->release = release;
7655 + tb->next = argp->to_free;
7656 + argp->to_free = tb;
7660 +char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
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;
7669 memcpy(p, argp->tmp, nbytes);
7671 if (p != argp->tmpp)
7675 - tb = kmalloc(sizeof(*tb), GFP_KERNEL);
7678 + if (defer_free(argp, kfree, p)) {
7683 - tb->next = argp->to_free;
7684 - argp->to_free = tb;
7691 @@ -328,7 +350,8 @@ nfsd4_decode_bitmap(struct nfsd4_compoun
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)
7699 int expected_len, len = 0;
7701 @@ -344,7 +367,7 @@ nfsd4_decode_fattr(struct nfsd4_compound
7702 * read-only attributes return ERR_INVAL.
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;
7710 @@ -357,6 +380,39 @@ nfsd4_decode_fattr(struct nfsd4_compound
7711 READ64(iattr->ia_size);
7712 iattr->ia_valid |= ATTR_SIZE;
7714 +#ifdef CONFIG_NFS_V4_ACL
7715 + if (bmval[0] & FATTR4_WORD0_ACL) {
7717 + struct nfs4_ace ace;
7719 + READ_BUF(4); len += 4;
7722 + *acl = nfs4_acl_new();
7723 + if (*acl == NULL) {
7727 + defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl);
7729 + for (i = 0; i < nace; i++) {
7730 + READ_BUF(16); len += 16;
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) {
7742 + p += XDR_QUADLEN(ace.wholen);
7746 +#endif /* CONFIG_NFS_V4_ACL */
7747 if (bmval[1] & FATTR4_WORD1_MODE) {
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)))
7757 iattr->ia_valid |= ATTR_UID;
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)))
7766 iattr->ia_valid |= ATTR_GID;
7768 @@ -482,6 +538,7 @@ nfsd4_decode_close(struct nfsd4_compound
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)))
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)))
7785 @@ -572,6 +629,7 @@ nfsd4_decode_lock(struct nfsd4_compounda
7789 + (int)lock->lk_stateowner = -1;
7791 * type, reclaim(boolean), offset, length, new_lock_owner(boolean)
7793 @@ -629,6 +687,7 @@ nfsd4_decode_locku(struct nfsd4_compound
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
7803 memset(open->op_bmval, 0, sizeof(open->op_bmval));
7804 open->op_iattr.ia_valid = 0;
7805 + (int)open->op_stateowner = -1;
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)))
7817 case NFS4_CREATE_EXCLUSIVE:
7818 @@ -739,6 +799,7 @@ nfsd4_decode_open_confirm(struct nfsd4_c
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
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)))
7843 @@ -928,7 +990,7 @@ nfsd4_decode_write(struct nfsd4_compound
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
7856 +nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
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);
7870 nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
7873 @@ -1043,6 +1119,13 @@ nfsd4_decode_compound(struct nfsd4_compo
7874 op->opnum = ntohl(*argp->p++);
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;
7882 + op->status = nfserr_minor_vers_mismatch;
7885 op->status = nfsd4_decode_access(argp, &op->u.access);
7887 @@ -1136,14 +1219,12 @@ nfsd4_decode_compound(struct nfsd4_compo
7889 op->status = nfsd4_decode_write(argp, &op->u.write);
7891 + case OP_RELEASE_LOCKOWNER:
7892 + op->status = nfsd4_decode_release_lockowner(argp, &op->u.release_lockowner);
7896 - * According to spec, anything greater than OP_WRITE
7897 - * is treated as OP_WRITE+1 in the response.
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;
7907 @@ -1183,10 +1264,10 @@ nfsd4_decode_compound(struct nfsd4_compo
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); \
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.
7927 + * if stateowner != -1 then called with nfs4_lock_state() held
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); \
7943 + if ((int)stateowner != -1) nfs4_unlock_state();
7946 static u32 nfs4_ftypes[16] = {
7947 @@ -1239,13 +1324,16 @@ static u32 nfs4_ftypes[16] = {
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)
7955 u32 bmval0 = bmval[0];
7956 u32 bmval1 = bmval[1];
7958 - struct name_ent *owner = NULL;
7959 - struct name_ent *group = NULL;
7960 + char owner[IDMAP_NAMESZ];
7962 + char group[IDMAP_NAMESZ];
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
7971 + struct nfs4_acl *acl = NULL;
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
7978 if (bmval1 & FATTR4_WORD1_OWNER) {
7979 - status = name_get_user(stat.uid, &owner);
7981 + int temp = nfsd_map_uid_to_name(rqstp, stat.uid, owner);
7986 + ownerlen = (unsigned) temp;
7988 if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
7989 - status = name_get_group(stat.gid, &group);
7991 + int temp = nfsd_map_gid_to_name(rqstp, stat.gid, group);
7996 + grouplen = (unsigned) temp;
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)
8006 +#endif /* CONFIG_NFS_V4_ACL */
8008 if ((buflen -= 16) < 0)
8010 @@ -1317,32 +1421,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
8012 if (bmval0 & FATTR4_WORD0_CHANGE) {
8014 - * XXX: We currently use the inode ctime as the nfsv4 "changeid"
8015 - * attribute. This violates the spec, which says
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
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.
8026 - * The real solution to this problem is probably to work on
8027 - * adding high-resolution mtimes to the VFS layer.
8029 - * Note: Started using i_size for the high 32 bits of the changeid.
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()
8037 if ((buflen -= 8) < 0)
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? */
8044 if (bmval0 & FATTR4_WORD0_SIZE) {
8045 if ((buflen -= 8) < 0)
8046 @@ -1387,10 +1474,48 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
8050 +#ifdef CONFIG_NFS_V4_ACL
8051 + if (bmval0 & FATTR4_WORD0_ACL) {
8052 + struct nfs4_ace *ace;
8053 + struct list_head *h;
8056 + if (acl == NULL) {
8057 + if ((buflen -= 4) < 0)
8058 + goto out_resource;
8064 + alen = acl->naces * 16 + 4;
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;
8071 + if ((buflen -= alen) < 0)
8072 + goto out_resource;
8074 + WRITE32(acl->naces);
8076 + list_for_each(h, &acl->ace_head) {
8077 + ace = list_entry(h, struct nfs4_ace, l_ace);
8079 + WRITE32(ace->type);
8080 + WRITE32(ace->flag);
8081 + WRITE32(ace->access_mask);
8082 + WRITE32(ace->wholen);
8083 + WRITEMEM(ace->who, ace->wholen);
8087 +#endif /* CONFIG_NFS_V4_ACL */
8088 if (bmval0 & FATTR4_WORD0_ACLSUPPORT) {
8089 if ((buflen -= 4) < 0)
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);
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;
8106 - WRITEMEM(owner->name, namelen);
8107 + WRITE32(ownerlen);
8108 + WRITEMEM(owner, ownerlen);
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;
8117 - WRITEMEM(group->name, namelen);
8118 + WRITE32(grouplen);
8119 + WRITEMEM(group, grouplen);
8121 if (bmval1 & FATTR4_WORD1_RAWDEV) {
8122 if ((buflen -= 8) < 0)
8123 @@ -1564,12 +1687,11 @@ nfsd4_encode_fattr(struct svc_fh *fhp, s
8127 +#ifdef CONFIG_NFS_V4_ACL
8128 + nfs4_acl_free(acl);
8138 status = nfserrno(status);
8139 @@ -1648,7 +1770,8 @@ nfsd4_encode_dirent(struct readdir_cd *c
8142 nfserr = nfsd4_encode_fattr(NULL, exp,
8143 - dentry, p, &buflen, cd->rd_bmval);
8144 + dentry, p, &buflen, cd->rd_bmval,
8149 @@ -1701,7 +1824,7 @@ out:
8153 - cd->common.err = nfserr_readdir_nospc;
8154 + cd->common.err = nfserr_toosmall;
8158 @@ -1771,7 +1894,8 @@ nfsd4_encode_getattr(struct nfsd4_compou
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,
8168 @@ -1871,7 +1995,7 @@ nfsd4_encode_open(struct nfsd4_compoundr
8169 ENCODE_SEQID_OP_HEAD;
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
8182 + /* XXX save filehandle here */
8184 ENCODE_SEQID_OP_TAIL(open->op_stateowner);
8187 @@ -1995,6 +2120,8 @@ nfsd4_encode_read(struct nfsd4_compoundr
8189 read->rd_iov, read->rd_vlen,
8191 + if (nfserr == nfserr_symlink)
8192 + nfserr = nfserr_inval;
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.
8199 nfserr = nfsd_readlink(readlink->rl_rqstp, readlink->rl_fhp, page, &maxcount);
8200 + if (nfserr == nfserr_isdir)
8201 + return nfserr_inval;
8205 @@ -2081,7 +2210,7 @@ nfsd4_encode_readdir(struct nfsd4_compou
8210 + u32 *page, *savep;
8214 @@ -2090,6 +2219,7 @@ nfsd4_encode_readdir(struct nfsd4_compou
8215 return nfserr_resource;
8217 RESERVE_SPACE(8); /* verifier */
8220 /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */
8222 @@ -2107,8 +2237,10 @@ nfsd4_encode_readdir(struct nfsd4_compou
8223 * pointer and eof field.
8225 maxcount = (maxcount >> 2) - 4;
8227 - return nfserr_readdir_nospc;
8228 + if (maxcount < 0) {
8229 + nfserr = nfserr_toosmall;
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
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;
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;
8263 @@ -2237,7 +2375,7 @@ nfsd4_encode_operation(struct nfsd4_comp
8267 - statp = p++; /* to be backfilled at the end */
8268 + statp = p++; /* to be backfilled at the end */
8271 switch (op->opnum) {
8272 @@ -2324,6 +2462,8 @@ nfsd4_encode_operation(struct nfsd4_comp
8274 nfsd4_encode_write(resp, op->status, &op->u.write);
8276 + case OP_RELEASE_LOCKOWNER:
8281 @@ -2340,6 +2480,8 @@ nfsd4_encode_operation(struct nfsd4_comp
8283 * XDR note: do not encode rp->rp_buflen: the buffer contains the
8284 * previously sent already encoded operation.
8286 + * called with nfs4_lock_state() held
8289 nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
8290 @@ -2351,12 +2493,13 @@ nfsd4_encode_replay(struct nfsd4_compoun
8295 + *p++ = rp->rp_status; /* already xdr'ed */
8298 RESERVE_SPACE(rp->rp_buflen);
8299 WRITEMEM(rp->rp_buf, rp->rp_buflen);
8301 + nfs4_unlock_state();
8305 @@ -2369,6 +2512,24 @@ nfs4svc_encode_voidres(struct svc_rqst *
8306 return xdr_ressize_check(rqstp, p);
8309 +void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args)
8311 + if (args->ops != args->iops) {
8313 + args->ops = args->iops;
8316 + kfree(args->tmpp);
8317 + args->tmpp = NULL;
8319 + while (args->to_free) {
8320 + struct tmpbuf *tb = args->to_free;
8321 + args->to_free = tb->next;
8322 + tb->release(tb->buf);
8328 nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args)
8330 @@ -2381,23 +2542,11 @@ nfs4svc_decode_compoundargs(struct svc_r
8332 args->to_free = NULL;
8333 args->ops = args->iops;
8334 + args->rqstp = rqstp;
8336 status = nfsd4_decode_compound(args);
8338 - if (args->ops != args->iops) {
8340 - args->ops = args->iops;
8343 - kfree(args->tmpp);
8344 - args->tmpp = NULL;
8346 - while (args->to_free) {
8347 - struct tmpbuf *tb = args->to_free;
8348 - args->to_free = tb->next;
8352 + nfsd4_release_compoundargs(args);
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;
8362 unsigned intrp_allocated;
8363 + int rp_openfh_len;
8364 + char rp_openfh[NFS4_FHSIZE];
8365 char rp_ibuf[NFSD4_REPLAY_ISIZE];
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.
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 */
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
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;
8410 - unsigned int st_share_access;
8411 - unsigned int st_share_deny;
8412 + unsigned long st_access_bmap;
8413 + unsigned long st_deny_bmap;
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
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
8440 + * fs/nfsd/nfs4idmap.c
8442 + * Mapping of UID/GIDs to name and vice versa.
8444 + * Copyright (c) 2002, 2003 The Regents of the University of
8445 + * Michigan. All rights reserved.
8447 + * Marius Aamodt Eriksen <marius@umich.edu>
8449 + * Redistribution and use in source and binary forms, with or without
8450 + * modification, are permitted provided that the following conditions
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.
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.
8475 +#include <linux/config.h>
8476 +#include <linux/module.h>
8477 +#include <linux/init.h>
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>
8502 + * XXX we know that IDMAP_NAMESZ < PAGE_SIZE, but it's ugly to rely on
8506 +#define IDMAP_TYPE_USER 0
8507 +#define IDMAP_TYPE_GROUP 1
8510 + struct cache_head h;
8511 + int type; /* User / Group */
8513 + char name[IDMAP_NAMESZ];
8514 + char authname[IDMAP_NAMESZ];
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)
8523 +/* Common entry handling */
8525 +#define ENT_HASHBITS 8
8526 +#define ENT_HASHMAX (1 << ENT_HASHBITS)
8527 +#define ENT_HASHMASK (ENT_HASHMAX - 1)
8530 +ent_init(struct ent *new, struct ent *itm)
8532 + new->id = itm->id;
8533 + new->type = itm->type;
8535 + strlcpy(new->name, itm->name, sizeof(new->name));
8536 + strlcpy(new->authname, itm->authname, sizeof(new->name));
8540 +ent_update(struct ent *new, struct ent *itm)
8542 + ent_init(new, itm);
8546 +ent_put(struct cache_head *ch, struct cache_detail *cd)
8548 + if (cache_put(ch, cd)) {
8549 + struct ent *map = container_of(ch, struct ent, h);
8555 + * ID -> Name cache
8558 +static struct cache_head *idtoname_table[ENT_HASHMAX];
8561 +idtoname_hash(struct ent *ent)
8565 + hash = hash_str(ent->authname, ENT_HASHBITS);
8566 + hash = hash_long(hash ^ ent->id, ENT_HASHBITS);
8568 + /* Flip LSB for user/group */
8569 + if (ent->type == IDMAP_TYPE_GROUP)
8576 +idtoname_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
8579 + struct ent *ent = container_of(ch, struct ent, h);
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);
8587 + (*bpp)[-1] = '\n';
8591 +idtoname_match(struct ent *a, struct ent *b)
8593 + return (a->id == b->id && a->type == b->type &&
8594 + strcmp(a->authname, b->authname) == 0);
8598 +idtoname_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
8603 + seq_puts(m, "#domain type id [name]\n");
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",
8610 + if (test_bit(CACHE_VALID, &h->flags))
8611 + seq_printf(m, " %s", ent->name);
8612 + seq_printf(m, "\n");
8616 +static int idtoname_parse(struct cache_detail *, char *, int);
8617 +static struct ent *idtoname_lookup(struct ent *, int);
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,
8630 +idtoname_parse(struct cache_detail *cd, char *buf, int buflen)
8632 + struct ent ent, *res;
8634 + int error = -EINVAL;
8636 + if (buf[buflen - 1] != '\n')
8638 + buf[buflen - 1]= '\0';
8640 + buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL);
8644 + memset(&ent, 0, sizeof(ent));
8646 + /* Authentication name */
8647 + if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8649 + memcpy(ent.authname, buf1, sizeof(ent.authname));
8652 + if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8654 + ent.type = strcmp(buf1, "user") == 0 ?
8655 + IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
8658 + if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8660 + ent.id = simple_strtoul(buf1, &bp, 10);
8665 + ent.h.expiry_time = get_expiry(&buf);
8666 + if (ent.h.expiry_time == 0)
8670 + error = qword_get(&buf, buf1, PAGE_SIZE);
8671 + if (error == -EINVAL)
8673 + if (error == -ENOENT)
8674 + set_bit(CACHE_NEGATIVE, &ent.h.flags);
8676 + if (error >= IDMAP_NAMESZ) {
8680 + memcpy(ent.name, buf1, sizeof(ent.name));
8683 + if ((res = idtoname_lookup(&ent, 1)) == NULL)
8686 + ent_put(&res->h, &idtoname_cache);
8695 +static DefineSimpleCacheLookupMap(ent, idtoname);
8698 + * Name -> ID cache
8701 +static struct cache_head *nametoid_table[ENT_HASHMAX];
8704 +nametoid_hash(struct ent *ent)
8706 + return hash_str(ent->name, ENT_HASHBITS);
8710 +nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
8713 + struct ent *ent = container_of(ch, struct ent, h);
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);
8719 + (*bpp)[-1] = '\n';
8723 +nametoid_match(struct ent *a, struct ent *b)
8725 + return (a->type == b->type && strcmp(a->name, b->name) == 0 &&
8726 + strcmp(a->authname, b->authname) == 0);
8730 +nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
8735 + seq_puts(m, "#domain type name [id]\n");
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",
8742 + if (test_bit(CACHE_VALID, &h->flags))
8743 + seq_printf(m, " %d", ent->id);
8744 + seq_printf(m, "\n");
8748 +static struct ent *nametoid_lookup(struct ent *, int);
8749 +int nametoid_parse(struct cache_detail *, char *, int);
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,
8762 +nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
8764 + struct ent ent, *res;
8766 + int error = -EINVAL;
8768 + if (buf[buflen - 1] != '\n')
8770 + buf[buflen - 1]= '\0';
8772 + buf1 = kmalloc(PAGE_SIZE, GFP_KERNEL);
8776 + memset(&ent, 0, sizeof(ent));
8778 + /* Authentication name */
8779 + if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8781 + memcpy(ent.authname, buf1, sizeof(ent.authname));
8784 + if (qword_get(&buf, buf1, PAGE_SIZE) <= 0)
8786 + ent.type = strcmp(buf1, "user") == 0 ?
8787 + IDMAP_TYPE_USER : IDMAP_TYPE_GROUP;
8790 + error = qword_get(&buf, buf1, PAGE_SIZE);
8791 + if (error <= 0 || error >= IDMAP_NAMESZ)
8793 + memcpy(ent.name, buf1, sizeof(ent.name));
8796 + ent.h.expiry_time = get_expiry(&buf);
8797 + if (ent.h.expiry_time == 0)
8801 + error = get_int(&buf, &ent.id);
8802 + if (error == -EINVAL)
8804 + if (error == -ENOENT)
8805 + set_bit(CACHE_NEGATIVE, &ent.h.flags);
8808 + if ((res = nametoid_lookup(&ent, 1)) == NULL)
8811 + ent_put(&res->h, &nametoid_cache);
8819 +static DefineSimpleCacheLookupMap(ent, nametoid);
8826 +nfsd_idmap_init(void)
8828 + cache_register(&idtoname_cache);
8829 + cache_register(&nametoid_cache);
8833 +nfsd_idmap_shutdown(void)
8835 + cache_unregister(&idtoname_cache);
8836 + cache_unregister(&nametoid_cache);
8840 + * Deferred request handling
8843 +struct idmap_defer_req {
8844 + struct cache_req req;
8845 + struct cache_deferred_req deferred_req;
8846 + wait_queue_head_t waitq;
8851 +put_mdr(struct idmap_defer_req *mdr)
8853 + if (atomic_dec_and_test(&mdr->count))
8858 +idmap_revisit(struct cache_deferred_req *dreq, int toomany)
8860 + struct idmap_defer_req *mdr =
8861 + container_of(dreq, struct idmap_defer_req, deferred_req);
8863 + wake_up(&mdr->waitq);
8867 +static struct cache_deferred_req *
8868 +idmap_defer(struct cache_req *req)
8870 + struct idmap_defer_req *mdr =
8871 + container_of(req, struct idmap_defer_req, req);
8873 + mdr->deferred_req.revisit = idmap_revisit;
8874 + return (&mdr->deferred_req);
8877 +static int threads_waiting = 0;
8880 +idmap_lookup_wait(struct idmap_defer_req *mdr, wait_queue_t waitq, struct
8881 + svc_rqst *rqstp) {
8882 + int ret = -ETIMEDOUT;
8884 + set_task_state(current, TASK_INTERRUPTIBLE);
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)
8890 + threads_waiting++;
8891 + schedule_timeout(10 * HZ);
8892 + threads_waiting--;
8896 + remove_wait_queue(&mdr->waitq, &waitq);
8897 + set_task_state(current, TASK_RUNNING);
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)
8907 + struct idmap_defer_req *mdr;
8908 + DECLARE_WAITQUEUE(waitq, current);
8911 + *item = lookup_fn(key, 0);
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);
8925 + /* Try again, but don't wait. */
8926 + *item = lookup_fn(key, 0);
8931 + if (!test_bit(CACHE_VALID, &(*item)->h.flags)) {
8932 + ent_put(&(*item)->h, detail);
8935 + ret = cache_check(detail, &(*item)->h, NULL);
8942 +idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
8945 + struct ent *item, key = {
8950 + if (namelen + 1 > sizeof(key.name))
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);
8959 + ent_put(&item->h, &nametoid_cache);
8964 +idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
8966 + struct ent *item, key = {
8972 + strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
8973 + ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item);
8976 + ret = strlen(item->name);
8977 + BUG_ON(ret > IDMAP_NAMESZ);
8978 + memcpy(name, item->name, ret);
8979 + ent_put(&item->h, &idtoname_cache);
8984 +nfsd_map_name_to_uid(struct svc_rqst *rqstp, const char *name, size_t namelen,
8987 + return idmap_name_to_id(rqstp, IDMAP_TYPE_USER, name, namelen, id);
8991 +nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
8994 + return idmap_name_to_id(rqstp, IDMAP_TYPE_GROUP, name, namelen, id);
8998 +nfsd_map_uid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
9000 + return idmap_id_to_name(rqstp, IDMAP_TYPE_USER, id, name);
9004 +nfsd_map_gid_to_name(struct svc_rqst *rqstp, __u32 id, char *name)
9006 + return idmap_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name);
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
9012 #include <linux/init.h>
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);
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 },
9045 { nfserr_stale, -ESTALE },
9046 + { nfserr_jukebox, -ETIMEDOUT },
9047 { nfserr_dropit, -EAGAIN },
9048 { nfserr_dropit, -ENOMEM },
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
9055 + * include/linux/nfsd_idmap.h
9057 + * Mapping of UID to name and vice versa.
9059 + * Copyright (c) 2002, 2003 The Regents of the University of
9060 + * Michigan. All rights reserved.
9062 + * Marius Aamodt Eriksen <marius@umich.edu>
9064 + * Redistribution and use in source and binary forms, with or without
9065 + * modification, are permitted provided that the following conditions
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.
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.
9090 +#ifndef LINUX_NFSD_IDMAP_H
9091 +#define LINUX_NFSD_IDMAP_H
9093 +#include <linux/in.h>
9094 +#include <linux/sunrpc/svc.h>
9096 +/* XXX from linux/nfs_idmap.h */
9097 +#define IDMAP_NAMESZ 128
9099 +void nfsd_idmap_init(void);
9100 +void nfsd_idmap_shutdown(void);
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 *);
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
9112 #ifndef _LINUX_NFSD_XDR4_H
9113 #define _LINUX_NFSD_XDR4_H
9115 +#include <linux/nfs4.h>
9117 #define NFSD4_MAX_TAGLEN 128
9118 #define XDR_LEN(n) (((n) + 3) & ~3)
9120 @@ -54,10 +56,10 @@ typedef struct {
9122 struct nfsd4_change_info {
9128 + u32 before_ctime_sec;
9129 + u32 before_ctime_nsec;
9130 + u32 after_ctime_sec;
9131 + u32 after_ctime_nsec;
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;
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 */
9148 + struct nfs4_acl *op_acl;
9150 #define op_iattr u.iattr
9151 #define op_verf u.verf
9152 @@ -263,6 +266,10 @@ struct nfsd4_readdir {
9156 +struct nfsd4_release_lockowner {
9157 + clientid_t rl_clientid;
9158 + struct xdr_netobj rl_owner;
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;
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;
9177 struct nfs4_replay * replay;
9179 @@ -373,9 +382,12 @@ struct nfsd4_compoundargs {
9182 struct tmpbuf *next;
9183 + void (*release)(const void *);
9188 + struct svc_rqst *rqstp;
9193 @@ -404,10 +416,10 @@ set_change_info(struct nfsd4_change_info
9195 BUG_ON(!fhp->fh_pre_saved || !fhp->fh_post_saved);
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;
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,
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 *);
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
9233 - * map between user/group name and id for a given 'client'
9239 -static inline int name_get_user(int uid, struct name_ent **namep)
9241 - struct name_ent *n = kmalloc(sizeof(*n),GFP_KERNEL);
9242 - if (n) sprintf(n->name, "%d",uid);
9244 - return n ? 0 : -ENOMEM;
9246 -static inline int name_get_group(int uid, struct name_ent **namep)
9248 - struct name_ent *n = kmalloc(sizeof(*n),GFP_KERNEL);
9249 - if (n) sprintf(n->name, "%d",uid);
9251 - return n ? 0 : -ENOMEM;
9253 -static inline int name_get_uid(char *name, int name_len, int *uidp)
9255 - *uidp = simple_strtoul(name, NULL, 0);
9259 -static inline int name_get_gid(char *name, int name_len, int *gidp)
9261 - *gidp = simple_strtoul(name, NULL, 0);
9265 -static inline void name_put(struct name_ent *ent)
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
9285 + * fs/nfs4acl/acl.c
9287 + * Common NFSv4 ACL handling code.
9289 + * Copyright (c) 2002, 2003 The Regents of the University of Michigan.
9290 + * All rights reserved.
9292 + * Marius Aamodt Eriksen <marius@umich.edu>
9293 + * Jeff Sedlak <jsedlak@umich.edu>
9295 + * Redistribution and use in source and binary forms, with or without
9296 + * modification, are permitted provided that the following conditions
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.
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.
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>
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)
9337 +#define MASK_EQUAL(mask1, mask2) \
9338 + ( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )
9341 +mask_from_posix(unsigned short perm, int owner)
9343 + int mask = NFS4_ANYONE_MODE;
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;
9356 +mode_from_nfs4(u32 perm, unsigned short *mode, int owner)
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;
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)))
9374 +struct ace_container {
9375 + struct nfs4_ace *ace;
9376 + struct list_head ace_l;
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 *);
9384 +nfs4_acl_posix_to_nfsv4(struct nfs4_acl_idmapper *idmapper, void *idarg,
9385 + struct posix_acl *pacl, struct posix_acl *dpacl)
9387 + struct nfs4_acl *acl;
9388 + int error = -EINVAL;
9390 + if ((pacl != NULL &&
9391 + (posix_acl_valid(pacl) < 0 || pacl->a_count == 0)) ||
9393 + (posix_acl_valid(dpacl) < 0 || dpacl->a_count == 0)))
9396 + acl = nfs4_acl_new();
9397 + if (acl == NULL) {
9402 + if (pacl != NULL) {
9403 + error = _posix_to_nfsv4_one(idmapper, idarg, pacl, acl, 0);
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);
9420 + nfs4_acl_free(acl);
9422 + acl = ERR_PTR(error);
9428 +nfs4_acl_add_pair(struct nfs4_acl *acl, int eflag, u32 mask, char *owner,
9433 + error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
9434 + eflag, mask, owner, owner_len);
9437 + error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9438 + eflag, ~mask, owner, owner_len);
9442 +/* We assume the acl has been verified with posix_acl_valid. */
9444 +_posix_to_nfsv4_one(struct nfs4_acl_idmapper *idmapper, void *idarg,
9445 + struct posix_acl *pacl, struct nfs4_acl *acl, int eflag)
9447 + struct posix_acl_entry *pa, *pe, *group_owner_entry;
9448 + int error = -EINVAL;
9449 + u32 mask, mask_mask;
9450 + char xname[IDMAP_NAMESZ];
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);
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);
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);
9477 + error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9478 + eflag, mask_mask, xname, xnamelen);
9483 + error = nfs4_acl_add_pair(acl, eflag, mask, xname, xnamelen);
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. */
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);
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);
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);
9518 + error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9519 + NFS4_ACE_IDENTIFIER_GROUP | eflag,
9520 + mask_mask, xname, xnamelen);
9524 + error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE,
9525 + NFS4_ACE_IDENTIFIER_GROUP | eflag, mask, xname, xnamelen);
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);
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);
9548 + error = nfs4_acl_add_ace(acl, NFS4_ACE_ACCESS_DENIED_ACE_TYPE,
9549 + NFS4_ACE_IDENTIFIER_GROUP | eflag, ~mask, xname, xnamelen);
9555 + if (pa->e_tag == ACL_MASK)
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);
9567 +sort_pacl_range(struct posix_acl *pacl, int start, int end) {
9568 + int sorted = 0, i;
9569 + struct posix_acl_entry tmp;
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. */
9575 + for (i = start; i < end; i++) {
9576 + if (pacl->a_entries[i].e_id
9577 + > pacl->a_entries[i+1].e_id) {
9579 + tmp = pacl->a_entries[i];
9580 + pacl->a_entries[i] = pacl->a_entries[i+1];
9581 + pacl->a_entries[i+1] = tmp;
9588 +sort_pacl(struct posix_acl *pacl)
9590 + /* posix_acl_valid requires that users and groups be in order
9594 + if (pacl->a_count <= 4)
9595 + return; /* no users or groups */
9597 + while (pacl->a_entries[i].e_tag == ACL_USER)
9599 + sort_pacl_range(pacl, 1, i-1);
9601 + BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);
9603 + while (pacl->a_entries[j].e_tag == ACL_GROUP)
9605 + sort_pacl_range(pacl, i, j-1);
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)
9614 + struct posix_acl_entry *this = *pace;;
9616 + if (*pace == pacl->a_entries + pacl->a_count)
9617 + return -EINVAL; /* fell off the end */
9619 + this->e_tag = tag;
9620 + if (mode_from_nfs4(ace->access_mask, &this->e_perm,
9621 + tag == ACL_USER_OBJ))
9625 + return idmapper->name2uid(idarg, ace->who, ace->wholen,
9628 + return idmapper->name2gid(idarg, ace->who, ace->wholen,
9631 + this->e_id = ACL_UNDEFINED_ID;
9636 +static struct nfs4_ace *
9637 +get_next_v4_ace(struct list_head **p, struct list_head *head)
9639 + struct nfs4_ace *ace;
9644 + ace = list_entry(*p, struct nfs4_ace, l_ace);
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)
9654 + struct nfs4_acl *dacl;
9655 + int error = -ENOMEM;
9660 + dacl = nfs4_acl_new();
9664 + error = nfs4_acl_split(acl, dacl);
9668 + if (pacl != NULL) {
9669 + if (acl->naces == 0) {
9674 + *pacl = _nfsv4_to_posix_one(idmapper, idarg, acl);
9675 + if (IS_ERR(*pacl)) {
9676 + error = PTR_ERR(*pacl);
9683 + if (dpacl != NULL) {
9684 + if (dacl->naces == 0) {
9685 + if (pacl == NULL || *pacl == NULL)
9691 + *dpacl = _nfsv4_to_posix_one(idmapper, idarg, dacl);
9692 + if (IS_ERR(*dpacl)) {
9693 + error = PTR_ERR(*dpacl);
9700 + if (error && pacl) {
9701 + posix_acl_release(*pacl);
9704 + nfs4_acl_free(dacl);
9710 +complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny)
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;
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)
9725 + int error = -EINVAL;
9726 + struct nfs4_ace *ace, *ace2;
9728 + ace = get_next_v4_ace(p, &n4acl->ace_head);
9731 + if (ace2type(ace) != ACL_USER_OBJ)
9733 + error = write_pace(ace, pacl, pace, ACL_USER_OBJ, idmapper, idarg);
9737 + ace2 = get_next_v4_ace(p, &n4acl->ace_head);
9740 + if (!complementary_ace_pair(ace, ace2))
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)
9753 + int error = -EINVAL;
9754 + struct nfs4_ace *ace, *ace2;
9756 + ace = get_next_v4_ace(p, &n4acl->ace_head);
9759 + while (ace2type(ace) == ACL_USER) {
9760 + if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
9763 + !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
9766 + ace = get_next_v4_ace(p, &n4acl->ace_head);
9769 + if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
9771 + error = write_pace(ace, pacl, pace, ACL_USER, idmapper, idarg);
9775 + ace2 = get_next_v4_ace(p, &n4acl->ace_head);
9778 + if (!complementary_ace_pair(ace, ace2))
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)
9785 + ace = get_next_v4_ace(p, &n4acl->ace_head);
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)
9800 + int error = -EINVAL;
9801 + struct nfs4_ace *ace, *ace2;
9802 + struct ace_container *ac;
9803 + struct list_head group_l;
9805 + INIT_LIST_HEAD(&group_l);
9806 + ace = list_entry(*p, struct nfs4_ace, l_ace);
9808 + /* group owner (mask and allow aces) */
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)
9815 + !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
9818 + ace = get_next_v4_ace(p, &n4acl->ace_head);
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)
9829 + if (ace2type(ace) != ACL_GROUP_OBJ)
9832 + ac = kmalloc(sizeof(*ac), GFP_KERNEL);
9837 + list_add_tail(&ac->ace_l, &group_l);
9840 + if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
9843 + error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, idmapper, idarg);
9848 + ace = get_next_v4_ace(p, &n4acl->ace_head);
9852 + /* groups (mask and allow aces) */
9854 + while (ace2type(ace) == ACL_GROUP) {
9855 + if (*mask_ace == NULL)
9858 + if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
9859 + !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
9863 + ace = get_next_v4_ace(p, &n4acl->ace_head);
9866 + ac = kmalloc(sizeof(*ac), GFP_KERNEL);
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)
9877 + list_add_tail(&ac->ace_l, &group_l);
9879 + error = write_pace(ace, pacl, pace, ACL_GROUP, idmapper, idarg);
9883 + ace = get_next_v4_ace(p, &n4acl->ace_head);
9888 + /* group owner (deny ace) */
9890 + if (ace2type(ace) != ACL_GROUP_OBJ)
9892 + ac = list_entry(group_l.next, struct ace_container, ace_l);
9894 + if (!complementary_ace_pair(ace2, ace))
9896 + list_del(group_l.next);
9899 + /* groups (deny aces) */
9901 + while (!list_empty(&group_l)) {
9902 + ace = get_next_v4_ace(p, &n4acl->ace_head);
9905 + if (ace2type(ace) != ACL_GROUP)
9907 + ac = list_entry(group_l.next, struct ace_container, ace_l);
9909 + if (!complementary_ace_pair(ace2, ace))
9911 + list_del(group_l.next);
9915 + ace = get_next_v4_ace(p, &n4acl->ace_head);
9918 + if (ace2type(ace) != ACL_OTHER)
9922 + while (!list_empty(&group_l)) {
9923 + ac = list_entry(group_l.next, struct ace_container, ace_l);
9924 + list_del(group_l.next);
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)
9936 + int error = -EINVAL;
9937 + struct nfs4_ace *ace;
9939 + ace = list_entry(*p, struct nfs4_ace, l_ace);
9940 + if (pacl->a_count != 3) {
9941 + if (*mask_ace == NULL)
9943 + (*mask_ace)->access_mask = ~(*mask_ace)->access_mask;
9944 + write_pace(*mask_ace, pacl, pace, ACL_MASK, idmapper, idarg);
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)
9956 + int error = -EINVAL;
9957 + struct nfs4_ace *ace, *ace2;
9959 + ace = list_entry(*p, struct nfs4_ace, l_ace);
9960 + if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
9962 + error = write_pace(ace, pacl, pace, ACL_OTHER, idmapper, idarg);
9966 + ace2 = get_next_v4_ace(p, &n4acl->ace_head);
9969 + if (!complementary_ace_pair(ace, ace2))
9977 +calculate_posix_ace_count(struct nfs4_acl *n4acl)
9979 + if (n4acl->naces == 6) /* owner, owner group, and other only */
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)
9986 + return 4 + (n4acl->naces - 7)/3;
9991 +static struct posix_acl *
9992 +_nfsv4_to_posix_one(struct nfs4_acl_idmapper *idmapper, void *idarg, struct nfs4_acl *n4acl)
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;
10000 + nace = calculate_posix_ace_count(n4acl);
10002 + pacl = posix_acl_alloc(nace, GFP_KERNEL);
10004 + if (pacl == NULL)
10007 + pace = &pacl->a_entries[0];
10008 + p = &n4acl->ace_head;
10010 + error = user_obj_from_v4(n4acl, &p, pacl, &pace, idmapper, idarg);
10014 + error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, idmapper,
10019 + error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace,
10020 + idmapper, idarg);
10024 + error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, idmapper, idarg);
10027 + error = other_from_v4(n4acl, &p, pacl, &pace, idmapper, idarg);
10032 + if (p->next != &n4acl->ace_head)
10034 + if (pace != pacl->a_entries + pacl->a_count)
10041 + posix_acl_release(pacl);
10043 + pacl = ERR_PTR(error);
10049 +nfs4_acl_new(void)
10051 + struct nfs4_acl *acl;
10053 + if ((acl = kmalloc(sizeof(*acl), GFP_KERNEL)) == NULL)
10057 + INIT_LIST_HEAD(&acl->ace_head);
10063 +nfs4_acl_free(struct nfs4_acl *acl)
10065 + struct list_head *h;
10066 + struct nfs4_ace *ace;
10071 + while (!list_empty(&acl->ace_head)) {
10072 + h = acl->ace_head.next;
10074 + ace = list_entry(h, struct nfs4_ace, l_ace);
10075 + if (ace->who != NULL)
10086 +nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask,
10087 + char *who, u32 wholen)
10089 + struct nfs4_ace *ace;
10091 + if ((ace = kmalloc(sizeof(*ace), GFP_KERNEL)) == NULL)
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)
10100 + memcpy(ace->who, who, wholen);
10102 + ace->wholen = wholen;
10104 + list_add_tail(&ace->l_ace, &acl->ace_head);
10106 + return ++acl->naces; /* XXXJBF: why? */
10115 +nfs4_acl_merge(struct nfs4_acl *fromacl, struct nfs4_acl *withacl)
10117 + struct nfs4_ace *ace;
10118 + struct list_head *h;
10120 + if (fromacl == NULL || withacl == NULL)
10123 + while (!list_empty(&fromacl->ace_head)) {
10124 + h = fromacl->ace_head.next;
10126 + ace = list_entry(h, struct nfs4_ace, l_ace);
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++;
10138 +nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
10140 + struct list_head *h, *n;
10141 + struct nfs4_ace *ace;
10144 + list_for_each_safe(h, n, &acl->ace_head) {
10145 + ace = list_entry(h, struct nfs4_ace, l_ace);
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))
10152 + error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
10153 + ace->access_mask, ace->who, ace->wholen) == -1;
10158 + if (ace->who != NULL)
10174 + .string = "OWNER@",
10175 + .stringlen = sizeof("OWNER@") - 1,
10176 + .type = ACL_USER_OBJ
10179 + .string = "GROUP@",
10180 + .stringlen = sizeof("GROUP@") - 1,
10181 + .type = ACL_GROUP_OBJ
10184 + .string = "EVERYONE@",
10185 + .stringlen = sizeof("EVERYONE@") - 1,
10186 + .type = ACL_OTHER
10191 +ace2type(struct nfs4_ace *ace)
10195 + if (ace->who == NULL || ace->wholen <= 0)
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);
10203 + return (ace->flag & NFS4_ACE_IDENTIFIER_GROUP ? ACL_GROUP : ACL_USER);
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
10210 + * fs/nfs4acl/acl_syms.c
10212 + * Common NFSv4 ACL handling symbol exports.
10214 + * Copyright (c) 2002 The Regents of the University of Michigan.
10215 + * All rights reserved.
10217 + * Marius Aamodt Eriksen <marius@umich.edu>
10219 + * Redistribution and use in source and binary forms, with or without
10220 + * modification, are permitted provided that the following conditions
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.
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.
10246 +#include <linux/config.h>
10247 +#include <linux/module.h>
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>
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
10264 +obj-$(CONFIG_NFS_V4_ACL) += nfs4acl.o
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
10272 + * include/linux/nfs4_acl.c
10274 + * Common NFSv4 ACL handling definitions.
10276 + * Copyright (c) 2002 The Regents of the University of Michigan.
10277 + * All rights reserved.
10279 + * Marius Aamodt Eriksen <marius@umich.edu>
10281 + * Redistribution and use in source and binary forms, with or without
10282 + * modification, are permitted provided that the following conditions
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.
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.
10307 +#ifndef LINUX_NFS4_ACL_H
10308 +#define LINUX_NFS4_ACL_H
10310 +#include <linux/posix_acl.h>
10312 +#define NFS4_ACL_TYPE_ACCESS 0
10313 +#define NFS4_ACL_TYPE_DEFAULT 1
10315 +/* XXX from include/linux/nfs_idmap.h: */
10316 +#define IDMAP_NAMESZ 128
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 *);
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 **);
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
10348 #define NFS4_SET_TO_SERVER_TIME 0
10349 #define NFS4_SET_TO_CLIENT_TIME 1
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
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
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
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
10404 + struct list_head l_ace;
10409 + struct list_head ace_head;
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,
10418 + OP_RELEASE_LOCKOWNER = 39,
10419 + OP_ILLEGAL = 10044,
10423 @@ -283,7 +338,6 @@ enum lock_type4 {
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,
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
10458 #include <linux/nfs4.h>
10459 #include <linux/nfs_fs.h>
10460 #include <linux/nfs_idmap.h>
10461 +#include <linux/nfs4_acl.h>
10463 #define NFSDBG_FACILITY NFSDBG_XDR
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 + \
10491 +#define encode_rename_maxsz op_encode_hdr_maxsz + \
10492 + 2 * nfs4_name_maxsz
10493 +#define encode_link_maxsz op_encode_hdr_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
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
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
10660 @@ -333,8 +490,7 @@ encode_compound_hdr(struct xdr_stream *x
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)
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.
10679 @@ -392,6 +548,7 @@ encode_attrs(struct xdr_stream *xdr, str
10681 else if (iap->ia_valid & ATTR_MTIME)
10684 RESERVE_SPACE(len);
10687 @@ -462,13 +619,13 @@ encode_attrs(struct xdr_stream *xdr, str
10691 -encode_access(struct xdr_stream *xdr, struct nfs4_access *access)
10692 +encode_access(struct xdr_stream *xdr, u32 access)
10697 WRITE32(OP_ACCESS);
10698 - WRITE32(access->ac_req_access);
10703 @@ -500,37 +657,36 @@ encode_commit(struct xdr_stream *xdr, st
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)
10714 WRITE32(OP_CREATE);
10715 - WRITE32(create->cr_ftype);
10716 + WRITE32(create->ftype);
10718 - switch (create->cr_ftype) {
10719 + switch (create->ftype) {
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);
10729 case NF4BLK: case NF4CHR:
10731 - WRITE32(create->cr_specdata1);
10732 - WRITE32(create->cr_specdata2);
10733 + WRITE32(create->u.device.specdata1);
10734 + WRITE32(create->u.device.specdata2);
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);
10748 - return encode_attrs(xdr, create->cr_attrs, server);
10749 + return encode_attrs(xdr, create->attrs, create->server);
10753 @@ -558,11 +714,14 @@ encode_getattr_two(struct xdr_stream *xd
10757 +extern u32 nfs4_fattr_bitmap[];
10758 +extern u32 nfs4_statfs_bitmap[];
10761 -encode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr)
10762 +encode_getfattr(struct xdr_stream *xdr)
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]);
10771 @@ -618,14 +777,14 @@ encode_getfh(struct xdr_stream *xdr)
10775 -encode_link(struct xdr_stream *xdr, struct nfs4_link *link)
10776 +encode_link(struct xdr_stream *xdr, struct qstr *name)
10780 - RESERVE_SPACE(8 + link->ln_namelen);
10781 + RESERVE_SPACE(8 + name->len);
10783 - WRITE32(link->ln_namelen);
10784 - WRITEMEM(link->ln_name, link->ln_namelen);
10785 + WRITE32(name->len);
10786 + WRITEMEM(name->name, name->len);
10790 @@ -705,15 +864,15 @@ encode_locku(struct xdr_stream *xdr, str
10794 -encode_lookup(struct xdr_stream *xdr, struct nfs4_lookup *lookup)
10795 +encode_lookup(struct xdr_stream *xdr, struct qstr *name)
10797 - int len = lookup->lo_name->len;
10798 + int len = name->len;
10801 RESERVE_SPACE(8 + len);
10802 WRITE32(OP_LOOKUP);
10804 - WRITEMEM(lookup->lo_name->name, len);
10805 + WRITEMEM(name->name, len);
10809 @@ -883,7 +1042,7 @@ encode_read(struct xdr_stream *xdr, stru
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)
10816 struct rpc_auth *auth = req->rq_task->tk_auth;
10818 @@ -891,21 +1050,21 @@ encode_readdir(struct xdr_stream *xdr, s
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);
10831 - WRITE32(readdir->rd_bmval[0]);
10832 - WRITE32(readdir->rd_bmval[1]);
10833 + WRITE32(FATTR4_WORD0_FILEID);
10836 /* set up reply iovec
10837 * toplevel_status + taglen + rescount + OP_PUTFH + status
10838 * + OP_READDIR + status + verifer(2) = 9
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);
10848 @@ -925,37 +1084,37 @@ encode_readlink(struct xdr_stream *xdr,
10849 * + OP_READLINK + status = 7
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);
10859 -encode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove)
10860 +encode_remove(struct xdr_stream *xdr, struct qstr *name)
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);
10876 -encode_rename(struct xdr_stream *xdr, struct nfs4_rename *rename)
10877 +encode_rename(struct xdr_stream *xdr, struct qstr *oldname, struct qstr *newname)
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);
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);
10898 @@ -1011,6 +1170,39 @@ encode_setattr(struct xdr_stream *xdr, s
10902 +extern nfs4_stateid zero_stateid;
10904 +#ifdef CONFIG_NFS_V4_ACL
10907 +encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
10909 + uint32_t *p, *attrbuflen;
10910 + struct nfs4_ace *ace;
10911 + struct nfs4_acl *acl = arg->acl;
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);
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);
10929 + *attrbuflen = htonl((char *)p - (char *)attrbuflen - 4);
10933 +#endif /* CONFIG_NFS_V4_ACL */
10936 encode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid *setclientid)
10938 @@ -1068,312 +1260,566 @@ encode_write(struct xdr_stream *xdr, str
10943 -/* FIXME: this sucks */
10945 -encode_compound(struct xdr_stream *xdr, struct nfs4_compound *cp, struct rpc_rqst *req)
10947 - struct compound_hdr hdr = {
10948 - .taglen = cp->taglen,
10950 - .nops = cp->req_nops,
10952 - int i, status = 0;
10954 - encode_compound_hdr(xdr, &hdr);
10956 - for (i = 0; i < cp->req_nops; i++) {
10957 - switch (cp->ops[i].opnum) {
10959 - status = encode_access(xdr, &cp->ops[i].u.access);
10962 - status = encode_create(xdr, &cp->ops[i].u.create, cp->server);
10965 - status = encode_getattr(xdr, &cp->ops[i].u.getattr);
10968 - status = encode_getfh(xdr);
10971 - status = encode_link(xdr, &cp->ops[i].u.link);
10974 - status = encode_lookup(xdr, &cp->ops[i].u.lookup);
10977 - status = encode_putfh(xdr, cp->ops[i].u.putfh.pf_fhandle);
10979 - case OP_PUTROOTFH:
10980 - status = encode_putrootfh(xdr);
10983 - status = encode_readdir(xdr, &cp->ops[i].u.readdir, req);
10985 - case OP_READLINK:
10986 - status = encode_readlink(xdr, &cp->ops[i].u.readlink, req);
10989 - status = encode_remove(xdr, &cp->ops[i].u.remove);
10992 - status = encode_rename(xdr, &cp->ops[i].u.rename);
10994 - case OP_RESTOREFH:
10995 - status = encode_restorefh(xdr);
10998 - status = encode_savefh(xdr);
11010 * END OF "GENERIC" ENCODE ROUTINES.
11015 - * Encode COMPOUND argument
11016 + * Encode ACCESS request
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)
11022 struct xdr_stream xdr;
11023 + struct compound_hdr hdr = {
11028 - xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11029 - status = encode_compound(&xdr, cp, req);
11030 - cp->timestamp = jiffies;
11034 - * Encode a CLOSE request
11037 -nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
11039 - struct xdr_stream xdr;
11040 - struct compound_hdr hdr = {
11045 - xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11046 - encode_compound_hdr(&xdr, &hdr);
11047 - status = encode_putfh(&xdr, args->fh);
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);
11056 + status = encode_getfattr(&xdr);
11059 + status = encode_access(&xdr, args->req_access);
11066 - * Encode an OPEN request
11067 + * Encode LOOKUP request
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)
11073 struct xdr_stream xdr;
11074 struct compound_hdr hdr = {
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);
11086 - status = encode_savefh(&xdr);
11087 + status = encode_getfattr(&xdr);
11090 - status = encode_open(&xdr, args);
11091 + status = encode_lookup(&xdr, args->name);
11094 - status = encode_getattr(&xdr, args->f_getattr);
11095 + status = encode_getfattr(&xdr);
11098 status = encode_getfh(&xdr);
11101 - status = encode_restorefh(&xdr);
11104 - status = encode_getattr(&xdr, args->d_getattr);
11110 - * Encode an OPEN_CONFIRM request
11111 + * Encode GETROOT_HEAD request
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)
11117 struct xdr_stream xdr;
11118 struct compound_hdr hdr = {
11124 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11125 encode_compound_hdr(&xdr, &hdr);
11126 - status = encode_putfh(&xdr, args->fh);
11128 + status = encode_putrootfh(&xdr);
11131 - status = encode_open_confirm(&xdr, args);
11132 + status = encode_getfattr(&xdr);
11135 + status = encode_getfh(&xdr);
11141 - * Encode an OPEN request
11142 + * Encode GETROOT_PATH request
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)
11149 struct xdr_stream xdr;
11150 struct compound_hdr hdr = {
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);
11162 - status = encode_open_reclaim(&xdr, args);
11163 + status = encode_lookup(&xdr, args->name);
11166 + status = encode_getfattr(&xdr);
11169 - status = encode_getattr(&xdr, args->f_getattr);
11170 + status = encode_getfh(&xdr);
11176 - * Encode an OPEN_DOWNGRADE request
11177 + * Encode REMOVE request
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)
11183 struct xdr_stream xdr;
11184 struct compound_hdr hdr = {
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);
11196 - status = encode_open_downgrade(&xdr, args);
11197 + status = encode_remove(&xdr, args->name);
11200 + status = encode_getfattr(&xdr);
11206 - * Encode a LOCK request
11207 + * Encode UNLINK request
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)
11213 struct xdr_stream xdr;
11214 struct compound_hdr hdr = {
11220 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11221 encode_compound_hdr(&xdr, &hdr);
11222 status = encode_putfh(&xdr, args->fh);
11226 - status = encode_lock(&xdr, args);
11227 + status = encode_remove(&xdr, args->name);
11230 + status = encode_getfattr(&xdr);
11236 - * Encode a LOCKT request
11237 + * Encode RENAME request
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)
11243 struct xdr_stream xdr;
11244 struct compound_hdr hdr = {
11250 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11251 encode_compound_hdr(&xdr, &hdr);
11252 - status = encode_putfh(&xdr, args->fh);
11254 + status = encode_putfh(&xdr, args->old_dir);
11257 - status = encode_lockt(&xdr, args);
11258 + status = encode_savefh(&xdr);
11261 + status = encode_putfh(&xdr, args->new_dir);
11264 + status = encode_rename(&xdr, args->old_name, args->new_name);
11267 + status = encode_getfattr(&xdr);
11270 + status = encode_restorefh(&xdr);
11273 + status = encode_getfattr(&xdr);
11279 - * Encode a LOCKU request
11280 + * Encode LINK request
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)
11286 struct xdr_stream xdr;
11287 struct compound_hdr hdr = {
11293 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11294 encode_compound_hdr(&xdr, &hdr);
11295 status = encode_putfh(&xdr, args->fh);
11299 - status = encode_locku(&xdr, args);
11300 + status = encode_savefh(&xdr);
11303 + status = encode_putfh(&xdr, args->dir_fh);
11306 + status = encode_link(&xdr, args->name);
11309 + status = encode_getfattr(&xdr);
11312 + status = encode_restorefh(&xdr);
11315 + status = encode_getfattr(&xdr);
11321 - * Encode a READ request
11322 + * Encode CREATE request
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)
11328 - struct rpc_auth *auth = req->rq_task->tk_auth;
11329 struct xdr_stream xdr;
11330 struct compound_hdr hdr = {
11334 - int replen, status;
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);
11343 - status = encode_read(&xdr, args);
11344 + status = encode_savefh(&xdr);
11347 - status = encode_read_getattr(&xdr);
11349 - /* set up reply iovec
11350 - * toplevel status + taglen=0 + rescount + OP_PUTFH + status
11351 + status = encode_create(&xdr, args);
11354 + status = encode_getfattr(&xdr);
11357 + status = encode_getfh(&xdr);
11360 + status = encode_restorefh(&xdr);
11363 + status = encode_getfattr(&xdr);
11369 + * Encode GETATTR request
11372 +nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, struct nfs_fh *fh)
11374 + struct xdr_stream xdr;
11375 + struct compound_hdr hdr = {
11380 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11381 + encode_compound_hdr(&xdr, &hdr);
11382 + status = encode_putfh(&xdr, fh);
11385 + status = encode_getfattr(&xdr);
11391 + * Encode a CLOSE request
11394 +nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
11396 + struct xdr_stream xdr;
11397 + struct compound_hdr hdr = {
11402 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11403 + encode_compound_hdr(&xdr, &hdr);
11404 + status = encode_putfh(&xdr, args->fh);
11407 + status = encode_close(&xdr, args);
11413 + * Encode an OPEN request
11416 +nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
11418 + struct xdr_stream xdr;
11419 + struct compound_hdr hdr = {
11424 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11425 + encode_compound_hdr(&xdr, &hdr);
11426 + status = encode_putfh(&xdr, args->fh);
11429 + status = encode_savefh(&xdr);
11432 + status = encode_open(&xdr, args);
11435 + status = encode_getfattr(&xdr);
11438 + status = encode_getfh(&xdr);
11441 + status = encode_restorefh(&xdr);
11444 + status = encode_getfattr(&xdr);
11450 + * Encode an OPEN_CONFIRM request
11453 +nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
11455 + struct xdr_stream xdr;
11456 + struct compound_hdr hdr = {
11461 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11462 + encode_compound_hdr(&xdr, &hdr);
11463 + status = encode_putfh(&xdr, args->fh);
11466 + status = encode_open_confirm(&xdr, args);
11472 + * Encode an OPEN request
11475 +nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p,
11476 + struct nfs_open_reclaimargs *args)
11478 + struct xdr_stream xdr;
11479 + struct compound_hdr hdr = {
11484 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11485 + encode_compound_hdr(&xdr, &hdr);
11486 + status = encode_putfh(&xdr, args->fh);
11489 + status = encode_open_reclaim(&xdr, args);
11492 + status = encode_getfattr(&xdr);
11498 + * Encode an OPEN_DOWNGRADE request
11501 +nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
11503 + struct xdr_stream xdr;
11504 + struct compound_hdr hdr = {
11509 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11510 + encode_compound_hdr(&xdr, &hdr);
11511 + status = encode_putfh(&xdr, args->fh);
11514 + status = encode_open_downgrade(&xdr, args);
11520 + * Encode a LOCK request
11523 +nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
11525 + struct xdr_stream xdr;
11526 + struct compound_hdr hdr = {
11531 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11532 + encode_compound_hdr(&xdr, &hdr);
11533 + status = encode_putfh(&xdr, args->fh);
11536 + status = encode_lock(&xdr, args);
11542 + * Encode a LOCKT request
11545 +nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
11547 + struct xdr_stream xdr;
11548 + struct compound_hdr hdr = {
11553 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11554 + encode_compound_hdr(&xdr, &hdr);
11555 + status = encode_putfh(&xdr, args->fh);
11558 + status = encode_lockt(&xdr, args);
11564 + * Encode a LOCKU request
11567 +nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_lockargs *args)
11569 + struct xdr_stream xdr;
11570 + struct compound_hdr hdr = {
11575 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11576 + encode_compound_hdr(&xdr, &hdr);
11577 + status = encode_putfh(&xdr, args->fh);
11580 + status = encode_locku(&xdr, args);
11586 + * Encode a READLINK request
11589 +nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, struct nfs4_readlink *args)
11591 + struct xdr_stream xdr;
11592 + struct compound_hdr hdr = {
11597 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11598 + encode_compound_hdr(&xdr, &hdr);
11599 + status = encode_putfh(&xdr, args->fh);
11602 + status = encode_readlink(&xdr, args, req);
11608 + * Encode a READDIR request
11611 +nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, struct nfs4_readdir_arg *args)
11613 + struct xdr_stream xdr;
11614 + struct compound_hdr hdr = {
11619 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11620 + encode_compound_hdr(&xdr, &hdr);
11621 + status = encode_putfh(&xdr, args->fh);
11624 + status = encode_readdir(&xdr, args, req);
11630 + * Encode a READ request
11633 +nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
11635 + struct rpc_auth *auth = req->rq_task->tk_auth;
11636 + struct xdr_stream xdr;
11637 + struct compound_hdr hdr = {
11640 + int replen, status;
11642 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11643 + encode_compound_hdr(&xdr, &hdr);
11644 + status = encode_putfh(&xdr, args->fh);
11647 + status = encode_read(&xdr, args);
11650 + status = encode_read_getattr(&xdr);
11652 + /* set up reply iovec
11653 + * toplevel status + taglen=0 + rescount + OP_PUTFH + status
11654 * + OP_READ + status + eof + datalen = 9
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);
11661 - status = encode_getattr(&xdr, args->attr);
11662 + status = encode_getfattr(&xdr);
11667 +#ifdef CONFIG_NFS_V4_ACL
11670 + * Encode an SETACL request
11673 +nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args)
11676 + struct xdr_stream xdr;
11677 + struct compound_hdr hdr = {
11682 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11683 + encode_compound_hdr(&xdr, &hdr);
11684 + status = encode_putfh(&xdr, args->fh);
11687 + status = encode_setacl(&xdr, args);
11693 + * Encode a GETACL request
11696 +nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p,struct nfs_fh *fhandle)
11698 + struct xdr_stream xdr;
11699 + struct compound_hdr hdr = {
11704 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11705 + encode_compound_hdr(&xdr, &hdr);
11706 + status = encode_putfh(&xdr, fhandle);
11709 + status = encode_getattr_two(&xdr, FATTR4_WORD0_ACL, 0);
11715 +#endif /* CONFIG_NFS_V4_ACL */
11718 * Encode a WRITE request
11721 @@ -1487,6 +1983,48 @@ nfs4_xdr_enc_fsinfo(struct rpc_rqst *req
11725 + * a PATHCONF request
11728 +nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_fh *fhandle)
11730 + struct xdr_stream xdr;
11731 + struct compound_hdr hdr = {
11736 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11737 + encode_compound_hdr(&xdr, &hdr);
11738 + status = encode_putfh(&xdr, fhandle);
11740 + status = encode_getattr_one(&xdr,FATTR4_WORD0_MAXLINK |
11741 + FATTR4_WORD0_MAXNAME );
11746 + * a STATFS request
11749 +nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fh *fhandle)
11751 + struct xdr_stream xdr;
11752 + struct compound_hdr hdr = {
11757 + xdr_init_encode(&xdr, &req->rq_snd_buf, p);
11758 + encode_compound_hdr(&xdr, &hdr);
11759 + status = encode_putfh(&xdr, fhandle);
11761 + status = encode_getattr_two(&xdr,nfs4_statfs_bitmap[0],
11762 + nfs4_statfs_bitmap[1]);
11770 @@ -1636,7 +2174,7 @@ decode_change_info(struct xdr_stream *xd
11774 -decode_access(struct xdr_stream *xdr, struct nfs4_access *access)
11775 +decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
11778 uint32_t supp, acc;
11779 @@ -1648,12 +2186,12 @@ decode_access(struct xdr_stream *xdr, st
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");
11788 - *access->ac_resp_supported = supp;
11789 - *access->ac_resp_access = acc;
11790 + *access->resp_supported = supp;
11791 + *access->resp_access = acc;
11795 @@ -1686,7 +2224,7 @@ decode_commit(struct xdr_stream *xdr, st
11799 -decode_create(struct xdr_stream *xdr, struct nfs4_create *create)
11800 +decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
11804 @@ -1695,7 +2233,7 @@ decode_create(struct xdr_stream *xdr, st
11805 status = decode_op_hdr(xdr, OP_CREATE);
11808 - if ((status = decode_change_info(xdr, create->cr_cinfo)))
11809 + if ((status = decode_change_info(xdr, cinfo)))
11813 @@ -1703,17 +2241,144 @@ decode_create(struct xdr_stream *xdr, st
11817 -extern uint32_t nfs4_fattr_bitmap[2];
11818 extern uint32_t nfs4_fsstat_bitmap[2];
11819 -extern uint32_t nfs4_pathconf_bitmap[2];
11822 -decode_getattr(struct xdr_stream *xdr, struct nfs4_getattr *getattr,
11823 +decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
11825 + uint32_t attrlen, bmlen,
11832 + status = decode_op_hdr(xdr, OP_GETATTR);
11841 + READ_BUF((bmlen << 2) + 4);
11848 + if ((bmval0 & ~nfs4_statfs_bitmap[0]) ||
11849 + (bmval1 & ~nfs4_statfs_bitmap[1])) {
11850 + dprintk("read_attrs: server returned bad attributes!\n");
11854 + if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
11857 + READ64(fsstat->afiles);
11858 + dprintk("read_attrs: files_avail=0x%Lx\n", (long long) fsstat->afiles);
11860 + if (bmval0 & FATTR4_WORD0_FILES_FREE) {
11863 + READ64(fsstat->ffiles);
11864 + dprintk("read_attrs: files_free=0x%Lx\n", (long long) fsstat->ffiles);
11866 + if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
11869 + READ64(fsstat->tfiles);
11870 + dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles);
11873 + if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
11876 + READ64(fsstat->abytes);
11877 + dprintk("read_attrs: savail=0x%Lx\n", (long long) fsstat->abytes);
11879 + if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
11882 + READ64(fsstat->fbytes);
11883 + dprintk("read_attrs: sfree=0x%Lx\n", (long long) fsstat->fbytes);
11885 + if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
11888 + READ64(fsstat->tbytes);
11889 + dprintk("read_attrs: stotal=0x%Lx\n", (long long) fsstat->tbytes);
11891 + if (len != attrlen)
11898 +decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
11908 + status = decode_op_hdr(xdr, OP_GETATTR);
11914 + if ( (bmlen < 1) || (bmlen >2) )
11916 + READ_BUF((bmlen << 2) + 4);
11918 + if (bmval0 & ~(FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME)) {
11919 + goto out_bad_bitmap;
11921 + if (bmlen == 2) {
11924 + goto out_bad_bitmap;
11928 + if (bmval0 & FATTR4_WORD0_MAXLINK) {
11931 + READ32(pathconf->max_link);
11932 + dprintk("read_attrs: maxlink=%d\n", pathconf->max_link);
11934 + if (bmval0 & FATTR4_WORD0_MAXNAME) {
11937 + READ32(pathconf->max_namelen);
11938 + dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen);
11941 + if (len != attrlen)
11946 + printk(KERN_NOTICE "%s: server returned bad attribute bitmap\n",__FUNCTION__);
11950 + printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__);
11955 +decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *nfp,
11956 struct nfs_server *server)
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,
11964 @@ -1739,25 +2404,25 @@ decode_getattr(struct xdr_stream *xdr, s
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");
11976 - nfp->bitmap[0] = bmval0;
11977 - nfp->bitmap[1] = bmval1;
11982 + nfp->bitmap[0] = bmval0;
11983 + nfp->bitmap[1] = bmval1;
11986 * In case the server doesn't return some attributes,
11987 * we initialize them here to some nominal values..
11990 - nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
11992 - nfp->timestamp = jiffies;
11994 + nfp->valid = NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4;
11996 + nfp->timestamp = jiffies;
11998 if (bmval0 & FATTR4_WORD0_TYPE) {
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);
12005 - if (bmval0 & FATTR4_WORD0_FILES_AVAIL) {
12008 - READ64(fsstat->afiles);
12009 - dprintk("read_attrs: files_avail=0x%Lx\n", (long long) fsstat->afiles);
12011 - if (bmval0 & FATTR4_WORD0_FILES_FREE) {
12014 - READ64(fsstat->ffiles);
12015 - dprintk("read_attrs: files_free=0x%Lx\n", (long long) fsstat->ffiles);
12017 - if (bmval0 & FATTR4_WORD0_FILES_TOTAL) {
12020 - READ64(fsstat->tfiles);
12021 - dprintk("read_attrs: files_tot=0x%Lx\n", (long long) fsstat->tfiles);
12023 - if (bmval0 & FATTR4_WORD0_MAXLINK) {
12026 - READ32(pathconf->max_link);
12027 - dprintk("read_attrs: maxlink=%d\n", pathconf->max_link);
12029 - if (bmval0 & FATTR4_WORD0_MAXNAME) {
12032 - READ32(pathconf->max_namelen);
12033 - dprintk("read_attrs: maxname=%d\n", pathconf->max_namelen);
12036 if (bmval1 & FATTR4_WORD1_MODE) {
12039 @@ -1851,9 +2485,11 @@ decode_getattr(struct xdr_stream *xdr, s
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);
12049 + dprintk("read_attrs: nfs_map_name_to_uid failed!\n");
12053 dprintk("read_attrs: uid=%d\n", (int)nfp->uid);
12054 @@ -1868,10 +2504,12 @@ decode_getattr(struct xdr_stream *xdr, s
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);
12064 + dprintk("read_attrs: gss_get_num failed!\n");
12068 dprintk("read_attrs: gid=%d\n", (int)nfp->gid);
12070 @@ -1882,28 +2520,10 @@ decode_getattr(struct xdr_stream *xdr, s
12074 - nfp->rdev = MKDEV(major, minor);
12075 - if (MAJOR(nfp->rdev) != major || MINOR(nfp->rdev) != minor)
12077 - dprintk("read_attrs: rdev=%u:%u\n", major, minor);
12079 - if (bmval1 & FATTR4_WORD1_SPACE_AVAIL) {
12082 - READ64(fsstat->abytes);
12083 - dprintk("read_attrs: savail=0x%Lx\n", (long long) fsstat->abytes);
12085 - if (bmval1 & FATTR4_WORD1_SPACE_FREE) {
12088 - READ64(fsstat->fbytes);
12089 - dprintk("read_attrs: sfree=0x%Lx\n", (long long) fsstat->fbytes);
12091 - if (bmval1 & FATTR4_WORD1_SPACE_TOTAL) {
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)
12099 + dprintk("read_attrs: rdev=%u:%u\n", major, minor);
12101 if (bmval1 & FATTR4_WORD1_SPACE_USED) {
12103 @@ -1935,6 +2555,88 @@ decode_getattr(struct xdr_stream *xdr, s
12107 +#ifdef CONFIG_NFS_V4_ACL
12110 +decode_getacl(struct xdr_stream *xdr, struct nfs4_acl **aclp)
12112 + uint32_t attrlen, bmlen,
12119 + status = decode_op_hdr(xdr, OP_GETATTR);
12128 + READ_BUF((bmlen << 2) + 4);
12135 + if ((bmval0 & ~FATTR4_WORD0_ACL) || (bmval1)) {
12136 + dprintk("read_attrs: server returned bad attributes!\n");
12139 + if (bmval0 & FATTR4_WORD0_ACL) {
12140 + struct nfs4_acl *acl;
12141 + struct nfs4_ace ace;
12145 + if (aclp == NULL)
12146 + goto xdr_error; /* XXX MARIUS */
12148 + READ_BUF(4); len += 4;
12156 + acl = *aclp = nfs4_acl_new();
12157 + if (acl == NULL) {
12158 + status = -ENOMEM;
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);
12175 + p += XDR_QUADLEN(ace.wholen);
12177 + } else if (aclp != NULL)
12181 + if (len != attrlen)
12187 +#endif /* CONFIG_NFS_V4_ACL */
12190 decode_change_attr(struct xdr_stream *xdr, uint64_t *change_attr)
12192 @@ -2067,6 +2769,77 @@ out_bad_bitmap:
12197 +decode_putfh(struct xdr_stream *xdr)
12199 + return decode_op_hdr(xdr, OP_PUTFH);
12203 +decode_setattr(struct xdr_stream *xdr)
12210 + status = decode_op_hdr(xdr, OP_SETATTR);
12215 + READ_BUF(bmlen << 2);
12219 +#ifdef CONFIG_NFS_V4_ACL
12222 + * Decode SETACL response
12225 +nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res)
12227 + struct xdr_stream xdr;
12228 + struct compound_hdr hdr;
12231 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12232 + status = decode_compound_hdr(&xdr, &hdr);
12235 + status = decode_putfh(&xdr);
12238 + status = decode_setattr(&xdr);
12244 + * Decode GETACL response
12247 +nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_acl **res)
12249 + struct xdr_stream xdr;
12250 + struct compound_hdr hdr;
12253 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12254 + status = decode_compound_hdr(&xdr, &hdr);
12257 + status = decode_putfh(&xdr);
12260 + status = decode_getacl(&xdr, res);
12266 +#endif /* CONFIG_NFS_V4_ACL */
12269 decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
12270 @@ -2137,9 +2910,8 @@ out_bad_bitmap:
12274 -decode_getfh(struct xdr_stream *xdr, struct nfs4_getfh *getfh)
12275 +decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
12277 - struct nfs_fh *fh = getfh->gf_fhandle;
12281 @@ -2161,14 +2933,14 @@ decode_getfh(struct xdr_stream *xdr, str
12285 -decode_link(struct xdr_stream *xdr, struct nfs4_link *link)
12286 +decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
12290 status = decode_op_hdr(xdr, OP_LINK);
12293 - return decode_change_info(xdr, link->ln_cinfo);
12294 + return decode_change_info(xdr, cinfo);
12298 @@ -2296,12 +3068,6 @@ decode_open_downgrade(struct xdr_stream
12302 -decode_putfh(struct xdr_stream *xdr)
12304 - return decode_op_hdr(xdr, OP_PUTFH);
12308 decode_putrootfh(struct xdr_stream *xdr)
12310 return decode_op_hdr(xdr, OP_PUTROOTFH);
12311 @@ -2336,7 +3102,7 @@ decode_read(struct xdr_stream *xdr, stru
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)
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
12324 - COPYMEM(readdir->rd_resp_verifier.data, 8);
12325 + COPYMEM(readdir->resp_verifier.data, 8);
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
12331 xdr_read_pages(xdr, pglen);
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);
12339 for (nr = 0; *p++; nr++) {
12341 @@ -2421,7 +3187,7 @@ err_unmap:
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)
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)
12354 -decode_remove(struct xdr_stream *xdr, struct nfs4_remove *remove)
12355 +decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
12359 status = decode_op_hdr(xdr, OP_REMOVE);
12362 - status = decode_change_info(xdr, remove->rm_cinfo);
12363 + status = decode_change_info(xdr, cinfo);
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)
12375 status = decode_op_hdr(xdr, OP_RENAME);
12378 - if ((status = decode_change_info(xdr, rename->rn_src_cinfo)))
12380 - if ((status = decode_change_info(xdr, rename->rn_dst_cinfo)))
12381 + if ((status = decode_change_info(xdr, old_cinfo)))
12383 + status = decode_change_info(xdr, new_cinfo);
12387 @@ -2510,23 +3276,6 @@ decode_savefh(struct xdr_stream *xdr)
12391 -decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
12398 - status = decode_op_hdr(xdr, OP_SETATTR);
12403 - READ_BUF(bmlen << 2);
12408 decode_setclientid(struct xdr_stream *xdr, struct nfs4_client *clp)
12411 @@ -2566,158 +3315,348 @@ decode_setclientid(struct xdr_stream *xd
12415 -decode_setclientid_confirm(struct xdr_stream *xdr)
12416 +decode_setclientid_confirm(struct xdr_stream *xdr)
12418 + return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
12422 +decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
12427 + status = decode_op_hdr(xdr, OP_WRITE);
12432 + READ32(res->count);
12433 + READ32(res->verf->committed);
12434 + COPYMEM(res->verf->verifier, 8);
12439 + * Decode OPEN_DOWNGRADE response
12442 +nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
12444 + struct xdr_stream xdr;
12445 + struct compound_hdr hdr;
12448 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12449 + status = decode_compound_hdr(&xdr, &hdr);
12452 + status = decode_putfh(&xdr);
12455 + status = decode_open_downgrade(&xdr, res);
12461 + * END OF "GENERIC" DECODE ROUTINES.
12465 + * Decode ACCESS response
12468 +nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res)
12470 + struct xdr_stream xdr;
12471 + struct compound_hdr hdr;
12474 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12475 + status = decode_compound_hdr(&xdr, &hdr);
12478 + status = decode_putfh(&xdr);
12481 + status = decode_getfattr(&xdr, res->fattr, res->server);
12484 + status = decode_access(&xdr, res);
12490 + * Decode LOOKUP response
12493 +nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookupres *res)
12495 + struct xdr_stream xdr;
12496 + struct compound_hdr hdr;
12499 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12500 + status = decode_compound_hdr(&xdr, &hdr);
12503 + status = decode_putfh(&xdr);
12506 + status = decode_getfattr(&xdr, res->dirattr, res->server);
12509 + status = decode_lookup(&xdr);
12512 + status = decode_getfattr(&xdr, res->fattr, res->server);
12515 + status = decode_getfh(&xdr, res->fhandle);
12521 + * Decode GETROOT_HEAD response
12524 +nfs4_xdr_dec_getroot_head(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getroot_res *res)
12526 + struct xdr_stream xdr;
12527 + struct compound_hdr hdr;
12530 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12531 + status = decode_compound_hdr(&xdr, &hdr);
12534 + status = decode_putrootfh(&xdr);
12537 + status = decode_getfattr(&xdr, res->fattr, res->server);
12540 + status = decode_getfh(&xdr, res->fhandle);
12546 + * Decode GETROOT_PATH response
12549 +nfs4_xdr_dec_getroot_path(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getroot_res *res)
12551 + struct xdr_stream xdr;
12552 + struct compound_hdr hdr;
12555 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12556 + status = decode_compound_hdr(&xdr, &hdr);
12559 + status = decode_putfh(&xdr);
12562 + status = decode_lookup(&xdr);
12565 + status = decode_getfattr(&xdr, res->fattr, res->server);
12568 + status = decode_getfh(&xdr, res->fhandle);
12574 + * Decode REMOVE response
12577 +nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_remove_res *res)
12579 - return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
12580 + struct xdr_stream xdr;
12581 + struct compound_hdr hdr;
12584 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12585 + status = decode_compound_hdr(&xdr, &hdr);
12588 + status = decode_putfh(&xdr);
12591 + status = decode_remove(&xdr, res->dir_cinfo);
12594 + status = decode_getfattr(&xdr, res->dir_attr, res->server);
12600 + * Decode UNLINK response
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)
12607 + struct xdr_stream xdr;
12608 + struct compound_hdr hdr;
12611 - status = decode_op_hdr(xdr, OP_WRITE);
12613 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12614 + status = decode_compound_hdr(&xdr, &hdr);
12619 - READ32(res->count);
12620 - READ32(res->verf->committed);
12621 - COPYMEM(res->verf->verifier, 8);
12624 + status = decode_putfh(&xdr);
12627 + status = decode_remove(&xdr, &res->cinfo);
12630 + status = decode_getfattr(&xdr, &res->attrs, res->server);
12635 -/* FIXME: this sucks */
12637 + * Decode RENAME response
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)
12643 + struct xdr_stream xdr;
12644 struct compound_hdr hdr;
12645 - struct nfs4_op *op;
12648 - status = decode_compound_hdr(xdr, &hdr);
12650 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12651 + status = decode_compound_hdr(&xdr, &hdr);
12655 - cp->toplevel_status = hdr.status;
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...
12661 - if (hdr.taglen != cp->taglen)
12662 - dprintk("nfs4: non-conforming server returns tag length mismatch!\n");
12664 - cp->resp_nops = hdr.nops;
12665 - if (hdr.nops > cp->req_nops) {
12666 - dprintk("nfs4: resp_nops > req_nops!\n");
12670 - op = &cp->ops[0];
12671 - for (cp->nops = 0; cp->nops < cp->resp_nops; cp->nops++, op++) {
12672 - switch (op->opnum) {
12674 - status = decode_access(xdr, &op->u.access);
12677 - status = decode_create(xdr, &op->u.create);
12680 - status = decode_getattr(xdr, &op->u.getattr, cp->server);
12683 - status = decode_getfh(xdr, &op->u.getfh);
12686 - status = decode_link(xdr, &op->u.link);
12689 - status = decode_lookup(xdr);
12692 - status = decode_putfh(xdr);
12694 - case OP_PUTROOTFH:
12695 - status = decode_putrootfh(xdr);
12698 - status = decode_readdir(xdr, req, &op->u.readdir);
12700 - case OP_READLINK:
12701 - status = decode_readlink(xdr, req, &op->u.readlink);
12703 - case OP_RESTOREFH:
12704 - status = decode_restorefh(xdr);
12707 - status = decode_remove(xdr, &op->u.remove);
12710 - status = decode_rename(xdr, &op->u.rename);
12713 - status = decode_savefh(xdr);
12724 + status = decode_putfh(&xdr);
12727 + status = decode_savefh(&xdr);
12730 + status = decode_putfh(&xdr);
12733 + status = decode_rename(&xdr, res->old_cinfo, res->new_cinfo);
12736 + status = decode_getfattr(&xdr, res->new_fattr, res->server);
12739 + status = decode_restorefh(&xdr);
12742 + status = decode_getfattr(&xdr, res->old_fattr, res->server);
12748 - * Decode OPEN_DOWNGRADE response
12749 + * Decode LINK response
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)
12755 - struct xdr_stream xdr;
12756 - struct compound_hdr hdr;
12759 - xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12760 - status = decode_compound_hdr(&xdr, &hdr);
12763 - status = decode_putfh(&xdr);
12766 - status = decode_open_downgrade(&xdr, res);
12767 + struct xdr_stream xdr;
12768 + struct compound_hdr hdr;
12771 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12772 + status = decode_compound_hdr(&xdr, &hdr);
12775 + status = decode_putfh(&xdr);
12778 + status = decode_savefh(&xdr);
12781 + status = decode_putfh(&xdr);
12784 + status = decode_link(&xdr, res->dir_cinfo);
12787 + status = decode_getfattr(&xdr, res->dir_attr, res->server);
12790 + status = decode_restorefh(&xdr);
12793 + status = decode_getfattr(&xdr, res->fattr, res->server);
12800 - * END OF "GENERIC" DECODE ROUTINES.
12801 + * Decode CREATE response
12804 +nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
12806 + struct xdr_stream xdr;
12807 + struct compound_hdr hdr;
12810 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12811 + status = decode_compound_hdr(&xdr, &hdr);
12814 + status = decode_putfh(&xdr);
12817 + status = decode_savefh(&xdr);
12820 + status = decode_create(&xdr,res->dir_cinfo);
12823 + status = decode_getfattr(&xdr, res->fattr, res->server);
12826 + status = decode_getfh(&xdr, res->fhandle);
12829 + status = decode_restorefh(&xdr);
12832 + status = decode_getfattr(&xdr, res->dir_attr, res->server);
12838 - * Decode COMPOUND response
12839 + * Decode GETATTR response
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)
12845 struct xdr_stream xdr;
12846 + struct compound_hdr hdr;
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);
12856 - if (cp->toplevel_status)
12857 - status = -nfs_stat_to_errno(cp->toplevel_status);
12859 + status = decode_putfh(&xdr);
12862 + status = decode_getfattr(&xdr, res->fattr, res->server);
12870 * Decode CLOSE response
12872 @@ -2748,9 +3687,6 @@ nfs4_xdr_dec_open(struct rpc_rqst *rqstp
12874 struct xdr_stream xdr;
12875 struct compound_hdr hdr;
12876 - struct nfs4_getfh gfh = {
12877 - .gf_fhandle = &res->fh,
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);
12886 - status = decode_getattr(&xdr, res->f_getattr, res->server);
12887 + status = decode_getfattr(&xdr, res->f_attr, res->server);
12890 - status = decode_getfh(&xdr, &gfh);
12891 + status = decode_getfh(&xdr, &res->fh);
12894 status = decode_restorefh(&xdr);
12897 - status = decode_getattr(&xdr, res->d_getattr, res->server);
12898 + status = decode_getfattr(&xdr, res->d_attr, res->server);
12902 @@ -2824,7 +3760,7 @@ nfs4_xdr_dec_open_reclaim(struct rpc_rqs
12903 status = decode_open(&xdr, res);
12906 - status = decode_getattr(&xdr, res->f_getattr, res->server);
12907 + status = decode_getfattr(&xdr, res->f_attr, res->server);
12911 @@ -2846,10 +3782,10 @@ nfs4_xdr_dec_setattr(struct rpc_rqst *rq
12912 status = decode_putfh(&xdr);
12915 - status = decode_setattr(&xdr, res);
12916 + status = decode_setattr(&xdr);
12919 - status = decode_getattr(&xdr, res->attr, res->server);
12920 + status = decode_getfattr(&xdr, res->fattr, res->server);
12924 @@ -2921,6 +3857,50 @@ out:
12928 + * Decode READLINK response
12931 +nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res)
12933 + struct xdr_stream xdr;
12934 + struct compound_hdr hdr;
12937 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12938 + status = decode_compound_hdr(&xdr, &hdr);
12941 + status = decode_putfh(&xdr);
12944 + status = decode_readlink(&xdr, rqstp);
12950 + * Decode READDIR response
12953 +nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res)
12955 + struct xdr_stream xdr;
12956 + struct compound_hdr hdr;
12959 + xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
12960 + status = decode_compound_hdr(&xdr, &hdr);
12963 + status = decode_putfh(&xdr);
12966 + status = decode_readdir(&xdr, rqstp, res);
12972 * Decode Read response
12975 @@ -3033,6 +4013,44 @@ nfs4_xdr_dec_fsinfo(struct rpc_rqst *req
12979 + * PATHCONF request
12982 +nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf)
12984 + struct xdr_stream xdr;
12985 + struct compound_hdr hdr;
12988 + xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
12989 + status = decode_compound_hdr(&xdr, &hdr);
12991 + status = decode_putfh(&xdr);
12993 + status = decode_pathconf(&xdr, pathconf);
13001 +nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat)
13003 + struct xdr_stream xdr;
13004 + struct compound_hdr hdr;
13007 + xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
13008 + status = decode_compound_hdr(&xdr, &hdr);
13010 + status = decode_putfh(&xdr);
13012 + status = decode_statfs(&xdr, fsstat);
13017 * Decode RENEW response
13020 @@ -3201,7 +4219,6 @@ nfs_stat_to_errno(int stat)
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),
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
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 */
13071 #include <asm/uaccess.h>
13073 @@ -341,6 +351,204 @@ out_nfserr:
13077 +#ifdef CONFIG_NFS_V4_ACL
13080 +set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
13084 + char *buf = NULL;
13086 + struct inode *inode = dentry->d_inode;
13088 + buflen = posix_acl_xattr_size(pacl->a_count);
13089 + buf = kmalloc(buflen, GFP_KERNEL);
13094 + len = posix_acl_to_xattr(pacl, buf, buflen);
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);
13106 + security_inode_post_setxattr(dentry, key, buf, len, 0);
13107 + up(&inode->i_sem);
13115 +nfsd_name_to_uid_wrapper(void *arg, const char *name, size_t len, __u32 *id)
13117 + return nfsd_map_name_to_uid((struct svc_rqst *)arg, name, len, id);
13121 +nfsd_name_to_gid_wrapper(void *arg, const char *name, size_t len, __u32 *id)
13123 + return nfsd_map_name_to_gid((struct svc_rqst *)arg, name, len, id);
13127 +nfsd_uid_to_name_wrapper(void *arg, __u32 id, char *name)
13129 + return nfsd_map_uid_to_name((struct svc_rqst *)arg, id, name);
13133 +nfsd_gid_to_name_wrapper(void *arg, __u32 id, char *name)
13135 + return nfsd_map_gid_to_name((struct svc_rqst *)arg, id, name);
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,
13147 +nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
13148 + struct nfs4_acl *acl)
13151 + struct dentry *dentry;
13152 + struct inode *inode;
13153 + struct posix_acl *pacl = NULL, *dpacl = NULL;
13156 + error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
13160 + dentry = fhp->fh_dentry;
13161 + inode = dentry->d_inode;
13163 + error = nfs4_acl_nfsv4_to_posix(&nfsd_idmapper, rqstp, acl, &pacl, &dpacl);
13168 + error = set_nfsv4_acl_one(dentry, pacl, XATTR_NAME_ACL_ACCESS);
13174 + error = set_nfsv4_acl_one(dentry, dpacl, XATTR_NAME_ACL_DEFAULT);
13182 + posix_acl_release(pacl);
13183 + posix_acl_release(dpacl);
13186 + error = nfserrno(error);
13190 +static struct posix_acl *
13191 +_get_posix_acl(struct dentry *dentry, char *key)
13193 + struct inode *inode = dentry->d_inode;
13194 + char *buf = NULL;
13195 + int buflen, error = 0;
13196 + struct posix_acl *pacl = NULL;
13198 + down(&inode->i_sem);
13200 + buflen = inode->i_op->getxattr(dentry, key, NULL, 0);
13201 + if (buflen <= 0) {
13202 + error = buflen < 0 ? buflen : -ENODATA;
13206 + buf = kmalloc(buflen, GFP_KERNEL);
13207 + if (buf == NULL) {
13212 + error = -EOPNOTSUPP;
13213 + if (inode->i_op && inode->i_op->getxattr) {
13214 + error = security_inode_getxattr(dentry, key);
13217 + error = inode->i_op->getxattr(dentry, key, buf, buflen);
13223 + up(&inode->i_sem);
13225 + pacl = posix_acl_from_xattr(buf, buflen);
13230 + up(&inode->i_sem);
13231 + pacl = ERR_PTR(error);
13236 +nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl)
13238 + struct inode *inode = dentry->d_inode;
13240 + struct posix_acl *pacl = NULL, *dpacl = NULL;
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);
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)
13255 + else if (IS_ERR(dpacl)) {
13256 + error = PTR_ERR(dpacl);
13262 + *acl = nfs4_acl_posix_to_nfsv4(&nfsd_idmapper, rqstp, pacl, dpacl);
13263 + if (IS_ERR(*acl)) {
13264 + error = PTR_ERR(*acl);
13268 + posix_acl_release(pacl);
13269 + posix_acl_release(dpacl);
13273 +#endif /* CONFIG_NFS_V4_ACL */
13275 #ifdef CONFIG_NFSD_V3
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;
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.
13288 - err = fh_verify(rqstp, fhp, type, access | MAY_OWNER_OVERRIDE);
13289 + if (type == S_IFDIR)
13290 + err = fh_verify(rqstp, fhp, type, access);
13292 + err = fh_verify(rqstp, fhp, type, access | MAY_OWNER_OVERRIDE);
13296 @@ -1494,7 +1706,7 @@ nfsd_readdir(struct svc_rqst *rqstp, str
13298 *offsetp = file.f_pos;
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 */
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)
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
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)
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)
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};
13368 - dprintk("RPC: krb5_encrypt: input data:\n");
13369 + dprintk("RPC: krb5_encrypt: input data:\n");
13370 print_hexl((u32 *)in, length, 0);
13372 if (length % crypto_tfm_alg_blocksize(tfm) != 0)
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));
13381 @@ -80,10 +80,10 @@ krb5_encrypt(
13383 ret = crypto_cipher_encrypt_iv(tfm, sg, sg, length, local_iv);
13385 - dprintk("RPC: krb5_encrypt: output data:\n");
13386 + dprintk("RPC: krb5_encrypt: output data:\n");
13387 print_hexl((u32 *)out, length, 0);
13389 - dprintk("krb5_encrypt returns %d\n",ret);
13390 + dprintk("RPC: krb5_encrypt returns %d\n",ret);
13394 @@ -99,14 +99,14 @@ krb5_decrypt(
13395 struct scatterlist sg[1];
13396 u8 local_iv[16] = {0};
13398 - dprintk("RPC: krb5_decrypt: input data:\n");
13399 + dprintk("RPC: krb5_decrypt: input data:\n");
13400 print_hexl((u32 *)in, length, 0);
13402 if (length % crypto_tfm_alg_blocksize(tfm) != 0)
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));
13411 @@ -120,10 +120,10 @@ krb5_decrypt(
13413 ret = crypto_cipher_decrypt_iv(tfm, sg, sg, length, local_iv);
13415 - dprintk("RPC: krb5_decrypt: output_data:\n");
13416 + dprintk("RPC: krb5_decrypt: output_data:\n");
13417 print_hexl((u32 *)out, length, 0);
13419 - dprintk("gss_k5decrypt returns %d\n",ret);
13420 + dprintk("RPC: gss_k5decrypt returns %d\n",ret);
13424 @@ -152,7 +152,7 @@ krb5_make_checksum(s32 cksumtype, char *
13428 - dprintk("RPC: krb5_make_checksum:"
13429 + dprintk("RPC: krb5_make_checksum:"
13430 " unsupported checksum %d", cksumtype);
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,
13438 unsigned char plain[8];
13440 - dprintk("krb5_get_seq_num: \n");
13441 + dprintk("RPC: krb5_get_seq_num:\n");
13443 if ((code = krb5_decrypt(key, cksum, buf, plain, 8)))
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
13450 spin_lock(®istered_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",
13457 list_add(&triple->triples, ®istered_triples);
13458 spin_unlock(®istered_triples_lock);
13459 - dprintk("RPC: registered pseudoflavor %d\n", pseudoflavor);
13460 + dprintk("RPC: registered pseudoflavor %d\n", pseudoflavor);
13464 @@ -145,7 +146,7 @@ gss_cmp_triples(u32 oid_len, char *oid_d
13466 oid.data = oid_data;
13468 - dprintk("RPC: gss_cmp_triples \n");
13469 + dprintk("RPC: gss_cmp_triples\n");
13470 print_sec_triple(&oid,qop,service);
13472 spin_lock(®istered_triples_lock);
13473 @@ -158,7 +159,7 @@ gss_cmp_triples(u32 oid_len, char *oid_d
13476 spin_unlock(®istered_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;
13482 @@ -193,8 +194,8 @@ gss_pseudoflavor_to_service(u32 pseudofl
13483 triple = do_lookup_triple_by_pseudoflavor(pseudoflavor);
13484 spin_unlock(®istered_triples_lock);
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",
13492 return triple->service;
13493 @@ -211,8 +212,8 @@ gss_pseudoflavor_to_mech(u32 pseudoflavo
13495 mech = gss_mech_get(triple->mech);
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",
13504 @@ -223,8 +224,8 @@ gss_pseudoflavor_to_mechOID(u32 pseudofl
13506 mech = gss_pseudoflavor_to_mech(pseudoflavor);
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",
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
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
13528 * client_lru holds client queue ordered by nfs4_client.cl_time
13529 * for lease renewal.
13531 + * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
13532 + * for last close replay.
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;
13542 renew_client(struct nfs4_client *clp)
13543 @@ -269,8 +274,7 @@ cmp_clid(clientid_t * cl1, clientid_t *
13544 /* XXX what about NGROUP */
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);
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
13567 +release_stateid_lockowner(struct nfs4_stateid *open_stp)
13569 + struct nfs4_stateowner *lock_sop;
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);
13581 release_stateowner(struct nfs4_stateowner *sop)
13583 struct nfs4_stateid *stp;
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);
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
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);
13617 release_stateid(struct nfs4_stateid *stp, int flags) {
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);
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;
13635 + locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
13637 - /* should use a slab cache */
13641 @@ -852,12 +882,25 @@ static void
13642 release_file(struct nfs4_file *fp)
13645 - list_del_init(&fp->fi_hash);
13646 + list_del(&fp->fi_hash);
13647 iput(fp->fi_inode);
13652 +move_to_close_lru(struct nfs4_stateowner *sop)
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);
13660 + list_add_tail(&sop->so_close_lru, &close_lru);
13661 + sop->so_time = get_seconds();
13665 release_state_owner(struct nfs4_stateid *stp, struct nfs4_stateowner **sopp,
13668 @@ -866,16 +909,13 @@ release_state_owner(struct nfs4_stateid
13670 dprintk("NFSD: release_state_owner\n");
13671 release_stateid(stp, flag);
13673 - * release unused nfs4_stateowners.
13674 - * XXX will need to be placed on an open_stateid_lru list to be
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
13680 - if (sop->so_confirmed && list_empty(&sop->so_perfilestate)) {
13681 - release_stateowner(sop);
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)) {
13689 @@ -940,15 +980,46 @@ find_file(unsigned int hashval, struct i
13693 +#define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0)
13694 +#define TEST_DENY(x) ((x >= 0 || x < 5)?1:0)
13697 +set_access(unsigned int *access, unsigned long bmap) {
13701 + for (i = 1; i < 4; i++) {
13702 + if(test_bit(i, &bmap))
13708 +set_deny(unsigned int *deny, unsigned long bmap) {
13712 + for (i = 0; i < 4; i++) {
13713 + if(test_bit(i, &bmap))
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;
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))
13733 + * Called to check deny when READ with all zero stateid or
13734 + * WRITE with all zero or all one stateid
13737 nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
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;
13749 @@ -1010,6 +1082,8 @@ nfs4_file_downgrade(struct file *filp, u
13754 + * called with nfs4_lock_state() held.
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))
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:
13768 renew_client(sop->so_client);
13770 - nfs4_unlock_state();
13775 + * called with nfs4_lock_state() held.
13778 nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
13780 @@ -1108,7 +1182,10 @@ nfsd4_process_open2(struct svc_rqst *rqs
13782 ino = current_fh->fh_dentry->d_inode;
13784 - nfs4_lock_state();
13785 + status = nfserr_inval;
13786 + if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
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
13796 + /* ignore lock owners */
13797 + if (stq->st_stateowner->so_is_open_owner == 0)
13799 if (!test_share(stq,open))
13802 @@ -1137,7 +1217,7 @@ nfsd4_process_open2(struct svc_rqst *rqs
13803 GFP_KERNEL)) == NULL)
13806 - if (open->op_share_access && NFS4_SHARE_ACCESS_WRITE)
13807 + if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
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;
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;
13823 /* update the struct file */
13824 if ((status = nfs4_file_upgrade(&stp->st_vfs_file, share_access)))
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);
13834 @@ -1194,7 +1277,6 @@ out:
13835 if (!open->op_stateowner->so_confirmed)
13836 open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;
13838 - nfs4_unlock_state();
13842 @@ -1250,9 +1332,11 @@ time_t
13843 nfs4_laundromat(void)
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;
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)
13861 + if (clientid_val > t)
13862 + clientid_val = t;
13865 dprintk("NFSD: purging unused client (clientid %08x)\n",
13866 clp->cl_clientid.cl_id);
13867 expire_client(clp);
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)
13879 + dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
13881 + release_stateowner(sop);
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;
13891 @@ -1285,17 +1381,22 @@ laundromat_main(void *not_used)
13892 schedule_delayed_work(&laundromat_work, t*HZ);
13895 -/* search ownerid_hashtbl[] for stateid owner (stateid->si_stateownerid) */
13896 +/* search ownerid_hashtbl[] and close_lru for stateid owner
13897 + * (stateid->si_stateownerid)
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);
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)
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,
13915 + if(local->so_id == st_id)
13921 @@ -1303,7 +1404,8 @@ find_openstateowner_id(u32 st_id) {
13923 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stateid *stp)
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);
13931 @@ -1375,7 +1477,7 @@ out:
13932 * Checks for sequence id mutating operations.
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)
13939 struct nfs4_stateid *stp;
13940 @@ -1412,6 +1514,21 @@ nfs4_preprocess_seqid_op(struct svc_fh *
13942 status = nfserr_bad_stateid;
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
13950 + struct nfs4_stateowner *sop = stp->st_stateowner;
13951 + struct nfs4_client *clp = sop->so_client;
13953 + if (!sop->so_is_open_owner)
13955 + if (!cmp_clid(&clp->cl_clientid, lockclid))
13959 if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
13960 printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
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.
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;
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;
13981 printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
13984 status = nfserr_bad_seqid;
13990 + * nfs4_unlock_state(); called in encode
13993 nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc)
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);
14000 + if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0)))
14003 oc->oc_stateowner = NULL;
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)))
14013 sop = oc->oc_stateowner;
14014 @@ -1512,49 +1639,89 @@ nfsd4_open_confirm(struct svc_rqst *rqst
14015 stp->st_stateid.si_generation);
14018 - nfs4_unlock_state();
14024 + * unset all bits in union bitmap (bmap) that
14025 + * do not exist in share (from successful OPEN_DOWNGRADE)
14028 +reset_union_bmap_access(unsigned long access, unsigned long *bmap)
14031 + for (i = 1; i < 4; i++) {
14032 + if ((i & access) != i)
14033 + __clear_bit(i, bmap);
14038 +reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
14041 + for (i = 0; i < 4; i++) {
14042 + if ((i & deny) != i)
14043 + __clear_bit(i, bmap);
14048 + * nfs4_unlock_state(); called in encode
14052 nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od)
14055 struct nfs4_stateid *stp;
14056 + unsigned int share_access;
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);
14062 + od->od_stateowner = NULL;
14063 + status = nfserr_inval;
14064 + if (!TEST_ACCESS(od->od_share_access) || !TEST_DENY(od->od_share_deny))
14068 if ((status = nfs4_preprocess_seqid_op(current_fh, od->od_seqid,
14070 CHECK_FH | OPEN_STATE,
14071 - &od->od_stateowner, &stp)))
14072 + &od->od_stateowner, &stp, NULL)))
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);
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);
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);
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);
14102 update_stateid(&stp->st_stateid);
14103 memcpy(&od->od_stateid, &stp->st_stateid, sizeof(stateid_t));
14106 - nfs4_unlock_state();
14111 + * nfs4_unlock_state() called after encode
14114 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close)
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);
14120 + close->cl_stateowner = NULL;
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)))
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);
14136 - nfs4_unlock_state();
14140 @@ -1717,7 +1885,7 @@ find_lockstateowner_str(unsigned int has
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);
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)
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;
14189 +check_lock_length(u64 offset, u64 length)
14191 + return ((length == 0) || ((length != ~(u64)0) &&
14192 + LOFF_OVERFLOW(offset, length)));
14198 + * nfs4_unlock_state(); called in encode
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);
14206 + if (check_lock_length(lock->lk_offset, lock->lk_length))
14207 + return nfserr_inval;
14209 lock->lk_stateowner = NULL;
14212 @@ -1812,12 +1996,15 @@ nfsd4_lock(struct svc_rqst *rqstp, struc
14213 printk("NFSD: nfsd4_lock: clientid is stale!\n");
14216 + /* does the clientid in the lock owner own the open stateid? */
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);
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))
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)))
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);
14248 @@ -1938,7 +2124,6 @@ out_destroy_new_stateid:
14249 release_state_owner(lock_stp, &lock->lk_stateowner, LOCK_STATE);
14252 - nfs4_unlock_state();
14256 @@ -1956,6 +2141,9 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
14257 unsigned int strhashval;
14260 + if (check_lock_length(lockt->lt_offset, lockt->lt_length))
14261 + return nfserr_inval;
14263 lockt->lt_stateowner = NULL;
14266 @@ -1967,6 +2155,8 @@ nfsd4_lockt(struct svc_rqst *rqstp, stru
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;
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);
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");
14287 + &lockt->lt_stateowner);
14288 sop = lockt->lt_stateowner;
14290 file_lock.fl_owner = (fl_owner_t) sop;
14291 @@ -2032,7 +2218,10 @@ out:
14292 nfs4_unlock_state();
14298 + * nfs4_unlock_state(); called in encode
14301 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku)
14303 @@ -2043,13 +2232,18 @@ nfsd4_locku(struct svc_rqst *rqstp, stru
14305 dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
14306 locku->lu_offset, locku->lu_length);
14308 + if (check_lock_length(locku->lu_offset, locku->lu_length))
14309 + return nfserr_inval;
14311 + locku->lu_stateowner = NULL;
14314 if ((status = nfs4_preprocess_seqid_op(current_fh,
14316 &locku->lu_stateid,
14317 CHECK_FH | LOCK_STATE,
14318 - &locku->lu_stateowner, &stp)))
14319 + &locku->lu_stateowner, &stp, NULL)))
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));
14327 - nfs4_unlock_state();
14331 @@ -2093,6 +2286,84 @@ out_nfserr:
14337 + * 1: locks held by lockowner
14338 + * 0: no locks held by lockowner
14341 +check_for_locks(struct file *filp, struct nfs4_stateowner *lowner)
14343 + struct file_lock **flpp;
14344 + struct inode *inode = filp->f_dentry->d_inode;
14348 + for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
14349 + if ((*flpp)->fl_owner == (fl_owner_t)lowner)
14359 +nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
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;
14367 + dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
14368 + clid->cl_boot, clid->cl_id);
14370 + /* XXX check for lease expiration */
14372 + status = nfserr_stale_clientid;
14373 + if (STALE_CLIENTID(clid)) {
14374 + printk("NFSD: nfsd4_release_lockowner: clientid is stale!\n");
14378 + nfs4_lock_state();
14380 + /* find the lockowner */
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,
14386 + if(cmp_owner_str(local, owner, clid))
14391 + struct nfs4_stateid *stp;
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))
14404 + /* no locks held by (lock) stateowner */
14406 + release_stateowner(local);
14409 + nfs4_unlock_state();
14414 * Start and stop routines
14416 @@ -2128,6 +2399,7 @@ nfs4_state_init(void)
14417 memset(&zerostateid, 0, sizeof(stateid_t));
14418 memset(&onestateid, ~0, sizeof(stateid_t));
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;
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
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;
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
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
14467 -static __inline__ void
14468 -fh_dup2(struct svc_fh *dst, struct svc_fh *src)
14471 - dget(src->fh_dentry);
14475 static __inline__ struct svc_fh *
14476 fh_init(struct svc_fh *fhp, int maxsize)
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);
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,
14497 /* obj is assumed to point to allocated memory of size at least len: */
14500 read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len)
14502 struct xdr_buf subbuf;
14503 @@ -824,7 +824,7 @@ out:
14509 read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)