aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/export.c22
-rw-r--r--fs/nfsd/lockd.c1
-rw-r--r--fs/nfsd/nfs2acl.c14
-rw-r--r--fs/nfsd/nfs3acl.c3
-rw-r--r--fs/nfsd/nfs3proc.c1
-rw-r--r--fs/nfsd/nfs4acl.c2
-rw-r--r--fs/nfsd/nfs4proc.c1
-rw-r--r--fs/nfsd/nfs4recover.c1
-rw-r--r--fs/nfsd/nfs4state.c65
-rw-r--r--fs/nfsd/nfs4xdr.c1
-rw-r--r--fs/nfsd/nfsfh.c1
-rw-r--r--fs/nfsd/nfsproc.c2
-rw-r--r--fs/nfsd/nfssvc.c1
-rw-r--r--fs/nfsd/vfs.c63
-rw-r--r--fs/nfsd/vfs.h98
15 files changed, 210 insertions, 66 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index c1c9e035d4a4..b73baba3fb97 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1320,6 +1320,23 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
1320 return exp; 1320 return exp;
1321} 1321}
1322 1322
1323static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp)
1324{
1325 struct svc_export *exp;
1326 u32 fsidv[2];
1327
1328 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1329
1330 exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
1331 /*
1332 * We shouldn't have accepting an nfsv4 request at all if we
1333 * don't have a pseudoexport!:
1334 */
1335 if (IS_ERR(exp) && PTR_ERR(exp) == -ENOENT)
1336 exp = ERR_PTR(-ESERVERFAULT);
1337 return exp;
1338}
1339
1323/* 1340/*
1324 * Called when we need the filehandle for the root of the pseudofs, 1341 * Called when we need the filehandle for the root of the pseudofs,
1325 * for a given NFSv4 client. The root is defined to be the 1342 * for a given NFSv4 client. The root is defined to be the
@@ -1330,11 +1347,8 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1330{ 1347{
1331 struct svc_export *exp; 1348 struct svc_export *exp;
1332 __be32 rv; 1349 __be32 rv;
1333 u32 fsidv[2];
1334
1335 mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1336 1350
1337 exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); 1351 exp = find_fsidzero_export(rqstp);
1338 if (IS_ERR(exp)) 1352 if (IS_ERR(exp))
1339 return nfserrno(PTR_ERR(exp)); 1353 return nfserrno(PTR_ERR(exp));
1340 rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); 1354 rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index b2786a5f9afe..812bc64874f6 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -16,6 +16,7 @@
16#include <linux/sunrpc/svc.h> 16#include <linux/sunrpc/svc.h>
17#include <linux/nfsd/nfsd.h> 17#include <linux/nfsd/nfsd.h>
18#include <linux/lockd/bind.h> 18#include <linux/lockd/bind.h>
19#include "vfs.h"
19 20
20#define NFSDDBG_FACILITY NFSDDBG_LOCKD 21#define NFSDDBG_FACILITY NFSDDBG_LOCKD
21 22
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index 4e3219e84116..38c883d48b02 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -14,6 +14,7 @@
14#include <linux/nfsd/xdr3.h> 14#include <linux/nfsd/xdr3.h>
15#include <linux/posix_acl.h> 15#include <linux/posix_acl.h>
16#include <linux/nfsacl.h> 16#include <linux/nfsacl.h>
17#include "vfs.h"
17 18
18#define NFSDDBG_FACILITY NFSDDBG_PROC 19#define NFSDDBG_FACILITY NFSDDBG_PROC
19#define RETURN_STATUS(st) { resp->status = (st); return (st); } 20#define RETURN_STATUS(st) { resp->status = (st); return (st); }
@@ -217,6 +218,16 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
217 * XDR encode functions 218 * XDR encode functions
218 */ 219 */
219 220
221/*
222 * There must be an encoding function for void results so svc_process
223 * will work properly.
224 */
225int
226nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
227{
228 return xdr_ressize_check(rqstp, p);
229}
230
220/* GETACL */ 231/* GETACL */
221static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, 232static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
222 struct nfsd3_getaclres *resp) 233 struct nfsd3_getaclres *resp)
@@ -308,7 +319,6 @@ static int nfsaclsvc_release_access(struct svc_rqst *rqstp, __be32 *p,
308} 319}
309 320
310#define nfsaclsvc_decode_voidargs NULL 321#define nfsaclsvc_decode_voidargs NULL
311#define nfsaclsvc_encode_voidres NULL
312#define nfsaclsvc_release_void NULL 322#define nfsaclsvc_release_void NULL
313#define nfsd3_fhandleargs nfsd_fhandle 323#define nfsd3_fhandleargs nfsd_fhandle
314#define nfsd3_attrstatres nfsd_attrstat 324#define nfsd3_attrstatres nfsd_attrstat
@@ -346,5 +356,5 @@ struct svc_version nfsd_acl_version2 = {
346 .vs_proc = nfsd_acl_procedures2, 356 .vs_proc = nfsd_acl_procedures2,
347 .vs_dispatch = nfsd_dispatch, 357 .vs_dispatch = nfsd_dispatch,
348 .vs_xdrsize = NFS3_SVC_XDRSIZE, 358 .vs_xdrsize = NFS3_SVC_XDRSIZE,
349 .vs_hidden = 1, 359 .vs_hidden = 0,
350}; 360};
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 9981dbb377a3..526d85a65f76 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -13,6 +13,7 @@
13#include <linux/nfsd/xdr3.h> 13#include <linux/nfsd/xdr3.h>
14#include <linux/posix_acl.h> 14#include <linux/posix_acl.h>
15#include <linux/nfsacl.h> 15#include <linux/nfsacl.h>
16#include "vfs.h"
16 17
17#define RETURN_STATUS(st) { resp->status = (st); return (st); } 18#define RETURN_STATUS(st) { resp->status = (st); return (st); }
18 19
@@ -264,6 +265,6 @@ struct svc_version nfsd_acl_version3 = {
264 .vs_proc = nfsd_acl_procedures3, 265 .vs_proc = nfsd_acl_procedures3,
265 .vs_dispatch = nfsd_dispatch, 266 .vs_dispatch = nfsd_dispatch,
266 .vs_xdrsize = NFS3_SVC_XDRSIZE, 267 .vs_xdrsize = NFS3_SVC_XDRSIZE,
267 .vs_hidden = 1, 268 .vs_hidden = 0,
268}; 269};
269 270
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index a713c418a922..1a259d313e14 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -25,6 +25,7 @@
25#include <linux/nfsd/cache.h> 25#include <linux/nfsd/cache.h>
26#include <linux/nfsd/xdr3.h> 26#include <linux/nfsd/xdr3.h>
27#include <linux/nfs3.h> 27#include <linux/nfs3.h>
28#include "vfs.h"
28 29
29#define NFSDDBG_FACILITY NFSDDBG_PROC 30#define NFSDDBG_FACILITY NFSDDBG_PROC
30 31
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 725d02f210e2..6d9c6aabc85e 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -389,7 +389,7 @@ sort_pacl(struct posix_acl *pacl)
389 sort_pacl_range(pacl, 1, i-1); 389 sort_pacl_range(pacl, 1, i-1);
390 390
391 BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ); 391 BUG_ON(pacl->a_entries[i].e_tag != ACL_GROUP_OBJ);
392 j = i++; 392 j = ++i;
393 while (pacl->a_entries[j].e_tag == ACL_GROUP) 393 while (pacl->a_entries[j].e_tag == ACL_GROUP)
394 j++; 394 j++;
395 sort_pacl_range(pacl, i, j-1); 395 sort_pacl_range(pacl, i, j-1);
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index bebc0c2e1b0a..60a93cdefef5 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -48,6 +48,7 @@
48#include <linux/nfsd/xdr4.h> 48#include <linux/nfsd/xdr4.h>
49#include <linux/nfs4_acl.h> 49#include <linux/nfs4_acl.h>
50#include <linux/sunrpc/gss_api.h> 50#include <linux/sunrpc/gss_api.h>
51#include "vfs.h"
51 52
52#define NFSDDBG_FACILITY NFSDDBG_PROC 53#define NFSDDBG_FACILITY NFSDDBG_PROC
53 54
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index b5348405046b..c7a6b245c7ad 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -47,6 +47,7 @@
47#include <linux/crypto.h> 47#include <linux/crypto.h>
48#include <linux/sched.h> 48#include <linux/sched.h>
49#include <linux/mount.h> 49#include <linux/mount.h>
50#include "vfs.h"
50 51
51#define NFSDDBG_FACILITY NFSDDBG_PROC 52#define NFSDDBG_FACILITY NFSDDBG_PROC
52 53
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 2153f9bdbebd..850960e5d626 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -56,6 +56,7 @@
56#include <linux/module.h> 56#include <linux/module.h>
57#include <linux/sunrpc/svcauth_gss.h> 57#include <linux/sunrpc/svcauth_gss.h>
58#include <linux/sunrpc/clnt.h> 58#include <linux/sunrpc/clnt.h>
59#include "vfs.h"
59 60
60#define NFSDDBG_FACILITY NFSDDBG_PROC 61#define NFSDDBG_FACILITY NFSDDBG_PROC
61 62
@@ -477,13 +478,14 @@ static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan)
477 478
478/* 479/*
479 * fchan holds the client values on input, and the server values on output 480 * fchan holds the client values on input, and the server values on output
481 * sv_max_mesg is the maximum payload plus one page for overhead.
480 */ 482 */
481static int init_forechannel_attrs(struct svc_rqst *rqstp, 483static int init_forechannel_attrs(struct svc_rqst *rqstp,
482 struct nfsd4_channel_attrs *session_fchan, 484 struct nfsd4_channel_attrs *session_fchan,
483 struct nfsd4_channel_attrs *fchan) 485 struct nfsd4_channel_attrs *fchan)
484{ 486{
485 int status = 0; 487 int status = 0;
486 __u32 maxcount = svc_max_payload(rqstp); 488 __u32 maxcount = nfsd_serv->sv_max_mesg;
487 489
488 /* headerpadsz set to zero in encode routine */ 490 /* headerpadsz set to zero in encode routine */
489 491
@@ -523,6 +525,15 @@ free_session_slots(struct nfsd4_session *ses)
523 kfree(ses->se_slots[i]); 525 kfree(ses->se_slots[i]);
524} 526}
525 527
528/*
529 * We don't actually need to cache the rpc and session headers, so we
530 * can allocate a little less for each slot:
531 */
532static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
533{
534 return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
535}
536
526static int 537static int
527alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, 538alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
528 struct nfsd4_create_session *cses) 539 struct nfsd4_create_session *cses)
@@ -554,7 +565,7 @@ alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp,
554 memcpy(new, &tmp, sizeof(*new)); 565 memcpy(new, &tmp, sizeof(*new));
555 566
556 /* allocate each struct nfsd4_slot and data cache in one piece */ 567 /* allocate each struct nfsd4_slot and data cache in one piece */
557 cachesize = new->se_fchannel.maxresp_cached - NFSD_MIN_HDR_SEQ_SZ; 568 cachesize = slot_bytes(&new->se_fchannel);
558 for (i = 0; i < new->se_fchannel.maxreqs; i++) { 569 for (i = 0; i < new->se_fchannel.maxreqs; i++) {
559 sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL); 570 sp = kzalloc(sizeof(*sp) + cachesize, GFP_KERNEL);
560 if (!sp) 571 if (!sp)
@@ -628,10 +639,12 @@ void
628free_session(struct kref *kref) 639free_session(struct kref *kref)
629{ 640{
630 struct nfsd4_session *ses; 641 struct nfsd4_session *ses;
642 int mem;
631 643
632 ses = container_of(kref, struct nfsd4_session, se_ref); 644 ses = container_of(kref, struct nfsd4_session, se_ref);
633 spin_lock(&nfsd_drc_lock); 645 spin_lock(&nfsd_drc_lock);
634 nfsd_drc_mem_used -= ses->se_fchannel.maxreqs * NFSD_SLOT_CACHE_SIZE; 646 mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
647 nfsd_drc_mem_used -= mem;
635 spin_unlock(&nfsd_drc_lock); 648 spin_unlock(&nfsd_drc_lock);
636 free_session_slots(ses); 649 free_session_slots(ses);
637 kfree(ses); 650 kfree(ses);
@@ -2404,11 +2417,8 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
2404 2417
2405 memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid)); 2418 memcpy(&open->op_delegate_stateid, &dp->dl_stateid, sizeof(dp->dl_stateid));
2406 2419
2407 dprintk("NFSD: delegation stateid=(%08x/%08x/%08x/%08x)\n\n", 2420 dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
2408 dp->dl_stateid.si_boot, 2421 STATEID_VAL(&dp->dl_stateid));
2409 dp->dl_stateid.si_stateownerid,
2410 dp->dl_stateid.si_fileid,
2411 dp->dl_stateid.si_generation);
2412out: 2422out:
2413 if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS 2423 if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
2414 && flag == NFS4_OPEN_DELEGATE_NONE 2424 && flag == NFS4_OPEN_DELEGATE_NONE
@@ -2498,9 +2508,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
2498 2508
2499 status = nfs_ok; 2509 status = nfs_ok;
2500 2510
2501 dprintk("nfs4_process_open2: stateid=(%08x/%08x/%08x/%08x)\n", 2511 dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
2502 stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid, 2512 STATEID_VAL(&stp->st_stateid));
2503 stp->st_stateid.si_fileid, stp->st_stateid.si_generation);
2504out: 2513out:
2505 if (fp) 2514 if (fp)
2506 put_nfs4_file(fp); 2515 put_nfs4_file(fp);
@@ -2666,9 +2675,8 @@ STALE_STATEID(stateid_t *stateid)
2666{ 2675{
2667 if (time_after((unsigned long)boot_time, 2676 if (time_after((unsigned long)boot_time,
2668 (unsigned long)stateid->si_boot)) { 2677 (unsigned long)stateid->si_boot)) {
2669 dprintk("NFSD: stale stateid (%08x/%08x/%08x/%08x)!\n", 2678 dprintk("NFSD: stale stateid " STATEID_FMT "!\n",
2670 stateid->si_boot, stateid->si_stateownerid, 2679 STATEID_VAL(stateid));
2671 stateid->si_fileid, stateid->si_generation);
2672 return 1; 2680 return 1;
2673 } 2681 }
2674 return 0; 2682 return 0;
@@ -2680,9 +2688,8 @@ EXPIRED_STATEID(stateid_t *stateid)
2680 if (time_before((unsigned long)boot_time, 2688 if (time_before((unsigned long)boot_time,
2681 ((unsigned long)stateid->si_boot)) && 2689 ((unsigned long)stateid->si_boot)) &&
2682 time_before((unsigned long)(stateid->si_boot + lease_time), get_seconds())) { 2690 time_before((unsigned long)(stateid->si_boot + lease_time), get_seconds())) {
2683 dprintk("NFSD: expired stateid (%08x/%08x/%08x/%08x)!\n", 2691 dprintk("NFSD: expired stateid " STATEID_FMT "!\n",
2684 stateid->si_boot, stateid->si_stateownerid, 2692 STATEID_VAL(stateid));
2685 stateid->si_fileid, stateid->si_generation);
2686 return 1; 2693 return 1;
2687 } 2694 }
2688 return 0; 2695 return 0;
@@ -2696,9 +2703,8 @@ stateid_error_map(stateid_t *stateid)
2696 if (EXPIRED_STATEID(stateid)) 2703 if (EXPIRED_STATEID(stateid))
2697 return nfserr_expired; 2704 return nfserr_expired;
2698 2705
2699 dprintk("NFSD: bad stateid (%08x/%08x/%08x/%08x)!\n", 2706 dprintk("NFSD: bad stateid " STATEID_FMT "!\n",
2700 stateid->si_boot, stateid->si_stateownerid, 2707 STATEID_VAL(stateid));
2701 stateid->si_fileid, stateid->si_generation);
2702 return nfserr_bad_stateid; 2708 return nfserr_bad_stateid;
2703} 2709}
2704 2710
@@ -2884,10 +2890,8 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
2884 struct svc_fh *current_fh = &cstate->current_fh; 2890 struct svc_fh *current_fh = &cstate->current_fh;
2885 __be32 status; 2891 __be32 status;
2886 2892
2887 dprintk("NFSD: preprocess_seqid_op: seqid=%d " 2893 dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
2888 "stateid = (%08x/%08x/%08x/%08x)\n", seqid, 2894 seqid, STATEID_VAL(stateid));
2889 stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
2890 stateid->si_generation);
2891 2895
2892 *stpp = NULL; 2896 *stpp = NULL;
2893 *sopp = NULL; 2897 *sopp = NULL;
@@ -3019,12 +3023,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3019 sop->so_confirmed = 1; 3023 sop->so_confirmed = 1;
3020 update_stateid(&stp->st_stateid); 3024 update_stateid(&stp->st_stateid);
3021 memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t)); 3025 memcpy(&oc->oc_resp_stateid, &stp->st_stateid, sizeof(stateid_t));
3022 dprintk("NFSD: nfsd4_open_confirm: success, seqid=%d " 3026 dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
3023 "stateid=(%08x/%08x/%08x/%08x)\n", oc->oc_seqid, 3027 __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stateid));
3024 stp->st_stateid.si_boot,
3025 stp->st_stateid.si_stateownerid,
3026 stp->st_stateid.si_fileid,
3027 stp->st_stateid.si_generation);
3028 3028
3029 nfsd4_create_clid_dir(sop->so_client); 3029 nfsd4_create_clid_dir(sop->so_client);
3030out: 3030out:
@@ -3283,9 +3283,8 @@ find_delegation_stateid(struct inode *ino, stateid_t *stid)
3283 struct nfs4_file *fp; 3283 struct nfs4_file *fp;
3284 struct nfs4_delegation *dl; 3284 struct nfs4_delegation *dl;
3285 3285
3286 dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n", 3286 dprintk("NFSD: %s: stateid=" STATEID_FMT "\n", __func__,
3287 stid->si_boot, stid->si_stateownerid, 3287 STATEID_VAL(stid));
3288 stid->si_fileid, stid->si_generation);
3289 3288
3290 fp = find_file(ino); 3289 fp = find_file(ino);
3291 if (!fp) 3290 if (!fp)
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 0fbd50cee1f6..db0fc55670b3 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -57,6 +57,7 @@
57#include <linux/nfs4_acl.h> 57#include <linux/nfs4_acl.h>
58#include <linux/sunrpc/gss_api.h> 58#include <linux/sunrpc/gss_api.h>
59#include <linux/sunrpc/svcauth_gss.h> 59#include <linux/sunrpc/svcauth_gss.h>
60#include "vfs.h"
60 61
61#define NFSDDBG_FACILITY NFSDDBG_XDR 62#define NFSDDBG_FACILITY NFSDDBG_XDR
62 63
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 01965b2f3a76..d0d8a217a3ea 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -22,6 +22,7 @@
22#include <linux/sunrpc/svc.h> 22#include <linux/sunrpc/svc.h>
23#include <linux/sunrpc/svcauth_gss.h> 23#include <linux/sunrpc/svcauth_gss.h>
24#include <linux/nfsd/nfsd.h> 24#include <linux/nfsd/nfsd.h>
25#include "vfs.h"
25#include "auth.h" 26#include "auth.h"
26 27
27#define NFSDDBG_FACILITY NFSDDBG_FH 28#define NFSDDBG_FACILITY NFSDDBG_FH
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 0eb9c820b7a6..6c967e1ba37b 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -24,6 +24,7 @@
24#include <linux/nfsd/nfsd.h> 24#include <linux/nfsd/nfsd.h>
25#include <linux/nfsd/cache.h> 25#include <linux/nfsd/cache.h>
26#include <linux/nfsd/xdr.h> 26#include <linux/nfsd/xdr.h>
27#include "vfs.h"
27 28
28typedef struct svc_rqst svc_rqst; 29typedef struct svc_rqst svc_rqst;
29typedef struct svc_buf svc_buf; 30typedef struct svc_buf svc_buf;
@@ -758,6 +759,7 @@ nfserrno (int errno)
758 { nfserr_io, -ETXTBSY }, 759 { nfserr_io, -ETXTBSY },
759 { nfserr_notsupp, -EOPNOTSUPP }, 760 { nfserr_notsupp, -EOPNOTSUPP },
760 { nfserr_toosmall, -ETOOSMALL }, 761 { nfserr_toosmall, -ETOOSMALL },
762 { nfserr_serverfault, -ESERVERFAULT },
761 }; 763 };
762 int i; 764 int i;
763 765
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 67ea83eedd43..2944b31dcbe6 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -35,6 +35,7 @@
35#include <linux/lockd/bind.h> 35#include <linux/lockd/bind.h>
36#include <linux/nfsacl.h> 36#include <linux/nfsacl.h>
37#include <linux/seq_file.h> 37#include <linux/seq_file.h>
38#include "vfs.h"
38 39
39#define NFSDDBG_FACILITY NFSDDBG_SVC 40#define NFSDDBG_FACILITY NFSDDBG_SVC
40 41
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index a293f0273263..a7038ede671a 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -56,6 +56,7 @@
56#endif /* CONFIG_NFSD_V4 */ 56#endif /* CONFIG_NFSD_V4 */
57#include <linux/jhash.h> 57#include <linux/jhash.h>
58#include <linux/ima.h> 58#include <linux/ima.h>
59#include "vfs.h"
59 60
60#include <asm/uaccess.h> 61#include <asm/uaccess.h>
61 62
@@ -141,6 +142,40 @@ out:
141 return err; 142 return err;
142} 143}
143 144
145static void follow_to_parent(struct path *path)
146{
147 struct dentry *dp;
148
149 while (path->dentry == path->mnt->mnt_root && follow_up(path))
150 ;
151 dp = dget_parent(path->dentry);
152 dput(path->dentry);
153 path->dentry = dp;
154}
155
156static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct dentry *dparent, struct svc_export **exp, struct dentry **dentryp)
157{
158 struct svc_export *exp2;
159 struct path path = {.mnt = mntget((*exp)->ex_path.mnt),
160 .dentry = dget(dparent)};
161
162 follow_to_parent(&path);
163
164 exp2 = rqst_exp_parent(rqstp, &path);
165 if (PTR_ERR(exp2) == -ENOENT) {
166 *dentryp = dget(dparent);
167 } else if (IS_ERR(exp2)) {
168 path_put(&path);
169 return PTR_ERR(exp2);
170 } else {
171 *dentryp = dget(path.dentry);
172 exp_put(*exp);
173 *exp = exp2;
174 }
175 path_put(&path);
176 return 0;
177}
178
144__be32 179__be32
145nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, 180nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
146 const char *name, unsigned int len, 181 const char *name, unsigned int len,
@@ -169,35 +204,13 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
169 dentry = dget(dparent); 204 dentry = dget(dparent);
170 else if (dparent != exp->ex_path.dentry) 205 else if (dparent != exp->ex_path.dentry)
171 dentry = dget_parent(dparent); 206 dentry = dget_parent(dparent);
172 else if (!EX_NOHIDE(exp)) 207 else if (!EX_NOHIDE(exp) && !nfsd_v4client(rqstp))
173 dentry = dget(dparent); /* .. == . just like at / */ 208 dentry = dget(dparent); /* .. == . just like at / */
174 else { 209 else {
175 /* checking mountpoint crossing is very different when stepping up */ 210 /* checking mountpoint crossing is very different when stepping up */
176 struct svc_export *exp2 = NULL; 211 host_err = nfsd_lookup_parent(rqstp, dparent, &exp, &dentry);
177 struct dentry *dp; 212 if (host_err)
178 struct path path = {.mnt = mntget(exp->ex_path.mnt),
179 .dentry = dget(dparent)};
180
181 while (path.dentry == path.mnt->mnt_root &&
182 follow_up(&path))
183 ;
184 dp = dget_parent(path.dentry);
185 dput(path.dentry);
186 path.dentry = dp;
187
188 exp2 = rqst_exp_parent(rqstp, &path);
189 if (PTR_ERR(exp2) == -ENOENT) {
190 dentry = dget(dparent);
191 } else if (IS_ERR(exp2)) {
192 host_err = PTR_ERR(exp2);
193 path_put(&path);
194 goto out_nfserr; 213 goto out_nfserr;
195 } else {
196 dentry = dget(path.dentry);
197 exp_put(exp);
198 exp = exp2;
199 }
200 path_put(&path);
201 } 214 }
202 } else { 215 } else {
203 fh_lock(fhp); 216 fh_lock(fhp);
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
new file mode 100644
index 000000000000..b8011fd2fcab
--- /dev/null
+++ b/fs/nfsd/vfs.h
@@ -0,0 +1,98 @@
1/*
2 * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
3 */
4
5#ifndef LINUX_NFSD_VFS_H
6#define LINUX_NFSD_VFS_H
7
8/*
9 * Flags for nfsd_permission
10 */
11#define NFSD_MAY_NOP 0
12#define NFSD_MAY_EXEC 1 /* == MAY_EXEC */
13#define NFSD_MAY_WRITE 2 /* == MAY_WRITE */
14#define NFSD_MAY_READ 4 /* == MAY_READ */
15#define NFSD_MAY_SATTR 8
16#define NFSD_MAY_TRUNC 16
17#define NFSD_MAY_LOCK 32
18#define NFSD_MAY_OWNER_OVERRIDE 64
19#define NFSD_MAY_LOCAL_ACCESS 128 /* IRIX doing local access check on device special file*/
20#define NFSD_MAY_BYPASS_GSS_ON_ROOT 256
21
22#define NFSD_MAY_CREATE (NFSD_MAY_EXEC|NFSD_MAY_WRITE)
23#define NFSD_MAY_REMOVE (NFSD_MAY_EXEC|NFSD_MAY_WRITE|NFSD_MAY_TRUNC)
24
25/*
26 * Callback function for readdir
27 */
28typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
29
30/* nfsd/vfs.c */
31int fh_lock_parent(struct svc_fh *, struct dentry *);
32int nfsd_racache_init(int);
33void nfsd_racache_shutdown(void);
34int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
35 struct svc_export **expp);
36__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
37 const char *, unsigned int, struct svc_fh *);
38__be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *,
39 const char *, unsigned int,
40 struct svc_export **, struct dentry **);
41__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
42 struct iattr *, int, time_t);
43#ifdef CONFIG_NFSD_V4
44__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
45 struct nfs4_acl *);
46int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
47#endif /* CONFIG_NFSD_V4 */
48__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
49 char *name, int len, struct iattr *attrs,
50 int type, dev_t rdev, struct svc_fh *res);
51#ifdef CONFIG_NFSD_V3
52__be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
53__be32 nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
54 char *name, int len, struct iattr *attrs,
55 struct svc_fh *res, int createmode,
56 u32 *verifier, int *truncp, int *created);
57__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
58 loff_t, unsigned long);
59#endif /* CONFIG_NFSD_V3 */
60__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int,
61 int, struct file **);
62void nfsd_close(struct file *);
63__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
64 loff_t, struct kvec *, int, unsigned long *);
65__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
66 loff_t, struct kvec *,int, unsigned long *, int *);
67__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
68 char *, int *);
69__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
70 char *name, int len, char *path, int plen,
71 struct svc_fh *res, struct iattr *);
72__be32 nfsd_link(struct svc_rqst *, struct svc_fh *,
73 char *, int, struct svc_fh *);
74__be32 nfsd_rename(struct svc_rqst *,
75 struct svc_fh *, char *, int,
76 struct svc_fh *, char *, int);
77__be32 nfsd_remove(struct svc_rqst *,
78 struct svc_fh *, char *, int);
79__be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
80 char *name, int len);
81int nfsd_truncate(struct svc_rqst *, struct svc_fh *,
82 unsigned long size);
83__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
84 loff_t *, struct readdir_cd *, filldir_t);
85__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
86 struct kstatfs *, int access);
87
88int nfsd_notify_change(struct inode *, struct iattr *);
89__be32 nfsd_permission(struct svc_rqst *, struct svc_export *,
90 struct dentry *, int);
91int nfsd_sync_dir(struct dentry *dp);
92
93#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
94struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
95int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
96#endif
97
98#endif /* LINUX_NFSD_VFS_H */