]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/nfsd/vfs.c
[PATCH] r/o bind mounts: get callers of vfs_mknod/create/mkdir()
[linux-2.6-omap-h63xx.git] / fs / nfsd / vfs.c
index cc75e4fcd02baf2a989573ac5aac2e16dad8df17..14d582467029a39bd83cf1cc9c93d55a14edc955 100644 (file)
@@ -101,7 +101,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
 {
        struct svc_export *exp = *expp, *exp2 = NULL;
        struct dentry *dentry = *dpp;
-       struct vfsmount *mnt = mntget(exp->ex_mnt);
+       struct vfsmount *mnt = mntget(exp->ex_path.mnt);
        struct dentry *mounts = dget(dentry);
        int err = 0;
 
@@ -156,15 +156,15 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (isdotent(name, len)) {
                if (len==1)
                        dentry = dget(dparent);
-               else if (dparent != exp->ex_dentry) {
+               else if (dparent != exp->ex_path.dentry)
                        dentry = dget_parent(dparent);
-               } else  if (!EX_NOHIDE(exp))
+               else if (!EX_NOHIDE(exp))
                        dentry = dget(dparent); /* .. == . just like at / */
                else {
                        /* checking mountpoint crossing is very different when stepping up */
                        struct svc_export *exp2 = NULL;
                        struct dentry *dp;
-                       struct vfsmount *mnt = mntget(exp->ex_mnt);
+                       struct vfsmount *mnt = mntget(exp->ex_path.mnt);
                        dentry = dget(dparent);
                        while(dentry == mnt->mnt_root && follow_up(&mnt, &dentry))
                                ;
@@ -721,7 +721,8 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
 
                DQUOT_INIT(inode);
        }
-       *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags);
+       *filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_path.mnt),
+                               flags);
        if (IS_ERR(*filp))
                host_err = PTR_ERR(*filp);
 out_nfserr:
@@ -1254,23 +1255,35 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        err = 0;
        switch (type) {
        case S_IFREG:
+               host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
+               if (host_err)
+                       goto out_nfserr;
                host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
                break;
        case S_IFDIR:
+               host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
+               if (host_err)
+                       goto out_nfserr;
                host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
                break;
        case S_IFCHR:
        case S_IFBLK:
        case S_IFIFO:
        case S_IFSOCK:
+               host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
+               if (host_err)
+                       goto out_nfserr;
                host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
                break;
        default:
                printk("nfsd: bad file type %o in nfsd_create\n", type);
                host_err = -EINVAL;
+               goto out_nfserr;
        }
-       if (host_err < 0)
+       if (host_err < 0) {
+               mnt_drop_write(fhp->fh_export->ex_path.mnt);
                goto out_nfserr;
+       }
 
        if (EX_ISSYNC(fhp->fh_export)) {
                err = nfserrno(nfsd_sync_dir(dentry));
@@ -1281,6 +1294,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
        err2 = nfsd_create_setattr(rqstp, resfhp, iap);
        if (err2)
                err = err2;
+       mnt_drop_write(fhp->fh_export->ex_path.mnt);
        /*
         * Update the file handle to get the new inode info.
         */
@@ -1358,6 +1372,9 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
                v_atime = verifier[1]&0x7fffffff;
        }
        
+       host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
+       if (host_err)
+               goto out_nfserr;
        if (dchild->d_inode) {
                err = 0;
 
@@ -1389,12 +1406,15 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
                case NFS3_CREATE_GUARDED:
                        err = nfserr_exist;
                }
+               mnt_drop_write(fhp->fh_export->ex_path.mnt);
                goto out;
        }
 
        host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
-       if (host_err < 0)
+       if (host_err < 0) {
+               mnt_drop_write(fhp->fh_export->ex_path.mnt);
                goto out_nfserr;
+       }
        if (created)
                *created = 1;
 
@@ -1419,6 +1439,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (err2)
                err = err2;
 
+       mnt_drop_write(fhp->fh_export->ex_path.mnt);
        /*
         * Update the filehandle to get the new inode info.
         */
@@ -1462,7 +1483,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
        if (!inode->i_op || !inode->i_op->readlink)
                goto out;
 
-       touch_atime(fhp->fh_export->ex_mnt, dentry);
+       touch_atime(fhp->fh_export->ex_path.mnt, dentry);
        /* N.B. Why does this call need a get_fs()??
         * Remove the set_fs and watch the fireworks:-) --okir
         */
@@ -1749,6 +1770,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        if (!type)
                type = rdentry->d_inode->i_mode & S_IFMT;
 
+       host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
+       if (host_err)
+               goto out_nfserr;
+
        if (type != S_IFDIR) { /* It's UNLINK */
 #ifdef MSNFS
                if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
@@ -1764,10 +1789,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        dput(rdentry);
 
        if (host_err)
-               goto out_nfserr;
+               goto out_drop;
        if (EX_ISSYNC(fhp->fh_export))
                host_err = nfsd_sync_dir(dentry);
 
+out_drop:
+       mnt_drop_write(fhp->fh_export->ex_path.mnt);
 out_nfserr:
        err = nfserrno(host_err);
 out: