knfsd: move EX_RDONLY out of header
[safe/jmp/linux-2.6] / fs / nfsd / vfs.c
index 65043af..f2684e5 100644 (file)
@@ -120,14 +120,14 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
                mntput(mnt);
                goto out;
        }
-       if (exp2 && ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2))) {
+       if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
                /* successfully crossed mount point */
                exp_put(exp);
                *expp = exp2;
                dput(dentry);
                *dpp = mounts;
        } else {
-               if (exp2) exp_put(exp2);
+               exp_put(exp2);
                dput(mounts);
        }
        mntput(mnt);
@@ -135,21 +135,10 @@ out:
        return err;
 }
 
-/*
- * Look up one component of a pathname.
- * N.B. After this call _both_ fhp and resfh need an fh_put
- *
- * If the lookup would cross a mountpoint, and the mounted filesystem
- * is exported to the client with NFSEXP_NOHIDE, then the lookup is
- * accepted as it stands and the mounted directory is
- * returned. Otherwise the covered directory is returned.
- * NOTE: this mountpoint crossing is not supported properly by all
- *   clients and is explicitly disallowed for NFSv3
- *      NeilBrown <neilb@cse.unsw.edu.au>
- */
 __be32
-nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
-                                       int len, struct svc_fh *resfh)
+nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
+                  const char *name, int len,
+                  struct svc_export **exp_ret, struct dentry **dentry_ret)
 {
        struct svc_export       *exp;
        struct dentry           *dparent;
@@ -219,6 +208,41 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
                        }
                }
        }
+       *dentry_ret = dentry;
+       *exp_ret = exp;
+       return 0;
+
+out_nfserr:
+       exp_put(exp);
+       return nfserrno(host_err);
+}
+
+/*
+ * Look up one component of a pathname.
+ * N.B. After this call _both_ fhp and resfh need an fh_put
+ *
+ * If the lookup would cross a mountpoint, and the mounted filesystem
+ * is exported to the client with NFSEXP_NOHIDE, then the lookup is
+ * accepted as it stands and the mounted directory is
+ * returned. Otherwise the covered directory is returned.
+ * NOTE: this mountpoint crossing is not supported properly by all
+ *   clients and is explicitly disallowed for NFSv3
+ *      NeilBrown <neilb@cse.unsw.edu.au>
+ */
+__be32
+nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
+                                       int len, struct svc_fh *resfh)
+{
+       struct svc_export       *exp;
+       struct dentry           *dentry;
+       __be32 err;
+
+       err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
+       if (err)
+               return err;
+       err = check_nfsd_access(exp, rqstp);
+       if (err)
+               goto out;
        /*
         * Note: we compose the file handle now, but as the
         * dentry may be negative, it may need to be updated.
@@ -226,16 +250,13 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
        err = fh_compose(resfh, exp, dentry, fhp);
        if (!err && !dentry->d_inode)
                err = nfserr_noent;
-       dput(dentry);
 out:
+       dput(dentry);
        exp_put(exp);
        return err;
-
-out_nfserr:
-       err = nfserrno(host_err);
-       goto out;
 }
 
+
 /*
  * Set various file attributes.
  * N.B. After this call fhp needs an fh_put
@@ -307,7 +328,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        /* The size case is special. It changes the file as well as the attributes.  */
        if (iap->ia_valid & ATTR_SIZE) {
                if (iap->ia_size < inode->i_size) {
-                       err = nfsd_permission(fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
+                       err = nfsd_permission(rqstp, fhp->fh_export, dentry, MAY_TRUNC|MAY_OWNER_OVERRIDE);
                        if (err)
                                goto out;
                }
@@ -595,7 +616,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
 
                        sresult |= map->access;
 
-                       err2 = nfsd_permission(export, dentry, map->how);
+                       err2 = nfsd_permission(rqstp, export, dentry, map->how);
                        switch (err2) {
                        case nfs_ok:
                                result |= map->access;
@@ -1022,7 +1043,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        __be32          err;
 
        if (file) {
-               err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+               err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
                                MAY_READ|MAY_OWNER_OVERRIDE);
                if (err)
                        goto out;
@@ -1051,7 +1072,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
        __be32                  err = 0;
 
        if (file) {
-               err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
+               err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry,
                                MAY_WRITE|MAY_OWNER_OVERRIDE);
                if (err)
                        goto out;
@@ -1776,11 +1797,24 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
        return err;
 }
 
+static inline int EX_RDONLY(struct svc_export *exp, struct svc_rqst *rqstp)
+{
+       struct exp_flavor_info *f;
+       struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
+
+       for (f = exp->ex_flavors; f < end; f++) {
+               if (f->pseudoflavor == rqstp->rq_flavor)
+                       return f->flags & NFSEXP_READONLY;
+       }
+       return exp->ex_flags & NFSEXP_READONLY;
+}
+
 /*
  * Check for a user's access permissions to this inode.
  */
 __be32
-nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
+nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
+                                       struct dentry *dentry, int acc)
 {
        struct inode    *inode = dentry->d_inode;
        int             err;
@@ -1811,7 +1845,7 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
         */
        if (!(acc & MAY_LOCAL_ACCESS))
                if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
-                       if (EX_RDONLY(exp) || IS_RDONLY(inode))
+                       if (EX_RDONLY(exp, rqstp) || IS_RDONLY(inode))
                                return nfserr_rofs;
                        if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
                                return nfserr_perm;
@@ -1894,7 +1928,7 @@ nfsd_racache_init(int cache_size)
                raparm_hash[i].pb_head = NULL;
                spin_lock_init(&raparm_hash[i].pb_lock);
        }
-       nperbucket = cache_size >> RAPARM_HASH_BITS;
+       nperbucket = DIV_ROUND_UP(cache_size, RAPARM_HASH_SIZE);
        for (i = 0; i < cache_size - 1; i++) {
                if (i % nperbucket == 0)
                        raparm_hash[j++].pb_head = raparml + i;