[PATCH] r/o bind mounts: write counts for link/symlink
[firefly-linux-kernel-4.4.55.git] / fs / nfsd / vfs.c
index 46f59d5365a0d49986512c54a25ecdc6daeb54f1..71f8994823060df7bc933627e9c1807c90319c03 100644 (file)
@@ -1255,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));
@@ -1282,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.
         */
@@ -1359,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;
 
@@ -1390,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;
 
@@ -1420,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.
         */
@@ -1522,6 +1542,10 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
        if (iap && (iap->ia_valid & ATTR_MODE))
                mode = iap->ia_mode & S_IALLUGO;
 
+       host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
+       if (host_err)
+               goto out_nfserr;
+
        if (unlikely(path[plen] != 0)) {
                char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
                if (path_alloced == NULL)
@@ -1542,6 +1566,8 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
        err = nfserrno(host_err);
        fh_unlock(fhp);
 
+       mnt_drop_write(fhp->fh_export->ex_path.mnt);
+
        cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
        dput(dnew);
        if (err==0) err = cerr;
@@ -1592,6 +1618,11 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
        dold = tfhp->fh_dentry;
        dest = dold->d_inode;
 
+       host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt);
+       if (host_err) {
+               err = nfserrno(host_err);
+               goto out_dput;
+       }
        host_err = vfs_link(dold, dirp, dnew);
        if (!host_err) {
                if (EX_ISSYNC(ffhp->fh_export)) {
@@ -1605,7 +1636,8 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
                else
                        err = nfserrno(host_err);
        }
-
+       mnt_drop_write(tfhp->fh_export->ex_path.mnt);
+out_dput:
        dput(dnew);
 out_unlock:
        fh_unlock(ffhp);
@@ -1750,6 +1782,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) &&
@@ -1765,10 +1801,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: