]> git.pld-linux.org Git - packages/kernel.git/blob - linux-2.6.22-rc5-CITI_NFS4_ALL-1.diff
- more strict values parser
[packages/kernel.git] / linux-2.6.22-rc5-CITI_NFS4_ALL-1.diff
1 Changes since 2.6.22-rc1-CITI_NFS4_ALL-1
2         - update to 2.6.22-rc5
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
14
15 ---
16
17  b/fs/Kconfig                            |    1 
18  b/fs/lockd/svc.c                        |   31 ++-
19  b/fs/locks.c                            |   23 +-
20  b/fs/nfs/file.c                         |    4 
21  b/fs/nfsd/auth.c                        |   18 +-
22  b/fs/nfsd/export.c                      |  284 ++++++++++++++++++++++++++------
23  b/fs/nfsd/lockd.c                       |    1 
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 ++++++------
35  b/fs/open.c                             |   16 +
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(-)
53
54 diff --git a/fs/Kconfig b/fs/Kconfig
55 index 0fa0c11..76cf825 100644
56 --- a/fs/Kconfig
57 +++ b/fs/Kconfig
58 @@ -1675,6 +1675,7 @@ config NFSD_V3_ACL
59  config NFSD_V4
60         bool "Provide NFSv4 server support (EXPERIMENTAL)"
61         depends on NFSD_V3 && EXPERIMENTAL
62 +       select RPCSEC_GSS_KRB5
63         help
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
68 --- a/fs/lockd/svc.c
69 +++ b/fs/lockd/svc.c
70 @@ -75,18 +75,35 @@ static const int            nlm_port_min = 0, nlm_port_max = 65535;
71  
72  static struct ctl_table_header * nlm_sysctl_table;
73  
74 -static unsigned long set_grace_period(void)
75 +static time_t get_lockd_grace_period(void)
76  {
77 -       unsigned long grace_period;
78 -
79         /* Note: nlm_timeout should always be nonzero */
80         if (nlm_grace_period)
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;
85         else
86 -               grace_period = nlm_timeout * 5 * HZ;
87 +               return nlm_timeout * 5;
88 +}
89 +
90 +time_t get_nfs_grace_period(void)
91 +{
92 +       time_t lockdgrace = get_lockd_grace_period();
93 +       time_t nfsdgrace = 0;
94 +
95 +       if (nlmsvc_ops)
96 +               nfsdgrace = nlmsvc_ops->get_grace_period();
97 +
98 +       return max(lockdgrace, nfsdgrace);
99 +}
100 +EXPORT_SYMBOL(get_nfs_grace_period);
101 +
102 +static unsigned long set_grace_period(void)
103 +{
104 +       time_t grace_period;
105 +
106 +       grace_period = get_nfs_grace_period();
107         nlmsvc_grace_period = 1;
108 -       return grace_period + jiffies;
109 +       return grace_period * HZ + jiffies;
110  }
111  
112  static inline void clear_grace_period(void)
113 diff --git a/fs/locks.c b/fs/locks.c
114 index 431a8b8..bcc37b9 100644
115 --- a/fs/locks.c
116 +++ b/fs/locks.c
117 @@ -661,7 +661,7 @@ static int locks_block_on_timeout(struct file_lock *blocker, struct file_lock *w
118         return result;
119  }
120  
121 -int
122 +void
123  posix_test_lock(struct file *filp, struct file_lock *fl)
124  {
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) {
128                 if (!IS_POSIX(cfl))
129                         continue;
130 -               if (posix_locks_conflict(cfl, fl))
131 +               if (posix_locks_conflict(fl, cfl))
132                         break;
133         }
134 -       if (cfl) {
135 +       if (cfl)
136                 __locks_copy_lock(fl, cfl);
137 -               unlock_kernel();
138 -               return 1;
139 -       } else
140 +       else
141                 fl->fl_type = F_UNLCK;
142         unlock_kernel();
143 -       return 0;
144 +       return;
145  }
146  
147  EXPORT_SYMBOL(posix_test_lock);
148 @@ -823,7 +821,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
149         lock_kernel();
150         if (request->fl_type != F_UNLCK) {
151                 for_each_lock(inode, before) {
152 -                       struct file_lock *fl = *before;
153 +                       fl = *before;
154                         if (!IS_POSIX(fl))
155                                 continue;
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)
160   *
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().
168   */
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)
171  /**
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
177   *
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
182 --- a/fs/nfs/file.c
183 +++ b/fs/nfs/file.c
184 @@ -397,7 +397,9 @@ static int do_getlk(struct file *filp, int cmd, struct file_lock *fl)
185  
186         lock_kernel();
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 */
192                 goto out;
193         }
194  
195 diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
196 index 6e92b0f..cf61dc8 100644
197 --- a/fs/nfsd/auth.c
198 +++ b/fs/nfsd/auth.c
199 @@ -12,17 +12,31 @@
200  
201  #define        CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE))
202  
203 +static int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp)
204 +{
205 +       struct exp_flavor_info *f;
206 +       struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
207 +
208 +       for (f = exp->ex_flavors; f < end; f++) {
209 +               if (f->pseudoflavor == rqstp->rq_flavor)
210 +                       return f->flags;
211 +       }
212 +       return exp->ex_flags;
213 +
214 +}
215 +
216  int nfsd_setuser(struct svc_rqst *rqstp, struct svc_export *exp)
217  {
218         struct svc_cred cred = rqstp->rq_cred;
219         int i;
220 +       int flags = nfsexp_flags(rqstp, exp);
221         int ret;
222  
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;
231                 if (!cred.cr_uid)
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
237 @@ -32,6 +32,8 @@
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>
243  
244  #define NFSDDBG_FACILITY       NFSDDBG_EXPORT
245  
246 @@ -451,8 +453,46 @@ out_free_all:
247         return err;
248  }
249  
250 +static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
251 +{
252 +       int listsize, err;
253 +       struct exp_flavor_info *f;
254 +
255 +       err = get_int(mesg, &listsize);
256 +       if (err)
257 +               return err;
258 +       if (listsize < 0 || listsize > MAX_SECINFO_LIST)
259 +               return -EINVAL;
260 +
261 +       for (f=exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
262 +               err = get_int(mesg, &f->pseudoflavor);
263 +               if (err)
264 +                       return err;
265 +               /*
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
272 +                * authenticate.
273 +                */
274 +               if (f->pseudoflavor < 0)
275 +                       return -EINVAL;
276 +               err = get_int(mesg, &f->flags);
277 +               if (err)
278 +                       return err;
279 +               /* Only some flags are allowed to differ between flavors: */
280 +               if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
281 +                       return -EINVAL;
282 +       }
283 +       exp->ex_nflavors = listsize;
284 +       return 0;
285 +}
286 +
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; }
290  #endif
291  
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)
294  
295         exp.ex_uuid = NULL;
296  
297 +       /* secinfo */
298 +       exp.ex_nflavors = 0;
299 +
300         if (mesg[mlen-1] != '\n')
301                 return -EINVAL;
302         mesg[mlen-1] = 0;
303 @@ -553,7 +596,9 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
304                                         if (exp.ex_uuid == NULL)
305                                                 err = -ENOMEM;
306                                 }
307 -                       } else
308 +                       } else if (strcmp(buf, "secinfo") == 0)
309 +                               err = secinfo_parse(&mesg, buf, &exp);
310 +                       else
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)
315  
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);
319  
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]);
324                         }
325                 }
326 +               show_secinfo(m, exp);
327         }
328         seq_puts(m, ")\n");
329         return 0;
330 @@ -654,6 +701,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
331  {
332         struct svc_export *new = container_of(cnew, struct svc_export, h);
333         struct svc_export *item = container_of(citem, struct svc_export, h);
334 +       int i;
335  
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];
345 +       }
346  }
347  
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)
350         int err;
351         
352         if (!clp)
353 -               return NULL;
354 +               return ERR_PTR(-ENOENT);
355  
356         key.ek_client = clp;
357         key.ek_fsidtype = fsid_type;
358         memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
359  
360         ek = svc_expkey_lookup(&key);
361 -       if (ek != NULL)
362 -               if ((err = cache_check(&svc_expkey_cache, &ek->h, reqp)))
363 -                       ek = ERR_PTR(err);
364 +       if (ek == NULL)
365 +               return ERR_PTR(-ENOMEM);
366 +       err = cache_check(&svc_expkey_cache, &ek->h, reqp);
367 +       if (err)
368 +               return ERR_PTR(err);
369         return ek;
370  }
371  
372 @@ -808,30 +862,21 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
373                 struct cache_req *reqp)
374  {
375         struct svc_export *exp, key;
376 +       int err;
377         
378         if (!clp)
379 -               return NULL;
380 +               return ERR_PTR(-ENOENT);
381  
382         key.ex_client = clp;
383         key.ex_mnt = mnt;
384         key.ex_dentry = dentry;
385  
386         exp = svc_export_lookup(&key);
387 -       if (exp != NULL)  {
388 -               int err;
389 -
390 -               err = cache_check(&svc_export_cache, &exp->h, reqp);
391 -               switch (err) {
392 -               case 0: break;
393 -               case -EAGAIN:
394 -               case -ETIMEDOUT:
395 -                       exp = ERR_PTR(err);
396 -                       break;
397 -               default:
398 -                       exp = NULL;
399 -               }
400 -       }
401 -
402 +       if (exp == NULL)
403 +               return ERR_PTR(-ENOMEM);
404 +       err = cache_check(&svc_export_cache, &exp->h, reqp);
405 +       if (err)
406 +               return ERR_PTR(err);
407         return exp;
408  }
409  
410 @@ -847,7 +892,7 @@ exp_parent(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
411         dget(dentry);
412         exp = exp_get_by_name(clp, mnt, dentry, reqp);
413  
414 -       while (exp == NULL && !IS_ROOT(dentry)) {
415 +       while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
416                 struct dentry *parent;
417  
418                 parent = dget_parent(dentry);
419 @@ -900,7 +945,7 @@ static void exp_fsid_unhash(struct svc_export *exp)
420                 return;
421  
422         ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
423 -       if (ek && !IS_ERR(ek)) {
424 +       if (!IS_ERR(ek)) {
425                 ek->h.expiry_time = get_seconds()-1;
426                 cache_put(&ek->h, &svc_expkey_cache);
427         }
428 @@ -938,7 +983,7 @@ static void exp_unhash(struct svc_export *exp)
429         struct inode *inode = exp->ex_dentry->d_inode;
430  
431         ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
432 -       if (ek && !IS_ERR(ek)) {
433 +       if (!IS_ERR(ek)) {
434                 ek->h.expiry_time = get_seconds()-1;
435                 cache_put(&ek->h, &svc_expkey_cache);
436         }
437 @@ -989,13 +1034,12 @@ exp_export(struct nfsctl_export *nxp)
438  
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))) &&
444             fsid_key->ek_mnt &&
445             (fsid_key->ek_mnt != nd.mnt || fsid_key->ek_dentry != nd.dentry) )
446                 goto finish;
447  
448 -       if (exp) {
449 +       if (!IS_ERR(exp)) {
450                 /* just a flags/id/fsid update */
451  
452                 exp_fsid_unhash(exp);
453 @@ -1104,7 +1148,7 @@ exp_unexport(struct nfsctl_export *nxp)
454         err = -EINVAL;
455         exp = exp_get_by_name(dom, nd.mnt, nd.dentry, NULL);
456         path_release(&nd);
457 -       if (!exp)
458 +       if (IS_ERR(exp))
459                 goto out_domain;
460  
461         exp_do_unexport(exp);
462 @@ -1149,10 +1193,6 @@ exp_rootfh(svc_client *clp, char *path, struct knfsd_fh *f, int maxsize)
463                 err = PTR_ERR(exp);
464                 goto out;
465         }
466 -       if (!exp) {
467 -               dprintk("nfsd: exp_rootfh export not found.\n");
468 -               goto out;
469 -       }
470  
471         /*
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,
474  {
475         struct svc_export *exp;
476         struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
477 -       if (!ek || IS_ERR(ek))
478 +       if (IS_ERR(ek))
479                 return ERR_PTR(PTR_ERR(ek));
480  
481         exp = exp_get_by_name(clp, ek->ek_mnt, ek->ek_dentry, reqp);
482         cache_put(&ek->h, &svc_expkey_cache);
483  
484 -       if (!exp || IS_ERR(exp))
485 +       if (IS_ERR(exp))
486                 return ERR_PTR(PTR_ERR(exp));
487         return exp;
488  }
489  
490 +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
491 +{
492 +       struct exp_flavor_info *f;
493 +       struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
494 +
495 +       /* legacy gss-only clients are always OK: */
496 +       if (exp->ex_client == rqstp->rq_gssclient)
497 +               return 0;
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)
501 +                       return 0;
502 +       }
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)
507 +                       return 0;
508 +       }
509 +       return nfserr_wrongsec;
510 +}
511 +
512 +/*
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.
516 + *
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().
520 + */
521 +struct svc_export *
522 +rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt,
523 +               struct dentry *dentry)
524 +{
525 +       struct svc_export *gssexp, *exp = NULL;
526 +
527 +       if (rqstp->rq_client == NULL)
528 +               goto gss;
529 +
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)
534 +               goto gss;
535 +       if (IS_ERR(exp))
536 +               return exp;
537 +       /* If it has secinfo, assume there are no gss/... clients */
538 +       if (exp->ex_nflavors > 0)
539 +               return exp;
540 +gss:
541 +       /* Otherwise, try falling back on gss client */
542 +       if (rqstp->rq_gssclient == NULL)
543 +               return exp;
544 +       gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry,
545 +                                               &rqstp->rq_chandle);
546 +       if (PTR_ERR(gssexp) == -ENOENT)
547 +               return exp;
548 +       if (exp)
549 +               exp_put(exp);
550 +       return gssexp;
551 +}
552 +
553 +struct svc_export *
554 +rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
555 +{
556 +       struct svc_export *gssexp, *exp = NULL;
557 +
558 +       if (rqstp->rq_client == NULL)
559 +               goto gss;
560 +
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)
564 +               goto gss;
565 +       if (IS_ERR(exp))
566 +               return exp;
567 +       /* If it has secinfo, assume there are no gss/... clients */
568 +       if (exp->ex_nflavors > 0)
569 +               return exp;
570 +gss:
571 +       /* Otherwise, try falling back on gss client */
572 +       if (rqstp->rq_gssclient == NULL)
573 +               return exp;
574 +       gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,
575 +                                               &rqstp->rq_chandle);
576 +       if (PTR_ERR(gssexp) == -ENOENT)
577 +               return exp;
578 +       if (exp)
579 +               exp_put(exp);
580 +       return gssexp;
581 +}
582 +
583 +struct svc_export *
584 +rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt,
585 +               struct dentry *dentry)
586 +{
587 +       struct svc_export *exp;
588 +
589 +       dget(dentry);
590 +       exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
591 +
592 +       while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
593 +               struct dentry *parent;
594 +
595 +               parent = dget_parent(dentry);
596 +               dput(dentry);
597 +               dentry = parent;
598 +               exp = rqst_exp_get_by_name(rqstp, mnt, dentry);
599 +       }
600 +       dput(dentry);
601 +       return exp;
602 +}
603  
604  /*
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
608   */
609  __be32
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)
613  {
614         struct svc_export *exp;
615         __be32 rv;
616 @@ -1203,12 +1355,16 @@ exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
617  
618         mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
619  
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;
624         if (IS_ERR(exp))
625                 return nfserrno(PTR_ERR(exp));
626 -       if (exp == NULL)
627 -               return nfserr_perm;
628         rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
629 +       if (rv)
630 +               goto out;
631 +       rv = check_nfsd_access(exp, rqstp);
632 +out:
633         exp_put(exp);
634         return rv;
635  }
636 @@ -1296,28 +1452,62 @@ static struct flags {
637         { 0, {"", ""}}
638  };
639  
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)
643  {
644 -       int first = 0;
645         struct flags *flg;
646 +       int state, first = 0;
647  
648         for (flg = expflags; flg->flag; flg++) {
649 -               int state = (flg->flag & flag)?0:1;
650 +               if (flg->flag & ~mask)
651 +                       continue;
652 +               state = (flg->flag & flags) ? 0 : 1;
653                 if (*flg->name[state])
654                         seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
655         }
656 +}
657 +
658 +static void show_secinfo_flags(struct seq_file *m, int flags)
659 +{
660 +       seq_printf(m, ",");
661 +       show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
662 +}
663 +
664 +static void show_secinfo(struct seq_file *m, struct svc_export *exp)
665 +{
666 +       struct exp_flavor_info *f;
667 +       struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
668 +       int lastflags = 0, first = 0;
669 +
670 +       if (exp->ex_nflavors == 0)
671 +               return;
672 +       for (f = exp->ex_flavors; f < end; f++) {
673 +               if (first || f->flags != lastflags) {
674 +                       if (!first)
675 +                               show_secinfo_flags(m, lastflags);
676 +                       seq_printf(m, ",sec=%d", f->pseudoflavor);
677 +                       lastflags = f->flags;
678 +               } else {
679 +                       seq_printf(m, ":%d", f->pseudoflavor);
680 +               }
681 +       }
682 +       show_secinfo_flags(m, lastflags);
683 +}
684 +
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)
687 +{
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";
700                 int i;
701  
702 -               seq_printf(m, "%s%s=", first++?",":"", loctype);
703 +               seq_printf(m, ",%s=", loctype);
704                 seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
705                 seq_putc(m, '@');
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,
716  };
717  
718  void
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)
725  {
726         struct posix_acl_entry *pa, *pe;
727 -       pas->users = 0;
728 -       pas->groups = 0;
729 +
730 +       /*
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:
734 +        */
735 +       memset(pas, 0, sizeof(*pas));
736         pas->mask = 07;
737  
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);
741         if (IS_ERR(*pacl)) {
742                 ret = PTR_ERR(*pacl);
743 +               *pacl = NULL;
744                 goto out_dstate;
745         }
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);
750 +               *dpacl = NULL;
751                 posix_acl_release(*pacl);
752 +               *pacl = NULL;
753                 goto out_dstate;
754         }
755         sort_pacl(*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 {
761  #define op_enc_sz                      1
762  #define op_dec_sz                      2
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 +            \
768                                         enc_nfs4_fh_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,
774         return ret;
775  }
776  
777 +static char *
778 +rqst_authname(struct svc_rqst *rqstp)
779 +{
780 +       struct auth_domain *clp;
781 +
782 +       clp = rqstp->rq_gssclient ? rqstp->rq_gssclient : rqstp->rq_client;
783 +       return clp->name;
784 +}
785 +
786  static int
787  idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen,
788                 uid_t *id)
789 @@ -600,7 +609,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
790                 return -EINVAL;
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);
796         if (ret == -ENOENT)
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)
799         };
800         int ret;
801  
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);
805         if (ret == -ENOENT)
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
811 @@ -47,6 +47,7 @@
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>
816  
817  #define NFSDDBG_FACILITY               NFSDDBG_PROC
818  
819 @@ -286,8 +287,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
820         __be32 status;
821  
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);
826         return status;
827  }
828  
829 @@ -474,8 +474,8 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
830         __be32 ret;
831  
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);
836 +       if (ret)
837                 return ret;
838         if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
839                 fh_put(&tmp_fh);
840 @@ -611,6 +611,29 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
841  }
842  
843  static __be32
844 +nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_secinfo *secinfo)
845 +{
846 +       struct svc_fh resfh;
847 +       struct svc_export *exp;
848 +       struct dentry *dentry;
849 +       __be32 err;
850 +
851 +       fh_init(&resfh, NFS4_FHSIZE);
852 +       err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
853 +                                   secinfo->si_name, secinfo->si_namelen,
854 +                                   &exp, &dentry);
855 +       if (err)
856 +               return err;
857 +       if (dentry->d_inode == NULL) {
858 +               exp_put(exp);
859 +               err = nfserr_noent;
860 +       } else
861 +               secinfo->si_exp = exp;
862 +       dput(dentry);
863 +       return err;
864 +}
865 +
866 +static __be32
867  nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
868               struct nfsd4_setattr *setattr)
869  {
870 @@ -1009,6 +1032,9 @@ static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
871         [OP_SAVEFH] = {
872                 .op_func = (nfsd4op_func)nfsd4_savefh,
873         },
874 +       [OP_SECINFO] = {
875 +               .op_func = (nfsd4op_func)nfsd4_secinfo,
876 +       },
877         [OP_SETATTR] = {
878                 .op_func = (nfsd4op_func)nfsd4_setattr,
879         },
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
884 @@ -51,6 +51,7 @@
885  #include <linux/namei.h>
886  #include <linux/mutex.h>
887  #include <linux/lockd/bind.h>
888 +#include <linux/module.h>
889  
890  #define NFSDDBG_FACILITY                NFSDDBG_PROC
891  
892 @@ -149,6 +150,7 @@ get_nfs4_file(struct nfs4_file *fi)
893  }
894  
895  static int num_delegations;
896 +unsigned int max_delegations = 0;
897  
898  /*
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;
902  
903         dprintk("NFSD alloc_init_deleg\n");
904 -       if (num_delegations > STATEID_HASH_SIZE * 4)
905 +       if (fp->fi_had_conflict)
906 +               return NULL;
907 +       if (num_delegations > max_delegations)
908                 return NULL;
909         dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
910         if (dp == NULL)
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;
916                 return fp;
917         }
918         return NULL;
919 @@ -1326,6 +1331,7 @@ do_recall(void *__dp)
920  {
921         struct nfs4_delegation *dp = __dp;
922  
923 +       dp->dl_file->fi_had_conflict = true;
924         nfsd4_cb_recall(dp);
925         return 0;
926  }
927 @@ -3191,6 +3197,23 @@ nfsd4_load_reboot_recovery_data(void)
928                 printk("NFSD: Failure reading reboot recovery data\n");
929  }
930  
931 +time_t
932 +get_nfs4_grace_period(void)
933 +{
934 +       return max(user_lease_time, lease_time);
935 +}
936 +
937 +static void
938 +set_max_delegations()
939 +{
940 +       struct sysinfo sys;
941 +
942 +       si_meminfo(&sys);
943 +       sys.totalram *= sys.mem_unit;
944 +       sys.totalram >>= (18 - PAGE_SHIFT);
945 +       max_delegations = (unsigned int) sys.totalram;
946 +}
947 +
948  /* initialization to perform when the nfsd service is started: */
949  
950  static void
951 @@ -3199,12 +3222,13 @@ __nfs4_state_start(void)
952         time_t grace_time;
953  
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;
958         in_grace = 1;
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();
963  }
964  
965  int
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
970 @@ -56,6 +56,8 @@
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>
976  
977  #define NFSDDBG_FACILITY               NFSDDBG_XDR
978  
979 @@ -819,6 +821,22 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
980  }
981  
982  static __be32
983 +nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, struct nfsd4_secinfo *secinfo)
984 +{
985 +       DECODE_HEAD;
986 +
987 +       READ_BUF(4);
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,
992 +                                                               nfserr_noent);
993 +       if (status)
994 +               return status;
995 +       DECODE_TAIL;
996 +}
997 +
998 +static __be32
999  nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
1000  {
1001         DECODE_HEAD;
1002 @@ -1131,6 +1149,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
1003                 case OP_SAVEFH:
1004                         op->status = nfs_ok;
1005                         break;
1006 +               case OP_SECINFO:
1007 +                       op->status = nfsd4_decode_secinfo(argp, &op->u.secinfo);
1008 +                       break;
1009                 case OP_SETATTR:
1010                         op->status = nfsd4_decode_setattr(argp, &op->u.setattr);
1011                         break;
1012 @@ -1296,7 +1317,7 @@ static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *
1013         char *path, *rootpath;
1014  
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);
1018         if (*stat)
1019                 return NULL;
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)) {
1023                 int err;
1024  
1025 +               /*
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....
1029 +                */
1030                 err = nfsd_cross_mnt(cd->rd_rqstp, &dentry, &exp);
1031                 if (err) {
1032                         nfserr = nfserrno(err);
1033                         goto out_put;
1034                 }
1035 +               nfserr = check_nfsd_access(exp, cd->rd_rqstp);
1036 +               if (nfserr)
1037 +                       goto out_put;
1038  
1039         }
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_
1042         }
1043  }
1044  
1045 +static void
1046 +nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_secinfo *secinfo)
1047 +{
1048 +       int i = 0;
1049 +       struct svc_export *exp = secinfo->si_exp;
1050 +       u32 nflavs;
1051 +       struct exp_flavor_info *flavs;
1052 +       struct exp_flavor_info def_flavs[2];
1053 +       ENCODE_HEAD;
1054 +
1055 +       if (nfserr)
1056 +               goto out;
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) {
1063 +                       nflavs = 2;
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) {
1067 +                       nflavs = 1;
1068 +                       flavs[0].pseudoflavor
1069 +                                       = svcauth_gss_flavor(exp->ex_client);
1070 +               } else {
1071 +                       nflavs = 1;
1072 +                       flavs[0].pseudoflavor
1073 +                                       = exp->ex_client->flavour->flavour;
1074 +               }
1075 +       }
1076 +
1077 +       RESERVE_SPACE(4);
1078 +       WRITE32(nflavs);
1079 +       ADJUST_ARGS();
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);
1083 +
1084 +               if (gm) {
1085 +                       RESERVE_SPACE(4);
1086 +                       WRITE32(RPC_AUTH_GSS);
1087 +                       ADJUST_ARGS();
1088 +                       RESERVE_SPACE(4 + gm->gm_oid.len);
1089 +                       WRITE32(gm->gm_oid.len);
1090 +                       WRITEMEM(gm->gm_oid.data, gm->gm_oid.len);
1091 +                       ADJUST_ARGS();
1092 +                       RESERVE_SPACE(4);
1093 +                       WRITE32(0); /* qop */
1094 +                       ADJUST_ARGS();
1095 +                       RESERVE_SPACE(4);
1096 +                       WRITE32(gss_pseudoflavor_to_service(gm, flav));
1097 +                       ADJUST_ARGS();
1098 +                       gss_mech_put(gm);
1099 +               } else {
1100 +                       RESERVE_SPACE(4);
1101 +                       WRITE32(flav);
1102 +                       ADJUST_ARGS();
1103 +               }
1104 +       }
1105 +out:
1106 +       if (exp)
1107 +               exp_put(exp);
1108 +}
1109 +
1110  /*
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)
1114                 break;
1115         case OP_SAVEFH:
1116                 break;
1117 +       case OP_SECINFO:
1118 +               nfsd4_encode_secinfo(resp, op->status, &op->u.secinfo);
1119 +               break;
1120         case OP_SETATTR:
1121                 nfsd4_encode_setattr(resp, op->status, &op->u.setattr);
1122                 break;
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
1127 @@ -35,7 +35,6 @@
1128  #include <linux/nfsd/cache.h>
1129  #include <linux/nfsd/xdr.h>
1130  #include <linux/nfsd/syscall.h>
1131 -#include <linux/nfsd/interface.h>
1132  
1133  #include <asm/uaccess.h>
1134  
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
1139 @@ -19,6 +19,7 @@
1140  
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>
1145  
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;
1149  
1150                 error = nfserr_stale;
1151 -               if (rqstp->rq_client == NULL)
1152 -                       goto out;
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];
1158                         }
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);
1162                         datap += len;
1163                 } else {
1164                         dev_t xdev;
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);
1172                 }
1173  
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)
1179                         goto out;
1180 -               }
1181  
1182 -               error = nfserr_stale; 
1183 -               if (!exp || IS_ERR(exp))
1184 +               if (IS_ERR(exp)) {
1185 +                       error = nfserrno(PTR_ERR(exp));
1186                         goto out;
1187 +               }
1188  
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)
1192         if (error)
1193                 goto out;
1194  
1195 +       if (!(access & MAY_LOCK)) {
1196 +               /*
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.
1200 +                */
1201 +               error = check_nfsd_access(exp, rqstp);
1202 +               if (error)
1203 +                       goto out;
1204 +       }
1205 +
1206         /* Finally, check access permissions. */
1207 -       error = nfsd_permission(exp, dentry, access);
1208 +       error = nfsd_permission(rqstp, exp, dentry, access);
1209  
1210         if (error) {
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
1219                                          */
1220 -                                       nfserr = nfsd_permission(newfhp->fh_export,
1221 +                                       nfserr = nfsd_permission(rqstp,
1222 +                                                                newfhp->fh_export,
1223                                                                  newfhp->fh_dentry,
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);
1232  }
1233  
1234 +static __be32 map_new_errors(u32 vers, __be32 nfserr)
1235 +{
1236 +       if (nfserr == nfserr_jukebox && vers == 2)
1237 +               return nfserr_dropit;
1238 +       if (nfserr == nfserr_wrongsec && vers < 4)
1239 +               return nfserr_acces;
1240 +       return nfserr;
1241 +}
1242 +
1243  int
1244  nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
1245  {
1246 @@ -534,6 +543,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
1247  
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
1256 --- a/fs/nfsd/vfs.c
1257 +++ b/fs/nfsd/vfs.c
1258 @@ -113,7 +113,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
1259  
1260         while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));
1261  
1262 -       exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle);
1263 +       exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts);
1264         if (IS_ERR(exp2)) {
1265                 err = PTR_ERR(exp2);
1266                 dput(mounts);
1267 @@ -135,21 +135,10 @@ out:
1268         return err;
1269  }
1270  
1271 -/*
1272 - * Look up one component of a pathname.
1273 - * N.B. After this call _both_ fhp and resfh need an fh_put
1274 - *
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>
1282 - */
1283  __be32
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)
1289  {
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;
1294         exp_get(exp);
1295  
1296 -       err = nfserr_acces;
1297 -
1298         /* Lookup the name, but don't follow links */
1299         if (isdotent(name, len)) {
1300                 if (len==1)
1301 @@ -190,17 +177,15 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
1302                         dput(dentry);
1303                         dentry = dp;
1304  
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) {
1310 +                               dput(dentry);
1311 +                               dentry = dget(dparent);
1312 +                       } else if (IS_ERR(exp2)) {
1313                                 host_err = PTR_ERR(exp2);
1314                                 dput(dentry);
1315                                 mntput(mnt);
1316                                 goto out_nfserr;
1317 -                       }
1318 -                       if (!exp2) {
1319 -                               dput(dentry);
1320 -                               dentry = dget(dparent);
1321                         } else {
1322                                 exp_put(exp);
1323                                 exp = exp2;
1324 @@ -223,6 +208,41 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
1325                         }
1326                 }
1327         }
1328 +       *dentry_ret = dentry;
1329 +       *exp_ret = exp;
1330 +       return 0;
1331 +
1332 +out_nfserr:
1333 +       exp_put(exp);
1334 +       return nfserrno(host_err);
1335 +}
1336 +
1337 +/*
1338 + * Look up one component of a pathname.
1339 + * N.B. After this call _both_ fhp and resfh need an fh_put
1340 + *
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>
1348 + */
1349 +__be32
1350 +nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
1351 +                                       int len, struct svc_fh *resfh)
1352 +{
1353 +       struct svc_export       *exp;
1354 +       struct dentry           *dentry;
1355 +       __be32 err;
1356 +
1357 +       err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
1358 +       if (err)
1359 +               return err;
1360 +       err = check_nfsd_access(exp, rqstp);
1361 +       if (err)
1362 +               goto out;
1363         /*
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)
1369                 err = nfserr_noent;
1370 -       dput(dentry);
1371  out:
1372 +       dput(dentry);
1373         exp_put(exp);
1374         return err;
1375 -
1376 -out_nfserr:
1377 -       err = nfserrno(host_err);
1378 -       goto out;
1379  }
1380  
1381 +
1382  /*
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);
1391                         if (err)
1392                                 goto out;
1393                 }
1394 @@ -435,7 +452,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
1395         /* Get inode */
1396         error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
1397         if (error)
1398 -               goto out;
1399 +               return error;
1400  
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,
1404  
1405         host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
1406         if (host_error == -EINVAL) {
1407 -               error = nfserr_attrnotsupp;
1408 -               goto out;
1409 +               return nfserr_attrnotsupp;
1410         } else if (host_error < 0)
1411                 goto out_nfserr;
1412  
1413         host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
1414         if (host_error < 0)
1415 -               goto out_nfserr;
1416 +               goto out_release;
1417  
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)
1422 -                       goto out_nfserr;
1423 -       }
1424 -
1425 -       error = nfs_ok;
1426  
1427 -out:
1428 +out_release:
1429         posix_acl_release(pacl);
1430         posix_acl_release(dpacl);
1431 -       return (error);
1432  out_nfserr:
1433         if (host_error == -EOPNOTSUPP)
1434 -               error = nfserr_attrnotsupp;
1435 +               return nfserr_attrnotsupp;
1436         else
1437 -               error = nfserrno(host_error);
1438 -       goto out;
1439 +               return nfserrno(host_error);
1440  }
1441  
1442  static struct posix_acl *
1443 @@ -607,7 +616,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
1444  
1445                         sresult |= map->access;
1446  
1447 -                       err2 = nfsd_permission(export, dentry, map->how);
1448 +                       err2 = nfsd_permission(rqstp, export, dentry, map->how);
1449                         switch (err2) {
1450                         case nfs_ok:
1451                                 result |= map->access;
1452 @@ -1018,7 +1027,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1453         __be32          err;
1454  
1455         if (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);
1459                 if (err)
1460                         goto out;
1461 @@ -1047,7 +1056,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1462         __be32                  err = 0;
1463  
1464         if (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);
1468                 if (err)
1469                         goto out;
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.
1472   */
1473  __be32
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)
1477  {
1478         struct inode    *inode = dentry->d_inode;
1479         int             err;
1480 @@ -1807,7 +1817,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
1481          */
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))
1486                                 return nfserr_rofs;
1487                         if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
1488                                 return nfserr_perm;
1489 diff --git a/fs/open.c b/fs/open.c
1490 index 0d515d1..c32aba0 100644
1491 --- a/fs/open.c
1492 +++ b/fs/open.c
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))
1495                 goto dput_and_out;
1496  
1497 -       /*
1498 -        * Make sure that there are no leases.
1499 -        */
1500 -       error = break_lease(inode, FMODE_WRITE);
1501 +       error = get_write_access(inode);
1502         if (error)
1503                 goto dput_and_out;
1504  
1505 -       error = get_write_access(inode);
1506 +       /*
1507 +        * Make sure that there are no leases.  get_write_access() protects
1508 +        * against the truncate racing with a lease-granting setlease().
1509 +        */
1510 +       error = break_lease(inode, FMODE_WRITE);
1511         if (error)
1512 -               goto dput_and_out;
1513 +               goto put_write_and_out;
1514  
1515         error = locks_verify_truncate(inode, NULL, length);
1516         if (!error) {
1517                 DQUOT_INIT(inode);
1518                 error = do_truncate(nd.dentry, length, 0, NULL);
1519         }
1520 -       put_write_access(inode);
1521  
1522 +put_write_and_out:
1523 +       put_write_access(inode);
1524  dput_and_out:
1525         path_release(&nd);
1526  out:
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 {
1545                                                 struct nfs_fh *,
1546                                                 struct file **);
1547         void                    (*fclose)(struct file *);
1548 +       time_t                  (*get_grace_period)(void);
1549  };
1550  
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);
1555  
1556 +time_t get_nfs_grace_period(void);
1557 +
1558 +#ifdef CONFIG_NFSD_V4
1559 +time_t get_nfs4_grace_period(void);
1560 +#else
1561 +static inline void get_nfs4_grace_period(void) {return 0;}
1562 +#endif
1563 +
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
1569 @@ -42,6 +42,9 @@
1570  #define        NFSEXP_NOACL            0x8000  /* reserved for possible ACL related use */
1571  #define NFSEXP_ALLFLAGS                0xFE3F
1572  
1573 +/* The flags that may vary depending on security flavor: */
1574 +#define NFSEXP_SECINFO_FLAGS   (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
1575 +                                       | NFSEXP_ALLSQUASH)
1576  
1577  #ifdef __KERNEL__
1578  
1579 @@ -64,6 +67,19 @@ struct nfsd4_fs_locations {
1580         int migrated;
1581  };
1582  
1583 +/*
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).
1588 + */
1589 +#define MAX_SECINFO_LIST       8
1590 +
1591 +struct exp_flavor_info {
1592 +       u32     pseudoflavor;
1593 +       u32     flags;
1594 +};
1595 +
1596  struct svc_export {
1597         struct cache_head       h;
1598         struct auth_domain *    ex_client;
1599 @@ -76,6 +92,8 @@ struct svc_export {
1600         int                     ex_fsid;
1601         unsigned char *         ex_uuid; /* 16 byte fsid */
1602         struct nfsd4_fs_locations ex_fslocs;
1603 +       int                     ex_nflavors;
1604 +       struct exp_flavor_info  ex_flavors[MAX_SECINFO_LIST];
1605  };
1606  
1607  /* an "export key" (expkey) maps a filehandlefragement to an
1608 @@ -95,10 +113,22 @@ struct svc_expkey {
1609  
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)
1615  
1616 +static inline int EX_RDONLY(struct svc_export *exp, struct svc_rqst *rqstp)
1617 +{
1618 +       struct exp_flavor_info *f;
1619 +       struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1620 +
1621 +       for (f = exp->ex_flavors; f < end; f++) {
1622 +               if (f->pseudoflavor == rqstp->rq_flavor)
1623 +                       return f->flags & NFSEXP_READONLY;
1624 +       }
1625 +       return exp->ex_flags & NFSEXP_READONLY;
1626 +}
1627 +
1628 +__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp);
1629  
1630  /*
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 *,
1638 +                                            struct dentry *);
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);
1651  
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 *);
1658  
1659  #endif /* __KERNEL__ */
1660  
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
1665 +++ /dev/null
1666 @@ -1,13 +0,0 @@
1667 -/*
1668 - * include/linux/nfsd/interface.h
1669 - *
1670 - * defines interface between nfsd and other bits of
1671 - * the kernel.  Particularly filesystems (eventually).
1672 - *
1673 - * Copyright (C) 2000 Neil Brown <neilb@cse.unsw.edu.au>
1674 - */
1675 -
1676 -#ifndef LINUX_NFSD_INTERFACE_H
1677 -#define LINUX_NFSD_INTERFACE_H
1678 -
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
1684 @@ -22,7 +22,6 @@
1685  #include <linux/nfsd/export.h>
1686  #include <linux/nfsd/auth.h>
1687  #include <linux/nfsd/stats.h>
1688 -#include <linux/nfsd/interface.h>
1689  /*
1690   * nfsd version
1691   */
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 *,
1703                                 struct kstatfs *);
1704  
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);
1710  
1711  #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
1712 @@ -149,6 +152,7 @@ extern int nfsd_max_blksize;
1713   * NFSv4 State
1714   */
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)
1726  
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 {
1733         int                     cbr_trunc;
1734         stateid_t               cbr_stateid;
1735         u32                     cbr_fhlen;
1736 -       u32                     cbr_fhval[NFS4_FHSIZE];
1737 +       char                    cbr_fhval[NFS4_FHSIZE];
1738         struct nfs4_delegation  *cbr_dp;
1739  };
1740  
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;
1746  };
1747  
1748  /*
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 */
1755  };
1756  
1757 +struct nfsd4_secinfo {
1758 +       u32 si_namelen;                                 /* request */
1759 +       char *si_name;                                  /* request */
1760 +       struct svc_export *si_exp;                      /* response */
1761 +};
1762 +
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;
1769                 clientid_t                      renew;
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);
1781  
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);
1785  
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 {
1799                                                  */
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);
1815  
1816  static inline unsigned long hash_str(char *name, int bits)
1817  {
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
1822 @@ -22,6 +22,8 @@
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);
1827 +
1828  
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 = {
1837         .gm_name        = "krb5",
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);
1849  
1850  u32
1851 +gss_svc_to_pseudoflavor(struct gss_api_mech *gm, u32 service)
1852 +{
1853 +       int i;
1854 +
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;
1858 +               }
1859 +       }
1860 +       return RPC_AUTH_MAXFLAVOR; /* illegal value */
1861 +}
1862 +
1863 +EXPORT_SYMBOL(gss_svc_to_pseudoflavor);
1864 +
1865 +u32
1866  gss_pseudoflavor_to_service(struct gss_api_mech *gm, u32 pseudoflavor)
1867  {
1868         int i;
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 = {
1875         .gm_name        = "spkm3",
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)
1886  
1887  static struct auth_ops svcauthops_gss;
1888  
1889 +u32 svcauth_gss_flavor(struct auth_domain *dom)
1890 +{
1891 +       struct gss_domain *gd = container_of(dom, struct gss_domain, h);
1892 +
1893 +       return gd->pseudoflavor;
1894 +}
1895 +
1896 +EXPORT_SYMBOL(svcauth_gss_flavor);
1897 +
1898  int
1899  svcauth_gss_register_pseudoflavor(u32 pseudoflavor, char * name)
1900  {
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;
1905 +       int stat;
1906  
1907 -       rqstp->rq_client = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
1908 -       if (rqstp->rq_client == NULL)
1909 +       /*
1910 +        * A gss export can be specified either by:
1911 +        *      export  *(sec=krb5,rw)
1912 +        * or by
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.
1917 +        */
1918 +       rqstp->rq_gssclient = find_gss_auth_domain(rsci->mechctx, gc->gc_svc);
1919 +       if (rqstp->rq_gssclient == NULL)
1920                 return SVC_DENIED;
1921 +       stat = svcauth_unix_set_client(rqstp);
1922 +       if (stat == SVC_DROP)
1923 +               return stat;
1924         return SVC_OK;
1925  }
1926  
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))
1930                                 goto drop;
1931 -                       rqstp->rq_client = NULL;
1932                 }
1933                 goto complete;
1934         case RPC_GSS_PROC_DESTROY:
1935 @@ -1131,6 +1152,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1936                 }
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);
1941                 ret = SVC_OK;
1942                 goto out;
1943         }
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
1958 @@ -5,6 +5,7 @@
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,
1967         }
1968  }
1969  
1970 -static int
1971 +int
1972  svcauth_unix_set_client(struct svc_rqst *rqstp)
1973  {
1974         struct sockaddr_in *sin = svc_addr_in(rqstp);
1975 @@ -672,6 +673,8 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
1976         return SVC_OK;
1977  }
1978  
1979 +EXPORT_SYMBOL(svcauth_unix_set_client);
1980 +
1981  static int
1982  svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
1983  {
1984 @@ -707,6 +710,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
1985         svc_putnl(resv, RPC_AUTH_NULL);
1986         svc_putnl(resv, 0);
1987  
1988 +       rqstp->rq_flavor = RPC_AUTH_NULL;
1989         return SVC_OK;
1990  }
1991  
1992 @@ -784,6 +788,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
1993         svc_putnl(resv, RPC_AUTH_NULL);
1994         svc_putnl(resv, 0);
1995  
1996 +       rqstp->rq_flavor = RPC_AUTH_UNIX;
1997         return SVC_OK;
1998  
1999  badcred:
This page took 0.223326 seconds and 3 git commands to generate.