]> git.pld-linux.org Git - packages/kernel.git/blame - linux-2.6.22-rc5-CITI_NFS4_ALL-1.diff
- kernel kvm module build disabled, it is provided by kvm.spec
[packages/kernel.git] / linux-2.6.22-rc5-CITI_NFS4_ALL-1.diff
CommitLineData
7f651772 1Changes 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
54diff --git a/fs/Kconfig b/fs/Kconfig
55index 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
66diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
67index 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)
113diff --git a/fs/locks.c b/fs/locks.c
114index 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.
180diff --git a/fs/nfs/file.c b/fs/nfs/file.c
181index 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
195diff --git a/fs/nfsd/auth.c b/fs/nfsd/auth.c
196index 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;
233diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
234index 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\\");
707diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
708index 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
719diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
720index 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);
756diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
757index 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)
769diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
770index 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);
807diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
808index 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 },
880diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
881index 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
966diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
967index 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;
1123diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
1124index 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
1135diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
1136index 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, "
1212diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
1213index 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)
1226diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
1227index 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) {
1254diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
1255index 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;
1489diff --git a/fs/open.c b/fs/open.c
1490index 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:
1527diff --git a/include/linux/fs.h b/include/linux/fs.h
1528index 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 *);
1540diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
1541index 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 */
1565diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
1566index 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
1661diff --git a/include/linux/nfsd/interface.h b/include/linux/nfsd/interface.h
1662deleted file mode 100644
1663index 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 */
1680diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
1681index 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 */
1728diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
1729index 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 /*
1749diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
1750index 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;
1774diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
1775index 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
1786diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
1787index 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
1806diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
1807index 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 {
1818diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h
1819index 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 */
1831diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
1832index 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,
1843diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
1844index 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;
1869diff --git a/net/sunrpc/auth_gss/gss_spkm3_mech.c b/net/sunrpc/auth_gss/gss_spkm3_mech.c
1870index 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,
1881diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
1882index 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;
1954diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
1955index 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.23283 seconds and 4 git commands to generate.