1 Changes since 2.6.22-rc1-CITI_NFS4_ALL-1
3 - allow id-squashing options to vary per pseudoflavor
4 - enforce requirement that flags other than ro/rw and
5 id-squashing flags not vary per pseudoflavor
6 - meelap: vary maximum delegation limit by RAM size
7 - meelap: don't grant delegations on files that saw conflicts
8 - silence a compiler warning in ACL code
9 - bhalevy: fix enc_stateid_sz for nfsd callbacks
10 - fix mishandling of acl errors that could cause an oops
11 - make all export finding function return -errno's on err
12 - show flavor info in /proc/net/rpc/nfsd.export/content
13 - miscellaneous cleanup
18 b/fs/lockd/svc.c | 31 ++-
21 b/fs/nfsd/auth.c | 18 +-
22 b/fs/nfsd/export.c | 284 ++++++++++++++++++++++++++------
24 b/fs/nfsd/nfs4acl.c | 12 +
25 b/fs/nfsd/nfs4callback.c | 2
26 b/fs/nfsd/nfs4idmap.c | 13 +
27 b/fs/nfsd/nfs4proc.c | 34 +++
28 b/fs/nfsd/nfs4state.c | 28 ++-
29 b/fs/nfsd/nfs4xdr.c | 99 +++++++++++
30 b/fs/nfsd/nfsctl.c | 1
31 b/fs/nfsd/nfsfh.c | 32 ++-
32 b/fs/nfsd/nfsproc.c | 3
33 b/fs/nfsd/nfssvc.c | 10 +
34 b/fs/nfsd/vfs.c | 110 ++++++------
36 b/include/linux/fs.h | 2
37 b/include/linux/lockd/bind.h | 9 +
38 b/include/linux/nfsd/export.h | 41 ++++
39 b/include/linux/nfsd/nfsd.h | 9 -
40 b/include/linux/nfsd/state.h | 3
41 b/include/linux/nfsd/xdr4.h | 7
42 b/include/linux/sunrpc/gss_api.h | 1
43 b/include/linux/sunrpc/svc.h | 2
44 b/include/linux/sunrpc/svcauth.h | 1
45 b/include/linux/sunrpc/svcauth_gss.h | 2
46 b/net/sunrpc/auth_gss/gss_krb5_mech.c | 1
47 b/net/sunrpc/auth_gss/gss_mech_switch.c | 15 +
48 b/net/sunrpc/auth_gss/gss_spkm3_mech.c | 1
49 b/net/sunrpc/auth_gss/svcauth_gss.c | 32 +++
50 b/net/sunrpc/svcauth_unix.c | 7
51 include/linux/nfsd/interface.h | 13 -
52 36 files changed, 693 insertions(+), 177 deletions(-)
54 diff --git a/fs/Kconfig b/fs/Kconfig
55 index 0fa0c11..76cf825 100644
58 @@ -1675,6 +1675,7 @@ config NFSD_V3_ACL
60 bool "Provide NFSv4 server support (EXPERIMENTAL)"
61 depends on NFSD_V3 && EXPERIMENTAL
62 + select RPCSEC_GSS_KRB5
64 If you would like to include the NFSv4 server as well as the NFSv2
65 and NFSv3 servers, say Y here. This feature is experimental, and
66 diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
67 index 126b1bf..6378572 100644
70 @@ -75,18 +75,35 @@ static const int nlm_port_min = 0, nlm_port_max = 65535;
72 static struct ctl_table_header * nlm_sysctl_table;
74 -static unsigned long set_grace_period(void)
75 +static time_t get_lockd_grace_period(void)
77 - unsigned long grace_period;
79 /* Note: nlm_timeout should always be nonzero */
81 - grace_period = ((nlm_grace_period + nlm_timeout - 1)
82 - / nlm_timeout) * nlm_timeout * HZ;
83 + return ((nlm_grace_period + nlm_timeout - 1)
84 + / nlm_timeout) * nlm_timeout;
86 - grace_period = nlm_timeout * 5 * HZ;
87 + return nlm_timeout * 5;
90 +time_t get_nfs_grace_period(void)
92 + time_t lockdgrace = get_lockd_grace_period();
93 + time_t nfsdgrace = 0;
96 + nfsdgrace = nlmsvc_ops->get_grace_period();
98 + return max(lockdgrace, nfsdgrace);
100 +EXPORT_SYMBOL(get_nfs_grace_period);
102 +static unsigned long set_grace_period(void)
104 + time_t grace_period;
106 + grace_period = get_nfs_grace_period();
107 nlmsvc_grace_period = 1;
108 - return grace_period + jiffies;
109 + return grace_period * HZ + jiffies;
112 static inline void clear_grace_period(void)
113 diff --git a/fs/locks.c b/fs/locks.c
114 index 431a8b8..bcc37b9 100644
117 @@ -661,7 +661,7 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w
123 posix_test_lock(struct file *filp, struct file_lock *fl)
125 struct file_lock *cfl;
126 @@ -670,17 +670,15 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
127 for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
130 - if (posix_locks_conflict(cfl, fl))
131 + if (posix_locks_conflict(fl, cfl))
136 __locks_copy_lock(fl, cfl);
141 fl->fl_type = F_UNLCK;
147 EXPORT_SYMBOL(posix_test_lock);
148 @@ -823,7 +821,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
150 if (request->fl_type != F_UNLCK) {
151 for_each_lock(inode, before) {
152 - struct file_lock *fl = *before;
156 if (!posix_locks_conflict(request, fl))
157 @@ -1169,9 +1167,9 @@ static void time_out_leases(struct inode *inode)
158 * @inode: the inode of the file to return
159 * @mode: the open mode (read or write)
161 - * break_lease (inlined for speed) has checked there already
162 - * is a lease on this file. Leases are broken on a call to open()
163 - * or truncate(). This function can sleep unless you
164 + * break_lease (inlined for speed) has checked there already is at least
165 + * some kind of lock (maybe a lease) on this file. Leases are broken on
166 + * a call to open() or truncate(). This function can sleep unless you
167 * specified %O_NONBLOCK to your open().
169 int __break_lease(struct inode *inode, unsigned int mode)
170 @@ -1597,8 +1595,7 @@ asmlinkage long sys_flock(unsigned int fd, unsigned int cmd)
172 * vfs_test_lock - test file byte range lock
173 * @filp: The file to test lock for
174 - * @fl: The lock to test
175 - * @conf: Place to return a copy of the conflicting lock, if found
176 + * @fl: The lock to test; also used to hold result
178 * Returns -ERRNO on failure. Indicates presence of conflicting lock by
179 * setting conf->fl_type to something other than F_UNLCK.
180 diff --git a/fs/nfs/file.c b/fs/nfs/file.c
181 index 9eb8eb4..5b24e88 100644
184 @@ -397,7 +397,9 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
187 /* Try local locking first */
188 - if (posix_test_lock(filp, fl)) {
189 + posix_test_lock(filp, fl);
190 + if (fl->fl_type != F_UNLCK) {
191 + /* found a conflict */
195 diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
196 index 6e92b0f..cf61dc8 100644
201 #define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
203 +static int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
205 + struct exp_flavor_info *f;
206 + struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
208 + for (f = exp->ex_flavors; f < end; f++) {
209 + if (f->pseudoflavor == rqstp->rq_flavor)
212 + return exp->ex_flags;
216 int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
218 struct svc_cred cred = rqstp->rq_cred;
220 + int flags = nfsexp_flags(rqstp, exp);
223 - if (exp->ex_flags & NFSEXP_ALLSQUASH) {
224 + if (flags & NFSEXP_ALLSQUASH) {
225 cred.cr_uid = exp->ex_anon_uid;
226 cred.cr_gid = exp->ex_anon_gid;
227 cred.cr_group_info = groups_alloc(0);
228 - } else if (exp->ex_flags & NFSEXP_ROOTSQUASH) {
229 + } else if (flags & NFSEXP_ROOTSQUASH) {
230 struct group_info *gi;
232 cred.cr_uid = exp->ex_anon_uid;
233 diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
234 index 79bd03b..d9ed7f1 100644
235 --- a/fs/nfsd/export.c
236 +++ b/fs/nfsd/export.c
238 #include <linux/nfsd/nfsfh.h>
239 #include <linux/nfsd/syscall.h>
240 #include <linux/lockd/bind.h>
241 +#include <linux/sunrpc/msg_prot.h>
242 +#include <linux/sunrpc/gss_api.h>
244 #define NFSDDBG_FACILITY NFSDDBG_EXPORT
246 @@ -451,8 +453,46 @@ out_free_all:
250 +static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
253 + struct exp_flavor_info *f;
255 + err = get_int(mesg, &listsize);
258 + if (listsize < 0 || listsize > MAX_SECINFO_LIST)
261 + for (f=exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
262 + err = get_int(mesg, &f->pseudoflavor);
266 + * Just a quick sanity check; we could also try to check
267 + * whether this pseudoflavor is supported, but at worst
268 + * an unsupported pseudoflavor on the export would just
269 + * be a pseudoflavor that won't match the flavor of any
270 + * authenticated request. The administrator will
271 + * probably discover the problem when someone fails to
274 + if (f->pseudoflavor < 0)
276 + err = get_int(mesg, &f->flags);
279 + /* Only some flags are allowed to differ between flavors: */
280 + if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
283 + exp->ex_nflavors = listsize;
287 #else /* CONFIG_NFSD_V4 */
288 static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; }
289 +static inline int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
292 static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
293 @@ -476,6 +516,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
298 + exp.ex_nflavors = 0;
300 if (mesg[mlen-1] != '\n')
303 @@ -553,7 +596,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
304 if (exp.ex_uuid == NULL)
308 + } else if (strcmp(buf, "secinfo") == 0)
309 + err = secinfo_parse(&mesg, buf, &exp);
311 /* quietly ignore unknown words and anything
312 * following. Newer user-space can try to set
313 * new values, then see what the result was.
314 @@ -593,6 +638,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
316 static void exp_flags(struct seq_file *m, int flag, int fsid,
317 uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
318 +static void show_secinfo(struct seq_file *m, struct svc_export *exp);
320 static int svc_export_show(struct seq_file *m,
321 struct cache_detail *cd,
322 @@ -622,6 +668,7 @@ static int svc_export_show(struct seq_file *m,
323 seq_printf(m, "%02x", exp->ex_uuid[i]);
326 + show_secinfo(m, exp);
330 @@ -654,6 +701,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
332 struct svc_export *new = container_of(cnew, struct svc_export, h);
333 struct svc_export *item = container_of(citem, struct svc_export, h);
336 new->ex_flags = item->ex_flags;
337 new->ex_anon_uid = item->ex_anon_uid;
338 @@ -669,6 +717,10 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
339 item->ex_fslocs.locations_count = 0;
340 new->ex_fslocs.migrated = item->ex_fslocs.migrated;
341 item->ex_fslocs.migrated = 0;
342 + new->ex_nflavors = item->ex_nflavors;
343 + for (i = 0; i < MAX_SECINFO_LIST; i++){
344 + new->ex_flavors[i] = item->ex_flavors[i];
348 static struct cache_head *svc_export_alloc(void)
349 @@ -738,16 +790,18 @@ exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
354 + return ERR_PTR(-ENOENT);
357 key.ek_fsidtype = fsid_type;
358 memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
360 ek = svc_expkey_lookup(&key);
362 - if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp)))
365 + return ERR_PTR(-ENOMEM);
366 + err = cache_check(&svc_expkey_cache, &ek->h, reqp);
368 + return ERR_PTR(err);
372 @@ -808,30 +862,21 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
373 struct cache_req *reqp)
375 struct svc_export *exp, key;
380 + return ERR_PTR(-ENOENT);
384 key.ex_dentry = dentry;
386 exp = svc_export_lookup(&key);
390 - err = cache_check(&svc_export_cache, &exp->h, reqp);
395 - exp = ERR_PTR(err);
403 + return ERR_PTR(-ENOMEM);
404 + err = cache_check(&svc_export_cache, &exp->h, reqp);
406 + return ERR_PTR(err);
410 @@ -847,7 +892,7 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
412 exp = exp_get_by_name(clp, mnt, dentry, reqp);
414 - while (exp == NULL && !IS_ROOT(dentry)) {
415 + while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
416 struct dentry *parent;
418 parent = dget_parent(dentry);
419 @@ -900,7 +945,7 @@ static void exp_fsid_unhash(struct svc_export *exp)
422 ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
423 - if (ek && !IS_ERR(ek)) {
425 ek->h.expiry_time = get_seconds()-1;
426 cache_put(&ek->h, &svc_expkey_cache);
428 @@ -938,7 +983,7 @@ static void exp_unhash(struct svc_export *exp)
429 struct inode *inode = exp->ex_dentry->d_inode;
431 ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
432 - if (ek && !IS_ERR(ek)) {
434 ek->h.expiry_time = get_seconds()-1;
435 cache_put(&ek->h, &svc_expkey_cache);
437 @@ -989,13 +1034,12 @@ exp_export(struct nfsctl_export *nxp)
439 /* must make sure there won't be an ex_fsid clash */
440 if ((nxp->ex_flags & NFSEXP_FSID) &&
441 - (fsid_key = exp_get_fsid_key(clp, nxp->ex_dev)) &&
442 - !IS_ERR(fsid_key) &&
443 + (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
445 (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
449 + if (!IS_ERR(exp)) {
450 /* just a flags/id/fsid update */
452 exp_fsid_unhash(exp);
453 @@ -1104,7 +1148,7 @@ exp_unexport(struct nfsctl_export *nxp)
455 exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
461 exp_do_unexport(exp);
462 @@ -1149,10 +1193,6 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
467 - dprintk("nfsd: exp_rootfh export not found.\n");
472 * fh must be initialized before calling fh_compose
473 @@ -1176,17 +1216,130 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
475 struct svc_export *exp;
476 struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
477 - if (!ek || IS_ERR(ek))
479 return ERR_PTR(PTR_ERR(ek));
481 exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
482 cache_put(&ek->h, &svc_expkey_cache);
484 - if (!exp || IS_ERR(exp))
486 return ERR_PTR(PTR_ERR(exp));
490 +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
492 + struct exp_flavor_info *f;
493 + struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
495 + /* legacy gss-only clients are always OK: */
496 + if (exp->ex_client == rqstp->rq_gssclient)
498 + /* ip-address based client; check sec= export option: */
499 + for (f = exp->ex_flavors; f < end; f++) {
500 + if (f->pseudoflavor == rqstp->rq_flavor)
503 + /* defaults in absence of sec= options: */
504 + if (exp->ex_nflavors == 0) {
505 + if (rqstp->rq_flavor == RPC_AUTH_NULL ||
506 + rqstp->rq_flavor == RPC_AUTH_UNIX)
509 + return nfserr_wrongsec;
513 + * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
514 + * auth_unix client) if it's available and has secinfo information;
515 + * otherwise, will try to use rq_gssclient.
517 + * Called from functions that handle requests; functions that do work on
518 + * behalf of mountd are passed a single client name to use, and should
519 + * use exp_get_by_name() or exp_find().
522 +rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,
523 + struct dentry *dentry)
525 + struct svc_export *gssexp, *exp = NULL;
527 + if (rqstp->rq_client == NULL)
530 + /* First try the auth_unix client: */
531 + exp = exp_get_by_name(rqstp->rq_client, mnt, dentry,
532 + &rqstp->rq_chandle);
533 + if (PTR_ERR(exp) == -ENOENT)
537 + /* If it has secinfo, assume there are no gss/... clients */
538 + if (exp->ex_nflavors > 0)
541 + /* Otherwise, try falling back on gss client */
542 + if (rqstp->rq_gssclient == NULL)
544 + gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry,
545 + &rqstp->rq_chandle);
546 + if (PTR_ERR(gssexp) == -ENOENT)
554 +rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
556 + struct svc_export *gssexp, *exp = NULL;
558 + if (rqstp->rq_client == NULL)
561 + /* First try the auth_unix client: */
562 + exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle);
563 + if (PTR_ERR(exp) == -ENOENT)
567 + /* If it has secinfo, assume there are no gss/... clients */
568 + if (exp->ex_nflavors > 0)
571 + /* Otherwise, try falling back on gss client */
572 + if (rqstp->rq_gssclient == NULL)
574 + gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,
575 + &rqstp->rq_chandle);
576 + if (PTR_ERR(gssexp) == -ENOENT)
584 +rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt,
585 + struct dentry *dentry)
587 + struct svc_export *exp;
590 + exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
592 + while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
593 + struct dentry *parent;
595 + parent = dget_parent(dentry);
598 + exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
605 * Called when we need the filehandle for the root of the pseudofs,
606 @@ -1194,8 +1347,7 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
607 * export point with fsid==0
610 -exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
611 - struct cache_req *creq)
612 +exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
614 struct svc_export *exp;
616 @@ -1203,12 +1355,16 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
618 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
620 - exp = exp_find(clp, FSID_NUM, fsidv, creq);
621 + exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
622 + if (PTR_ERR(exp) == -ENOENT)
623 + return nfserr_perm;
625 return nfserrno(PTR_ERR(exp));
627 - return nfserr_perm;
628 rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
631 + rv = check_nfsd_access(exp, rqstp);
636 @@ -1296,28 +1452,62 @@ static struct flags {
640 -static void exp_flags(struct seq_file *m, int flag, int fsid,
641 - uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
642 +static void show_expflags(struct seq_file *m, int flags, int mask)
646 + int state, first = 0;
648 for (flg = expflags; flg->flag; flg++) {
649 - int state = (flg->flag & flag)?0:1;
650 + if (flg->flag & ~mask)
652 + state = (flg->flag & flags) ? 0 : 1;
653 if (*flg->name[state])
654 seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
658 +static void show_secinfo_flags(struct seq_file *m, int flags)
660 + seq_printf(m, ",");
661 + show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
664 +static void show_secinfo(struct seq_file *m, struct svc_export *exp)
666 + struct exp_flavor_info *f;
667 + struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
668 + int lastflags = 0, first = 0;
670 + if (exp->ex_nflavors == 0)
672 + for (f = exp->ex_flavors; f < end; f++) {
673 + if (first || f->flags != lastflags) {
675 + show_secinfo_flags(m, lastflags);
676 + seq_printf(m, ",sec=%d", f->pseudoflavor);
677 + lastflags = f->flags;
679 + seq_printf(m, ":%d", f->pseudoflavor);
682 + show_secinfo_flags(m, lastflags);
685 +static void exp_flags(struct seq_file *m, int flag, int fsid,
686 + uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
688 + show_expflags(m, flag, NFSEXP_ALLFLAGS);
689 if (flag & NFSEXP_FSID)
690 - seq_printf(m, "%sfsid=%d", first++?",":"", fsid);
691 + seq_printf(m, ",fsid=%d", fsid);
692 if (anonu != (uid_t)-2 && anonu != (0x10000-2))
693 - seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);
694 + seq_printf(m, ",sanonuid=%d", anonu);
695 if (anong != (gid_t)-2 && anong != (0x10000-2))
696 - seq_printf(m, "%sanongid=%d", first++?",":"", anong);
697 + seq_printf(m, ",sanongid=%d", anong);
698 if (fsloc && fsloc->locations_count > 0) {
699 char *loctype = (fsloc->migrated) ? "refer" : "replicas";
702 - seq_printf(m, "%s%s=", first++?",":"", loctype);
703 + seq_printf(m, ",%s=", loctype);
704 seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
706 seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
707 diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
708 index 221acd1..9e4a568 100644
709 --- a/fs/nfsd/lockd.c
710 +++ b/fs/nfsd/lockd.c
711 @@ -65,6 +65,7 @@ nlm_fclose(struct file *filp)
712 static struct nlmsvc_binding nfsd_nlm_ops = {
713 .fopen = nlm_fopen, /* open file for locking */
714 .fclose = nlm_fclose, /* close file */
715 + .get_grace_period = get_nfs4_grace_period,
719 diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
720 index cc3b7ba..b6ed383 100644
721 --- a/fs/nfsd/nfs4acl.c
722 +++ b/fs/nfsd/nfs4acl.c
723 @@ -183,8 +183,13 @@ static void
724 summarize_posix_acl(struct posix_acl *acl, struct posix_acl_summary *pas)
726 struct posix_acl_entry *pa, *pe;
731 + * Only pas.users and pas.groups need initialization; previous
732 + * posix_acl_valid() calls ensure that the other fields will be
733 + * initialized in the following loop. But, just to placate gcc:
735 + memset(pas, 0, sizeof(*pas));
738 pe = acl->a_entries + acl->a_count;
739 @@ -732,13 +737,16 @@ int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
740 *pacl = posix_state_to_acl(&effective_acl_state, flags);
742 ret = PTR_ERR(*pacl);
746 *dpacl = posix_state_to_acl(&default_acl_state,
747 flags | NFS4_ACL_TYPE_DEFAULT);
748 if (IS_ERR(*dpacl)) {
749 ret = PTR_ERR(*dpacl);
751 posix_acl_release(*pacl);
756 diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
757 index 864090e..c9e0c30 100644
758 --- a/fs/nfsd/nfs4callback.c
759 +++ b/fs/nfsd/nfs4callback.c
760 @@ -75,7 +75,7 @@ enum nfs_cb_opnum4 {
763 #define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2))
764 -#define enc_stateid_sz 16
765 +#define enc_stateid_sz (NFS4_STATEID_SIZE >> 2)
766 #define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \
767 1 + enc_stateid_sz + \
769 diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
770 index 45aa21c..2cf9a9a 100644
771 --- a/fs/nfsd/nfs4idmap.c
772 +++ b/fs/nfsd/nfs4idmap.c
773 @@ -587,6 +587,15 @@ idmap_lookup(struct svc_rqst *rqstp,
778 +rqst_authname(struct svc_rqst *rqstp)
780 + struct auth_domain *clp;
782 + clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client;
787 idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
789 @@ -600,7 +609,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
791 memcpy(key.name, name, namelen);
792 key.name[namelen] = '\0';
793 - strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
794 + strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
795 ret = idmap_lookup(rqstp, nametoid_lookup, &key, &nametoid_cache, &item);
797 ret = -ESRCH; /* nfserr_badname */
798 @@ -620,7 +629,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
802 - strlcpy(key.authname, rqstp->rq_client->name, sizeof(key.authname));
803 + strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
804 ret = idmap_lookup(rqstp, idtoname_lookup, &key, &idtoname_cache, &item);
806 return sprintf(name, "%u", id);
807 diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
808 index 8522729..9403095 100644
809 --- a/fs/nfsd/nfs4proc.c
810 +++ b/fs/nfsd/nfs4proc.c
812 #include <linux/nfsd/state.h>
813 #include <linux/nfsd/xdr4.h>
814 #include <linux/nfs4_acl.h>
815 +#include <linux/sunrpc/gss_api.h>
817 #define NFSDDBG_FACILITY NFSDDBG_PROC
819 @@ -286,8 +287,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
822 fh_put(&cstate->current_fh);
823 - status = exp_pseudoroot(rqstp->rq_client, &cstate->current_fh,
824 - &rqstp->rq_chandle);
825 + status = exp_pseudoroot(rqstp, &cstate->current_fh);
829 @@ -474,8 +474,8 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
832 fh_init(&tmp_fh, NFS4_FHSIZE);
833 - if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh,
834 - &rqstp->rq_chandle)) != 0)
835 + ret = exp_pseudoroot(rqstp, &tmp_fh);
838 if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
840 @@ -611,6 +611,29 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
844 +nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_secinfo *secinfo)
846 + struct svc_fh resfh;
847 + struct svc_export *exp;
848 + struct dentry *dentry;
851 + fh_init(&resfh, NFS4_FHSIZE);
852 + err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
853 + secinfo->si_name, secinfo->si_namelen,
857 + if (dentry->d_inode == NULL) {
859 + err = nfserr_noent;
861 + secinfo->si_exp = exp;
867 nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
868 struct nfsd4_setattr *setattr)
870 @@ -1009,6 +1032,9 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
872 .op_func = (nfsd4op_func)nfsd4_savefh,
875 + .op_func = (nfsd4op_func)nfsd4_secinfo,
878 .op_func = (nfsd4op_func)nfsd4_setattr,
880 diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
881 index 3cc8ce4..47d48e8 100644
882 --- a/fs/nfsd/nfs4state.c
883 +++ b/fs/nfsd/nfs4state.c
885 #include <linux/namei.h>
886 #include <linux/mutex.h>
887 #include <linux/lockd/bind.h>
888 +#include <linux/module.h>
890 #define NFSDDBG_FACILITY NFSDDBG_PROC
892 @@ -149,6 +150,7 @@ get_nfs4_file(struct nfs4_file *fi)
895 static int num_delegations;
896 +unsigned int max_delegations = 0;
899 * Open owner state (share locks)
900 @@ -192,7 +194,9 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
901 struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
903 dprintk("NFSD alloc_init_deleg\n");
904 - if (num_delegations > STATEID_HASH_SIZE * 4)
905 + if (fp->fi_had_conflict)
907 + if (num_delegations > max_delegations)
909 dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
911 @@ -1000,6 +1004,7 @@ alloc_init_file(struct inode *ino)
912 list_add(&fp->fi_hash, &file_hashtbl[hashval]);
913 fp->fi_inode = igrab(ino);
914 fp->fi_id = current_fileid++;
915 + fp->fi_had_conflict = false;
919 @@ -1326,6 +1331,7 @@ do_recall(void *__dp)
921 struct nfs4_delegation *dp = __dp;
923 + dp->dl_file->fi_had_conflict = true;
927 @@ -3191,6 +3197,23 @@ nfsd4_load_reboot_recovery_data(void)
928 printk("NFSD: Failure reading reboot recovery data\n");
932 +get_nfs4_grace_period(void)
934 + return max(user_lease_time, lease_time);
938 +set_max_delegations()
940 + struct sysinfo sys;
943 + sys.totalram *= sys.mem_unit;
944 + sys.totalram >>= (18 - PAGE_SHIFT);
945 + max_delegations = (unsigned int) sys.totalram;
948 /* initialization to perform when the nfsd service is started: */
951 @@ -3199,12 +3222,13 @@ __nfs4_state_start(void)
954 boot_time = get_seconds();
955 - grace_time = max(user_lease_time, lease_time);
956 + grace_time = get_nfs_grace_period();
957 lease_time = user_lease_time;
959 printk("NFSD: starting %ld-second grace period\n", grace_time);
960 laundry_wq = create_singlethread_workqueue("nfsd4");
961 queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ);
962 + set_max_delegations();
966 diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
967 index 15809df..be8c614 100644
968 --- a/fs/nfsd/nfs4xdr.c
969 +++ b/fs/nfsd/nfs4xdr.c
971 #include <linux/nfsd_idmap.h>
972 #include <linux/nfs4.h>
973 #include <linux/nfs4_acl.h>
974 +#include <linux/sunrpc/gss_api.h>
975 +#include <linux/sunrpc/svcauth_gss.h>
977 #define NFSDDBG_FACILITY NFSDDBG_XDR
979 @@ -819,6 +821,22 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
983 +nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, struct nfsd4_secinfo *secinfo)
988 + READ32(secinfo->si_namelen);
989 + READ_BUF(secinfo->si_namelen);
990 + SAVEMEM(secinfo->si_name, secinfo->si_namelen);
991 + status = check_filename(secinfo->si_name, secinfo->si_namelen,
999 nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
1002 @@ -1131,6 +1149,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1004 op->status = nfs_ok;
1007 + op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo);
1010 op->status = nfsd4_decode_setattr(argp, &op->u.setattr);
1012 @@ -1296,7 +1317,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
1013 char *path, *rootpath;
1015 fh_init(&tmp_fh, NFS4_FHSIZE);
1016 - *stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle);
1017 + *stat = exp_pseudoroot(rqstp, &tmp_fh);
1020 rootpath = tmp_fh.fh_export->ex_path;
1021 @@ -1847,11 +1868,19 @@ nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
1022 if (d_mountpoint(dentry)) {
1026 + * Why the heck aren't we just using nfsd_lookup??
1027 + * Different "."/".." handling? Something else?
1028 + * At least, add a comment here to explain....
1030 err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
1032 nfserr = nfserrno(err);
1035 + nfserr = check_nfsd_access(exp, cd->rd_rqstp);
1040 nfserr = nfsd4_encode_fattr(NULL, exp, dentry, p, buflen, cd->rd_bmval,
1041 @@ -2419,6 +2448,71 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_
1046 +nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_secinfo *secinfo)
1049 + struct svc_export *exp = secinfo->si_exp;
1051 + struct exp_flavor_info *flavs;
1052 + struct exp_flavor_info def_flavs[2];
1057 + if (exp->ex_nflavors) {
1058 + flavs = exp->ex_flavors;
1059 + nflavs = exp->ex_nflavors;
1060 + } else { /* Handling of some defaults in absence of real secinfo: */
1061 + flavs = def_flavs;
1062 + if (exp->ex_client->flavour->flavour == RPC_AUTH_UNIX) {
1064 + flavs[0].pseudoflavor = RPC_AUTH_UNIX;
1065 + flavs[1].pseudoflavor = RPC_AUTH_NULL;
1066 + } else if (exp->ex_client->flavour->flavour == RPC_AUTH_GSS) {
1068 + flavs[0].pseudoflavor
1069 + = svcauth_gss_flavor(exp->ex_client);
1072 + flavs[0].pseudoflavor
1073 + = exp->ex_client->flavour->flavour;
1080 + for (i = 0; i < nflavs; i++) {
1081 + u32 flav = flavs[i].pseudoflavor;
1082 + struct gss_api_mech *gm = gss_mech_get_by_pseudoflavor(flav);
1086 + WRITE32(RPC_AUTH_GSS);
1088 + RESERVE_SPACE(4 + gm->gm_oid.len);
1089 + WRITE32(gm->gm_oid.len);
1090 + WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
1093 + WRITE32(0); /* qop */
1096 + WRITE32(gss_pseudoflavor_to_service(gm, flav));
1111 * The SETATTR encode routine is special -- it always encodes a bitmap,
1112 * regardless of the error status.
1113 @@ -2559,6 +2653,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
1118 + nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo);
1121 nfsd4_encode_setattr(resp, op->status, &op->u.setattr);
1123 diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
1124 index 71c686d..4f10257 100644
1125 --- a/fs/nfsd/nfsctl.c
1126 +++ b/fs/nfsd/nfsctl.c
1128 #include <linux/nfsd/cache.h>
1129 #include <linux/nfsd/xdr.h>
1130 #include <linux/nfsd/syscall.h>
1131 -#include <linux/nfsd/interface.h>
1133 #include <asm/uaccess.h>
1135 diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
1136 index 6ca2d24..5198573 100644
1137 --- a/fs/nfsd/nfsfh.c
1138 +++ b/fs/nfsd/nfsfh.c
1141 #include <linux/sunrpc/clnt.h>
1142 #include <linux/sunrpc/svc.h>
1143 +#include <linux/sunrpc/svcauth_gss.h>
1144 #include <linux/nfsd/nfsd.h>
1146 #define NFSDDBG_FACILITY NFSDDBG_FH
1147 @@ -123,8 +124,6 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
1148 int data_left = fh->fh_size/4;
1150 error = nfserr_stale;
1151 - if (rqstp->rq_client == NULL)
1153 if (rqstp->rq_vers > 2)
1154 error = nfserr_badhandle;
1155 if (rqstp->rq_vers == 4 && fh->fh_size == 0)
1156 @@ -148,7 +147,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
1157 fh->fh_fsid[1] = fh->fh_fsid[2];
1159 if ((data_left -= len)<0) goto out;
1160 - exp = exp_find(rqstp->rq_client, fh->fh_fsid_type, datap, &rqstp->rq_chandle);
1161 + exp = rqst_exp_find(rqstp, fh->fh_fsid_type, datap);
1165 @@ -159,19 +158,17 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
1166 xdev = old_decode_dev(fh->ofh_xdev);
1167 xino = u32_to_ino_t(fh->ofh_xino);
1168 mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL);
1169 - exp = exp_find(rqstp->rq_client, FSID_DEV, tfh,
1170 - &rqstp->rq_chandle);
1171 + exp = rqst_exp_find(rqstp, FSID_DEV, tfh);
1174 - if (IS_ERR(exp) && (PTR_ERR(exp) == -EAGAIN
1175 - || PTR_ERR(exp) == -ETIMEDOUT)) {
1176 - error = nfserrno(PTR_ERR(exp));
1177 + error = nfserr_stale;
1178 + if (PTR_ERR(exp) == -ENOENT)
1182 - error = nfserr_stale;
1183 - if (!exp || IS_ERR(exp))
1184 + if (IS_ERR(exp)) {
1185 + error = nfserrno(PTR_ERR(exp));
1189 /* Check if the request originated from a secure port. */
1190 error = nfserr_perm;
1191 @@ -257,8 +254,19 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
1195 + if (!(access & MAY_LOCK)) {
1197 + * pseudoflavor restrictions are not enforced on NLM,
1198 + * which clients virtually always use auth_sys for,
1199 + * even while using RPCSEC_GSS for NFS.
1201 + error = check_nfsd_access(exp, rqstp);
1206 /* Finally, check access permissions. */
1207 - error = nfsd_permission(exp, dentry, access);
1208 + error = nfsd_permission(rqstp, exp, dentry, access);
1211 dprintk("fh_verify: %s/%s permission failure, "
1212 diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
1213 index b2c7147..977a71f 100644
1214 --- a/fs/nfsd/nfsproc.c
1215 +++ b/fs/nfsd/nfsproc.c
1216 @@ -278,7 +278,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
1217 * echo thing > device-special-file-or-pipe
1218 * by doing a CREATE with type==0
1220 - nfserr = nfsd_permission(newfhp->fh_export,
1221 + nfserr = nfsd_permission(rqstp,
1222 + newfhp->fh_export,
1224 MAY_WRITE|MAY_LOCAL_ACCESS);
1225 if (nfserr && nfserr != nfserr_rofs)
1226 diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
1227 index ff55950..da33b25 100644
1228 --- a/fs/nfsd/nfssvc.c
1229 +++ b/fs/nfsd/nfssvc.c
1230 @@ -492,6 +492,15 @@ out:
1231 module_put_and_exit(0);
1234 +static __be32 map_new_errors(u32 vers, __be32 nfserr)
1236 + if (nfserr == nfserr_jukebox && vers == 2)
1237 + return nfserr_dropit;
1238 + if (nfserr == nfserr_wrongsec && vers < 4)
1239 + return nfserr_acces;
1244 nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
1246 @@ -534,6 +543,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
1248 /* Now call the procedure handler, and encode NFS status. */
1249 nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
1250 + nfserr = map_new_errors(rqstp->rq_vers, nfserr);
1251 if (nfserr == nfserr_jukebox && rqstp->rq_vers == 2)
1252 nfserr = nfserr_dropit;
1253 if (nfserr == nfserr_dropit) {
1254 diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
1255 index 7e6aa24..8a3f520 100644
1258 @@ -113,7 +113,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
1260 while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));
1262 - exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle);
1263 + exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts);
1265 err = PTR_ERR(exp2);
1267 @@ -135,21 +135,10 @@ out:
1272 - * Look up one component of a pathname.
1273 - * N.B. After this call _both_ fhp and resfh need an fh_put
1275 - * If the lookup would cross a mountpoint, and the mounted filesystem
1276 - * is exported to the client with NFSEXP_NOHIDE, then the lookup is
1277 - * accepted as it stands and the mounted directory is
1278 - * returned. Otherwise the covered directory is returned.
1279 - * NOTE: this mountpoint crossing is not supported properly by all
1280 - * clients and is explicitly disallowed for NFSv3
1281 - * NeilBrown <neilb@cse.unsw.edu.au>
1284 -nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
1285 - int len, struct svc_fh *resfh)
1286 +nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
1287 + const char *name, int len,
1288 + struct svc_export **exp_ret, struct dentry **dentry_ret)
1290 struct svc_export *exp;
1291 struct dentry *dparent;
1292 @@ -168,8 +157,6 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
1293 exp = fhp->fh_export;
1296 - err = nfserr_acces;
1298 /* Lookup the name, but don't follow links */
1299 if (isdotent(name, len)) {
1301 @@ -190,17 +177,15 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
1305 - exp2 = exp_parent(exp->ex_client, mnt, dentry,
1306 - &rqstp->rq_chandle);
1307 - if (IS_ERR(exp2)) {
1308 + exp2 = rqst_exp_parent(rqstp, mnt, dentry);
1309 + if (PTR_ERR(exp2) == -ENOENT) {
1311 + dentry = dget(dparent);
1312 + } else if (IS_ERR(exp2)) {
1313 host_err = PTR_ERR(exp2);
1320 - dentry = dget(dparent);
1324 @@ -223,6 +208,41 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
1328 + *dentry_ret = dentry;
1334 + return nfserrno(host_err);
1338 + * Look up one component of a pathname.
1339 + * N.B. After this call _both_ fhp and resfh need an fh_put
1341 + * If the lookup would cross a mountpoint, and the mounted filesystem
1342 + * is exported to the client with NFSEXP_NOHIDE, then the lookup is
1343 + * accepted as it stands and the mounted directory is
1344 + * returned. Otherwise the covered directory is returned.
1345 + * NOTE: this mountpoint crossing is not supported properly by all
1346 + * clients and is explicitly disallowed for NFSv3
1347 + * NeilBrown <neilb@cse.unsw.edu.au>
1350 +nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
1351 + int len, struct svc_fh *resfh)
1353 + struct svc_export *exp;
1354 + struct dentry *dentry;
1357 + err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
1360 + err = check_nfsd_access(exp, rqstp);
1364 * Note: we compose the file handle now, but as the
1365 * dentry may be negative, it may need to be updated.
1366 @@ -230,16 +250,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
1367 err = fh_compose(resfh, exp, dentry, fhp);
1368 if (!err && !dentry->d_inode)
1377 - err = nfserrno(host_err);
1383 * Set various file attributes.
1384 * N.B. After this call fhp needs an fh_put
1385 @@ -311,7 +328,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
1386 /* The size case is special. It changes the file as well as the attributes. */
1387 if (iap->ia_valid & ATTR_SIZE) {
1388 if (iap->ia_size < inode->i_size) {
1389 - err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
1390 + err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
1394 @@ -435,7 +452,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
1396 error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
1401 dentry = fhp->fh_dentry;
1402 inode = dentry->d_inode;
1403 @@ -444,33 +461,25 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
1405 host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
1406 if (host_error == -EINVAL) {
1407 - error = nfserr_attrnotsupp;
1409 + return nfserr_attrnotsupp;
1410 } else if (host_error < 0)
1413 host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
1418 - if (S_ISDIR(inode->i_mode)) {
1419 + if (S_ISDIR(inode->i_mode))
1420 host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
1421 - if (host_error < 0)
1429 posix_acl_release(pacl);
1430 posix_acl_release(dpacl);
1433 if (host_error == -EOPNOTSUPP)
1434 - error = nfserr_attrnotsupp;
1435 + return nfserr_attrnotsupp;
1437 - error = nfserrno(host_error);
1439 + return nfserrno(host_error);
1442 static struct posix_acl *
1443 @@ -607,7 +616,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
1445 sresult |= map->access;
1447 - err2 = nfsd_permission(export, dentry, map->how);
1448 + err2 = nfsd_permission(rqstp, export, dentry, map->how);
1451 result |= map->access;
1452 @@ -1018,7 +1027,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1456 - err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
1457 + err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
1458 MAY_READ|MAY_OWNER_OVERRIDE);
1461 @@ -1047,7 +1056,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1465 - err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
1466 + err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
1467 MAY_WRITE|MAY_OWNER_OVERRIDE);
1470 @@ -1776,7 +1785,8 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
1471 * Check for a user's access permissions to this inode.
1474 -nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
1475 +nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
1476 + struct dentry *dentry, int acc)
1478 struct inode *inode = dentry->d_inode;
1480 @@ -1807,7 +1817,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
1482 if (!(acc & MAY_LOCAL_ACCESS))
1483 if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
1484 - if (EX_RDONLY(exp) || IS_RDONLY(inode))
1485 + if (EX_RDONLY(exp, rqstp) || IS_RDONLY(inode))
1487 if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
1489 diff --git a/fs/open.c b/fs/open.c
1490 index 0d515d1..c32aba0 100644
1493 @@ -255,24 +255,26 @@ static long do_sys_truncate(const char __user * path, loff_t length)
1494 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
1498 - * Make sure that there are no leases.
1500 - error = break_lease(inode, FMODE_WRITE);
1501 + error = get_write_access(inode);
1505 - error = get_write_access(inode);
1507 + * Make sure that there are no leases. get_write_access() protects
1508 + * against the truncate racing with a lease-granting setlease().
1510 + error = break_lease(inode, FMODE_WRITE);
1512 - goto dput_and_out;
1513 + goto put_write_and_out;
1515 error = locks_verify_truncate(inode, NULL, length);
1518 error = do_truncate(nd.dentry, length, 0, NULL);
1520 - put_write_access(inode);
1523 + put_write_access(inode);
1527 diff --git a/include/linux/fs.h b/include/linux/fs.h
1528 index b3ae77c..9df3553 100644
1529 --- a/include/linux/fs.h
1530 +++ b/include/linux/fs.h
1531 @@ -855,7 +855,7 @@ extern void locks_init_lock(struct file_lock *);
1532 extern void locks_copy_lock(struct file_lock *, struct file_lock *);
1533 extern void locks_remove_posix(struct file *, fl_owner_t);
1534 extern void locks_remove_flock(struct file *);
1535 -extern int posix_test_lock(struct file *, struct file_lock *);
1536 +extern void posix_test_lock(struct file *, struct file_lock *);
1537 extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *);
1538 extern int posix_lock_file_wait(struct file *, struct file_lock *);
1539 extern int posix_unblock_lock(struct file *, struct file_lock *);
1540 diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
1541 index 246de1d..df008eb 100644
1542 --- a/include/linux/lockd/bind.h
1543 +++ b/include/linux/lockd/bind.h
1544 @@ -27,6 +27,7 @@ struct nlmsvc_binding {
1547 void (*fclose)(struct file *);
1548 + time_t (*get_grace_period)(void);
1551 extern struct nlmsvc_binding * nlmsvc_ops;
1552 @@ -38,4 +39,12 @@ extern int nlmclnt_proc(struct inode *, int, struct file_lock *);
1553 extern int lockd_up(int proto);
1554 extern void lockd_down(void);
1556 +time_t get_nfs_grace_period(void);
1558 +#ifdef CONFIG_NFSD_V4
1559 +time_t get_nfs4_grace_period(void);
1561 +static inline void get_nfs4_grace_period(void) {return 0;}
1564 #endif /* LINUX_LOCKD_BIND_H */
1565 diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
1566 index 9f62d61..78feb7b 100644
1567 --- a/include/linux/nfsd/export.h
1568 +++ b/include/linux/nfsd/export.h
1570 #define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
1571 #define NFSEXP_ALLFLAGS 0xFE3F
1573 +/* The flags that may vary depending on security flavor: */
1574 +#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
1575 + | NFSEXP_ALLSQUASH)
1579 @@ -64,6 +67,19 @@ struct nfsd4_fs_locations {
1584 + * We keep an array of pseudoflavors with the export, in order from most
1585 + * to least preferred. For the forseeable future, we don't expect more
1586 + * than the eight pseudoflavors null, unix, krb5, krb5i, krb5p, skpm3,
1587 + * spkm3i, and spkm3p (and using all 8 at once should be rare).
1589 +#define MAX_SECINFO_LIST 8
1591 +struct exp_flavor_info {
1597 struct cache_head h;
1598 struct auth_domain * ex_client;
1599 @@ -76,6 +92,8 @@ struct svc_export {
1601 unsigned char * ex_uuid; /* 16 byte fsid */
1602 struct nfsd4_fs_locations ex_fslocs;
1604 + struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST];
1607 /* an "export key" (expkey) maps a filehandlefragement to an
1608 @@ -95,10 +113,22 @@ struct svc_expkey {
1610 #define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
1611 #define EX_ISSYNC(exp) (!((exp)->ex_flags & NFSEXP_ASYNC))
1612 -#define EX_RDONLY(exp) ((exp)->ex_flags & NFSEXP_READONLY)
1613 #define EX_NOHIDE(exp) ((exp)->ex_flags & NFSEXP_NOHIDE)
1614 #define EX_WGATHER(exp) ((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
1616 +static inline int EX_RDONLY(struct svc_export *exp, struct svc_rqst *rqstp)
1618 + struct exp_flavor_info *f;
1619 + struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1621 + for (f = exp->ex_flavors; f < end; f++) {
1622 + if (f->pseudoflavor == rqstp->rq_flavor)
1623 + return f->flags & NFSEXP_READONLY;
1625 + return exp->ex_flags & NFSEXP_READONLY;
1628 +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
1631 * Function declarations
1632 @@ -112,13 +142,19 @@ struct svc_export * exp_get_by_name(struct auth_domain *clp,
1633 struct vfsmount *mnt,
1634 struct dentry *dentry,
1635 struct cache_req *reqp);
1636 +struct svc_export * rqst_exp_get_by_name(struct svc_rqst *,
1637 + struct vfsmount *,
1639 struct svc_export * exp_parent(struct auth_domain *clp,
1640 struct vfsmount *mnt,
1641 struct dentry *dentry,
1642 struct cache_req *reqp);
1643 +struct svc_export * rqst_exp_parent(struct svc_rqst *,
1644 + struct vfsmount *mnt,
1645 + struct dentry *dentry);
1646 int exp_rootfh(struct auth_domain *,
1647 char *path, struct knfsd_fh *, int maxsize);
1648 -__be32 exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
1649 +__be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *);
1650 __be32 nfserrno(int errno);
1652 extern struct cache_detail svc_export_cache;
1653 @@ -135,6 +171,7 @@ static inline void exp_get(struct svc_export *exp)
1654 extern struct svc_export *
1655 exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
1656 struct cache_req *reqp);
1657 +struct svc_export * rqst_exp_find(struct svc_rqst *, int, u32 *);
1659 #endif /* __KERNEL__ */
1661 diff --git a/include/linux/nfsd/interface.h b/include/linux/nfsd/interface.h
1662 deleted file mode 100644
1663 index af09797..0000000
1664 --- a/include/linux/nfsd/interface.h
1668 - * include/linux/nfsd/interface.h
1670 - * defines interface between nfsd and other bits of
1671 - * the kernel. Particularly filesystems (eventually).
1673 - * Copyright (C) 2000 Neil Brown <neilb@cse.unsw.edu.au>
1676 -#ifndef LINUX_NFSD_INTERFACE_H
1677 -#define LINUX_NFSD_INTERFACE_H
1679 -#endif /* LINUX_NFSD_INTERFACE_H */
1680 diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
1681 index 72feac5..e452256 100644
1682 --- a/include/linux/nfsd/nfsd.h
1683 +++ b/include/linux/nfsd/nfsd.h
1685 #include <linux/nfsd/export.h>
1686 #include <linux/nfsd/auth.h>
1687 #include <linux/nfsd/stats.h>
1688 -#include <linux/nfsd/interface.h>
1692 @@ -72,6 +71,9 @@ int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
1693 struct svc_export **expp);
1694 __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
1695 const char *, int, struct svc_fh *);
1696 +__be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
1697 + const char *, int,
1698 + struct svc_export **, struct dentry **);
1699 __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
1700 struct iattr *, int, time_t);
1701 #ifdef CONFIG_NFSD_V4
1702 @@ -120,7 +122,8 @@ __be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
1705 int nfsd_notify_change(struct inode *, struct iattr *);
1706 -__be32 nfsd_permission(struct svc_export *, struct dentry *, int);
1707 +__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
1708 + struct dentry *, int);
1709 int nfsd_sync_dir(struct dentry *dp);
1711 #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
1712 @@ -149,6 +152,7 @@ extern int nfsd_max_blksize;
1715 #ifdef CONFIG_NFSD_V4
1716 +extern unsigned int max_delegations;
1717 void nfs4_state_init(void);
1718 int nfs4_state_start(void);
1719 void nfs4_state_shutdown(void);
1720 @@ -236,6 +240,7 @@ void nfsd_lockd_shutdown(void);
1721 #define nfserr_badname __constant_htonl(NFSERR_BADNAME)
1722 #define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN)
1723 #define nfserr_locked __constant_htonl(NFSERR_LOCKED)
1724 +#define nfserr_wrongsec __constant_htonl(NFSERR_WRONGSEC)
1725 #define nfserr_replay_me __constant_htonl(NFSERR_REPLAY_ME)
1727 /* error codes for internal use */
1728 diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
1729 index ab5c236..db348f7 100644
1730 --- a/include/linux/nfsd/state.h
1731 +++ b/include/linux/nfsd/state.h
1732 @@ -67,7 +67,7 @@ struct nfs4_cb_recall {
1734 stateid_t cbr_stateid;
1736 - u32 cbr_fhval[NFS4_FHSIZE];
1737 + char cbr_fhval[NFS4_FHSIZE];
1738 struct nfs4_delegation *cbr_dp;
1741 @@ -224,6 +224,7 @@ struct nfs4_file {
1742 struct inode *fi_inode;
1743 u32 fi_id; /* used with stateowner->so_id
1744 * for stateid_hashtbl hash */
1745 + bool fi_had_conflict;
1749 diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
1750 index 09799bc..1b65326 100644
1751 --- a/include/linux/nfsd/xdr4.h
1752 +++ b/include/linux/nfsd/xdr4.h
1753 @@ -293,6 +293,12 @@ struct nfsd4_rename {
1754 struct nfsd4_change_info rn_tinfo; /* response */
1757 +struct nfsd4_secinfo {
1758 + u32 si_namelen; /* request */
1759 + char *si_name; /* request */
1760 + struct svc_export *si_exp; /* response */
1763 struct nfsd4_setattr {
1764 stateid_t sa_stateid; /* request */
1765 u32 sa_bmval[2]; /* request */
1766 @@ -365,6 +371,7 @@ struct nfsd4_op {
1767 struct nfsd4_remove remove;
1768 struct nfsd4_rename rename;
1770 + struct nfsd4_secinfo secinfo;
1771 struct nfsd4_setattr setattr;
1772 struct nfsd4_setclientid setclientid;
1773 struct nfsd4_setclientid_confirm setclientid_confirm;
1774 diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
1775 index 5eca9e4..f76f705 100644
1776 --- a/include/linux/sunrpc/gss_api.h
1777 +++ b/include/linux/sunrpc/gss_api.h
1778 @@ -58,6 +58,7 @@ u32 gss_unwrap(
1779 u32 gss_delete_sec_context(
1780 struct gss_ctx **ctx_id);
1782 +u32 gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 service);
1783 u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor);
1784 char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service);
1786 diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
1787 index 4a7ae8a..211f8da 100644
1788 --- a/include/linux/sunrpc/svc.h
1789 +++ b/include/linux/sunrpc/svc.h
1790 @@ -212,6 +212,7 @@ struct svc_rqst {
1791 struct svc_pool * rq_pool; /* thread pool */
1792 struct svc_procedure * rq_procinfo; /* procedure info */
1793 struct auth_ops * rq_authop; /* authentication flavour */
1794 + u32 rq_flavor; /* pseudoflavor */
1795 struct svc_cred rq_cred; /* auth info */
1796 struct sk_buff * rq_skbuff; /* fast recv inet buffer */
1797 struct svc_deferred_req*rq_deferred; /* deferred request we are replaying */
1798 @@ -248,6 +249,7 @@ struct svc_rqst {
1800 /* Catering to nfsd */
1801 struct auth_domain * rq_client; /* RPC peer info */
1802 + struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
1803 struct svc_cacherep * rq_cacherep; /* cache info */
1804 struct knfsd_fh * rq_reffh; /* Referrence filehandle, used to
1805 * determine what device number
1806 diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
1807 index de92619..22e1ef8 100644
1808 --- a/include/linux/sunrpc/svcauth.h
1809 +++ b/include/linux/sunrpc/svcauth.h
1810 @@ -127,6 +127,7 @@ extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
1811 extern int auth_unix_forget_old(struct auth_domain *dom);
1812 extern void svcauth_unix_purge(void);
1813 extern void svcauth_unix_info_release(void *);
1814 +extern int svcauth_unix_set_client(struct svc_rqst *rqstp);
1816 static inline unsigned long hash_str(char *name, int bits)
1818 diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h
1819 index 5a5db16..442b061 100644
1820 --- a/include/linux/sunrpc/svcauth_gss.h
1821 +++ b/include/linux/sunrpc/svcauth_gss.h
1823 int gss_svc_init(void);
1824 void gss_svc_shutdown(void);
1825 int svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name);
1826 +u32 svcauth_gss_flavor(struct auth_domain *dom);
1829 #endif /* __KERNEL__ */
1830 #endif /* _LINUX_SUNRPC_SVCAUTH_GSS_H */
1831 diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
1832 index 7b19432..03e0b8b 100644
1833 --- a/net/sunrpc/auth_gss/gss_krb5_mech.c
1834 +++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
1835 @@ -231,6 +231,7 @@ static struct pf_desc gss_kerberos_pfs[] = {
1836 static struct gss_api_mech gss_kerberos_mech = {
1838 .gm_owner = THIS_MODULE,
1839 + .gm_oid = {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"},
1840 .gm_ops = &gss_kerberos_ops,
1841 .gm_pf_num = ARRAY_SIZE(gss_kerberos_pfs),
1842 .gm_pfs = gss_kerberos_pfs,
1843 diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
1844 index 2687251..5c4e983 100644
1845 --- a/net/sunrpc/auth_gss/gss_mech_switch.c
1846 +++ b/net/sunrpc/auth_gss/gss_mech_switch.c
1847 @@ -194,6 +194,21 @@ gss_mech_get_by_pseudoflavor(u32 pseudoflavor)
1848 EXPORT_SYMBOL(gss_mech_get_by_pseudoflavor);
1851 +gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
1855 + for (i = 0; i < gm->gm_pf_num; i++) {
1856 + if (gm->gm_pfs[i].service == service) {
1857 + return gm->gm_pfs[i].pseudoflavor;
1860 + return RPC_AUTH_MAXFLAVOR; /* illegal value */
1863 +EXPORT_SYMBOL(gss_svc_to_pseudoflavor);
1866 gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
1869 diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
1870 index 7e15aa6..9331119 100644
1871 --- a/net/sunrpc/auth_gss/gss_spkm3_mech.c
1872 +++ b/net/sunrpc/auth_gss/gss_spkm3_mech.c
1873 @@ -217,6 +217,7 @@ static struct pf_desc gss_spkm3_pfs[] = {
1874 static struct gss_api_mech gss_spkm3_mech = {
1876 .gm_owner = THIS_MODULE,
1877 + .gm_oid = {7, "\053\006\001\005\005\001\003"},
1878 .gm_ops = &gss_spkm3_ops,
1879 .gm_pf_num = ARRAY_SIZE(gss_spkm3_pfs),
1880 .gm_pfs = gss_spkm3_pfs,
1881 diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
1882 index 099a983..34d6763 100644
1883 --- a/net/sunrpc/auth_gss/svcauth_gss.c
1884 +++ b/net/sunrpc/auth_gss/svcauth_gss.c
1885 @@ -743,6 +743,15 @@ find_gss_auth_domain(struct gss_ctx *ctx, u32 svc)
1887 static struct auth_ops svcauthops_gss;
1889 +u32 svcauth_gss_flavor(struct auth_domain *dom)
1891 + struct gss_domain *gd = container_of(dom, struct gss_domain, h);
1893 + return gd->pseudoflavor;
1896 +EXPORT_SYMBOL(svcauth_gss_flavor);
1899 svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
1901 @@ -913,10 +922,23 @@ svcauth_gss_set_client(struct svc_rqst *rqstp)
1902 struct gss_svc_data *svcdata = rqstp->rq_auth_data;
1903 struct rsc *rsci = svcdata->rsci;
1904 struct rpc_gss_wire_cred *gc = &svcdata->clcred;
1907 - rqstp->rq_client = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
1908 - if (rqstp->rq_client == NULL)
1910 + * A gss export can be specified either by:
1911 + * export *(sec=krb5,rw)
1913 + * export gss/krb5(rw)
1914 + * The latter is deprecated; but for backwards compatibility reasons
1915 + * the nfsd code will still fall back on trying it if the former
1916 + * doesn't work; so we try to make both available to nfsd, below.
1918 + rqstp->rq_gssclient = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
1919 + if (rqstp->rq_gssclient == NULL)
1921 + stat = svcauth_unix_set_client(rqstp);
1922 + if (stat == SVC_DROP)
1927 @@ -1088,7 +1110,6 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1928 svc_putnl(resv, GSS_SEQ_WIN);
1929 if (svc_safe_putnetobj(resv, &rsip->out_token))
1931 - rqstp->rq_client = NULL;
1934 case RPC_GSS_PROC_DESTROY:
1935 @@ -1131,6 +1152,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1937 svcdata->rsci = rsci;
1938 cache_get(&rsci->h);
1939 + rqstp->rq_flavor = gss_svc_to_pseudoflavor(
1940 + rsci->mechctx->mech_type, gc->gc_svc);
1944 @@ -1317,6 +1340,9 @@ out_err:
1945 if (rqstp->rq_client)
1946 auth_domain_put(rqstp->rq_client);
1947 rqstp->rq_client = NULL;
1948 + if (rqstp->rq_gssclient)
1949 + auth_domain_put(rqstp->rq_gssclient);
1950 + rqstp->rq_gssclient = NULL;
1951 if (rqstp->rq_cred.cr_group_info)
1952 put_group_info(rqstp->rq_cred.cr_group_info);
1953 rqstp->rq_cred.cr_group_info = NULL;
1954 diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
1955 index 07dcd20..4114794 100644
1956 --- a/net/sunrpc/svcauth_unix.c
1957 +++ b/net/sunrpc/svcauth_unix.c
1959 #include <linux/sunrpc/xdr.h>
1960 #include <linux/sunrpc/svcsock.h>
1961 #include <linux/sunrpc/svcauth.h>
1962 +#include <linux/sunrpc/gss_api.h>
1963 #include <linux/err.h>
1964 #include <linux/seq_file.h>
1965 #include <linux/hash.h>
1966 @@ -637,7 +638,7 @@ static int unix_gid_find(uid_t uid, struct group_info **gip,
1972 svcauth_unix_set_client(struct svc_rqst *rqstp)
1974 struct sockaddr_in *sin = svc_addr_in(rqstp);
1975 @@ -672,6 +673,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
1979 +EXPORT_SYMBOL(svcauth_unix_set_client);
1982 svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
1984 @@ -707,6 +710,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
1985 svc_putnl(resv, RPC_AUTH_NULL);
1988 + rqstp->rq_flavor = RPC_AUTH_NULL;
1992 @@ -784,6 +788,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
1993 svc_putnl(resv, RPC_AUTH_NULL);
1996 + rqstp->rq_flavor = RPC_AUTH_UNIX;