Pull ia64-clocksource into release branch
[pandora-kernel.git] / fs / nfsd / vfs.c
index 945b1ce..ee96a89 100644 (file)
@@ -113,21 +113,21 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
 
        while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));
 
-       exp2 = exp_get_by_name(exp->ex_client, mnt, mounts, &rqstp->rq_chandle);
+       exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts);
        if (IS_ERR(exp2)) {
                err = PTR_ERR(exp2);
                dput(mounts);
                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;
@@ -168,8 +157,6 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
        exp  = fhp->fh_export;
        exp_get(exp);
 
-       err = nfserr_acces;
-
        /* Lookup the name, but don't follow links */
        if (isdotent(name, len)) {
                if (len==1)
@@ -190,17 +177,15 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
                        dput(dentry);
                        dentry = dp;
 
-                       exp2 = exp_parent(exp->ex_client, mnt, dentry,
-                                         &rqstp->rq_chandle);
-                       if (IS_ERR(exp2)) {
+                       exp2 = rqst_exp_parent(rqstp, mnt, dentry);
+                       if (PTR_ERR(exp2) == -ENOENT) {
+                               dput(dentry);
+                               dentry = dget(dparent);
+                       } else if (IS_ERR(exp2)) {
                                host_err = PTR_ERR(exp2);
                                dput(dentry);
                                mntput(mnt);
                                goto out_nfserr;
-                       }
-                       if (!exp2) {
-                               dput(dentry);
-                               dentry = dget(dparent);
                        } else {
                                exp_put(exp);
                                exp = exp2;
@@ -223,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.
@@ -230,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
@@ -311,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;
                }
@@ -435,7 +452,7 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
        /* Get inode */
        error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
        if (error)
-               goto out;
+               return error;
 
        dentry = fhp->fh_dentry;
        inode = dentry->d_inode;
@@ -444,33 +461,25 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
 
        host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
        if (host_error == -EINVAL) {
-               error = nfserr_attrnotsupp;
-               goto out;
+               return nfserr_attrnotsupp;
        } else if (host_error < 0)
                goto out_nfserr;
 
        host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
        if (host_error < 0)
-               goto out_nfserr;
+               goto out_release;
 
-       if (S_ISDIR(inode->i_mode)) {
+       if (S_ISDIR(inode->i_mode))
                host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
-               if (host_error < 0)
-                       goto out_nfserr;
-       }
 
-       error = nfs_ok;
-
-out:
+out_release:
        posix_acl_release(pacl);
        posix_acl_release(dpacl);
-       return (error);
 out_nfserr:
        if (host_error == -EOPNOTSUPP)
-               error = nfserr_attrnotsupp;
+               return nfserr_attrnotsupp;
        else
-               error = nfserrno(host_error);
-       goto out;
+               return nfserrno(host_error);
 }
 
 static struct posix_acl *
@@ -607,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;
@@ -1034,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;
@@ -1063,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;
@@ -1788,11 +1797,17 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
        return err;
 }
 
+static int exp_rdonly(struct svc_rqst *rqstp, struct svc_export *exp)
+{
+       return nfsexp_flags(rqstp, exp) & 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;
@@ -1823,7 +1838,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 (exp_rdonly(rqstp, exp) || IS_RDONLY(inode))
                                return nfserr_rofs;
                        if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
                                return nfserr_perm;
@@ -1906,7 +1921,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;