diff options
| author | Jan Kara <jack@suse.cz> | 2012-06-12 10:20:33 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-30 17:02:51 -0400 |
| commit | 4a55c1017b8dcfd0554734ce3f19374d5b522d59 (patch) | |
| tree | 11bb9456d121ff1cc0adad10da12b25083823a19 /fs | |
| parent | e7848683ae7ded0a4a8964122a47da9104a98337 (diff) | |
nfsd: Push mnt_want_write() outside of i_mutex
When mnt_want_write() starts to handle freezing it will get a full lock
semantics requiring proper lock ordering. So push mnt_want_write() call
consistently outside of i_mutex.
CC: linux-nfs@vger.kernel.org
CC: "J. Bruce Fields" <bfields@fieldses.org>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/nfsd/nfs4recover.c | 9 | ||||
| -rw-r--r-- | fs/nfsd/nfsfh.c | 1 | ||||
| -rw-r--r-- | fs/nfsd/nfsproc.c | 9 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 79 | ||||
| -rw-r--r-- | fs/nfsd/vfs.h | 11 |
5 files changed, 63 insertions, 46 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 5ff0b7b9fc08..43295d45cc2b 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
| @@ -154,6 +154,10 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) | |||
| 154 | if (status < 0) | 154 | if (status < 0) |
| 155 | return; | 155 | return; |
| 156 | 156 | ||
| 157 | status = mnt_want_write_file(rec_file); | ||
| 158 | if (status) | ||
| 159 | return; | ||
| 160 | |||
| 157 | dir = rec_file->f_path.dentry; | 161 | dir = rec_file->f_path.dentry; |
| 158 | /* lock the parent */ | 162 | /* lock the parent */ |
| 159 | mutex_lock(&dir->d_inode->i_mutex); | 163 | mutex_lock(&dir->d_inode->i_mutex); |
| @@ -173,11 +177,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp) | |||
| 173 | * as well be forgiving and just succeed silently. | 177 | * as well be forgiving and just succeed silently. |
| 174 | */ | 178 | */ |
| 175 | goto out_put; | 179 | goto out_put; |
| 176 | status = mnt_want_write_file(rec_file); | ||
| 177 | if (status) | ||
| 178 | goto out_put; | ||
| 179 | status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU); | 180 | status = vfs_mkdir(dir->d_inode, dentry, S_IRWXU); |
| 180 | mnt_drop_write_file(rec_file); | ||
| 181 | out_put: | 181 | out_put: |
| 182 | dput(dentry); | 182 | dput(dentry); |
| 183 | out_unlock: | 183 | out_unlock: |
| @@ -189,6 +189,7 @@ out_unlock: | |||
| 189 | " (err %d); please check that %s exists" | 189 | " (err %d); please check that %s exists" |
| 190 | " and is writeable", status, | 190 | " and is writeable", status, |
| 191 | user_recovery_dirname); | 191 | user_recovery_dirname); |
| 192 | mnt_drop_write_file(rec_file); | ||
| 192 | nfs4_reset_creds(original_cred); | 193 | nfs4_reset_creds(original_cred); |
| 193 | } | 194 | } |
| 194 | 195 | ||
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index cc793005a87c..032af381b3aa 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
| @@ -635,6 +635,7 @@ fh_put(struct svc_fh *fhp) | |||
| 635 | fhp->fh_post_saved = 0; | 635 | fhp->fh_post_saved = 0; |
| 636 | #endif | 636 | #endif |
| 637 | } | 637 | } |
| 638 | fh_drop_write(fhp); | ||
| 638 | if (exp) { | 639 | if (exp) { |
| 639 | exp_put(exp); | 640 | exp_put(exp); |
| 640 | fhp->fh_export = NULL; | 641 | fhp->fh_export = NULL; |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index e15dc45fc5ec..aad6d457b9e8 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
| @@ -196,6 +196,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, | |||
| 196 | struct dentry *dchild; | 196 | struct dentry *dchild; |
| 197 | int type, mode; | 197 | int type, mode; |
| 198 | __be32 nfserr; | 198 | __be32 nfserr; |
| 199 | int hosterr; | ||
| 199 | dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size); | 200 | dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size); |
| 200 | 201 | ||
| 201 | dprintk("nfsd: CREATE %s %.*s\n", | 202 | dprintk("nfsd: CREATE %s %.*s\n", |
| @@ -214,6 +215,12 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, | |||
| 214 | nfserr = nfserr_exist; | 215 | nfserr = nfserr_exist; |
| 215 | if (isdotent(argp->name, argp->len)) | 216 | if (isdotent(argp->name, argp->len)) |
| 216 | goto done; | 217 | goto done; |
| 218 | hosterr = fh_want_write(dirfhp); | ||
| 219 | if (hosterr) { | ||
| 220 | nfserr = nfserrno(hosterr); | ||
| 221 | goto done; | ||
| 222 | } | ||
| 223 | |||
| 217 | fh_lock_nested(dirfhp, I_MUTEX_PARENT); | 224 | fh_lock_nested(dirfhp, I_MUTEX_PARENT); |
| 218 | dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); | 225 | dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); |
| 219 | if (IS_ERR(dchild)) { | 226 | if (IS_ERR(dchild)) { |
| @@ -330,7 +337,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp, | |||
| 330 | out_unlock: | 337 | out_unlock: |
| 331 | /* We don't really need to unlock, as fh_put does it. */ | 338 | /* We don't really need to unlock, as fh_put does it. */ |
| 332 | fh_unlock(dirfhp); | 339 | fh_unlock(dirfhp); |
| 333 | 340 | fh_drop_write(dirfhp); | |
| 334 | done: | 341 | done: |
| 335 | fh_put(dirfhp); | 342 | fh_put(dirfhp); |
| 336 | return nfsd_return_dirop(nfserr, resp); | 343 | return nfsd_return_dirop(nfserr, resp); |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 4700a0a929d7..dccd396a1bb7 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -1276,6 +1276,10 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1276 | * If it has, the parent directory should already be locked. | 1276 | * If it has, the parent directory should already be locked. |
| 1277 | */ | 1277 | */ |
| 1278 | if (!resfhp->fh_dentry) { | 1278 | if (!resfhp->fh_dentry) { |
| 1279 | host_err = fh_want_write(fhp); | ||
| 1280 | if (host_err) | ||
| 1281 | goto out_nfserr; | ||
| 1282 | |||
| 1279 | /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ | 1283 | /* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */ |
| 1280 | fh_lock_nested(fhp, I_MUTEX_PARENT); | 1284 | fh_lock_nested(fhp, I_MUTEX_PARENT); |
| 1281 | dchild = lookup_one_len(fname, dentry, flen); | 1285 | dchild = lookup_one_len(fname, dentry, flen); |
| @@ -1319,14 +1323,11 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1319 | goto out; | 1323 | goto out; |
| 1320 | } | 1324 | } |
| 1321 | 1325 | ||
| 1322 | host_err = fh_want_write(fhp); | ||
| 1323 | if (host_err) | ||
| 1324 | goto out_nfserr; | ||
| 1325 | |||
| 1326 | /* | 1326 | /* |
| 1327 | * Get the dir op function pointer. | 1327 | * Get the dir op function pointer. |
| 1328 | */ | 1328 | */ |
| 1329 | err = 0; | 1329 | err = 0; |
| 1330 | host_err = 0; | ||
| 1330 | switch (type) { | 1331 | switch (type) { |
| 1331 | case S_IFREG: | 1332 | case S_IFREG: |
| 1332 | host_err = vfs_create(dirp, dchild, iap->ia_mode, true); | 1333 | host_err = vfs_create(dirp, dchild, iap->ia_mode, true); |
| @@ -1343,10 +1344,8 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1343 | host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); | 1344 | host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); |
| 1344 | break; | 1345 | break; |
| 1345 | } | 1346 | } |
| 1346 | if (host_err < 0) { | 1347 | if (host_err < 0) |
| 1347 | fh_drop_write(fhp); | ||
| 1348 | goto out_nfserr; | 1348 | goto out_nfserr; |
| 1349 | } | ||
| 1350 | 1349 | ||
| 1351 | err = nfsd_create_setattr(rqstp, resfhp, iap); | 1350 | err = nfsd_create_setattr(rqstp, resfhp, iap); |
| 1352 | 1351 | ||
| @@ -1358,7 +1357,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1358 | err2 = nfserrno(commit_metadata(fhp)); | 1357 | err2 = nfserrno(commit_metadata(fhp)); |
| 1359 | if (err2) | 1358 | if (err2) |
| 1360 | err = err2; | 1359 | err = err2; |
| 1361 | fh_drop_write(fhp); | ||
| 1362 | /* | 1360 | /* |
| 1363 | * Update the file handle to get the new inode info. | 1361 | * Update the file handle to get the new inode info. |
| 1364 | */ | 1362 | */ |
| @@ -1417,6 +1415,11 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1417 | err = nfserr_notdir; | 1415 | err = nfserr_notdir; |
| 1418 | if (!dirp->i_op->lookup) | 1416 | if (!dirp->i_op->lookup) |
| 1419 | goto out; | 1417 | goto out; |
| 1418 | |||
| 1419 | host_err = fh_want_write(fhp); | ||
| 1420 | if (host_err) | ||
| 1421 | goto out_nfserr; | ||
| 1422 | |||
| 1420 | fh_lock_nested(fhp, I_MUTEX_PARENT); | 1423 | fh_lock_nested(fhp, I_MUTEX_PARENT); |
| 1421 | 1424 | ||
| 1422 | /* | 1425 | /* |
| @@ -1449,9 +1452,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1449 | v_atime = verifier[1]&0x7fffffff; | 1452 | v_atime = verifier[1]&0x7fffffff; |
| 1450 | } | 1453 | } |
| 1451 | 1454 | ||
| 1452 | host_err = fh_want_write(fhp); | ||
| 1453 | if (host_err) | ||
| 1454 | goto out_nfserr; | ||
| 1455 | if (dchild->d_inode) { | 1455 | if (dchild->d_inode) { |
| 1456 | err = 0; | 1456 | err = 0; |
| 1457 | 1457 | ||
| @@ -1522,7 +1522,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1522 | if (!err) | 1522 | if (!err) |
| 1523 | err = nfserrno(commit_metadata(fhp)); | 1523 | err = nfserrno(commit_metadata(fhp)); |
| 1524 | 1524 | ||
| 1525 | fh_drop_write(fhp); | ||
| 1526 | /* | 1525 | /* |
| 1527 | * Update the filehandle to get the new inode info. | 1526 | * Update the filehandle to get the new inode info. |
| 1528 | */ | 1527 | */ |
| @@ -1533,6 +1532,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1533 | fh_unlock(fhp); | 1532 | fh_unlock(fhp); |
| 1534 | if (dchild && !IS_ERR(dchild)) | 1533 | if (dchild && !IS_ERR(dchild)) |
| 1535 | dput(dchild); | 1534 | dput(dchild); |
| 1535 | fh_drop_write(fhp); | ||
| 1536 | return err; | 1536 | return err; |
| 1537 | 1537 | ||
| 1538 | out_nfserr: | 1538 | out_nfserr: |
| @@ -1613,6 +1613,11 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1613 | err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); | 1613 | err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); |
| 1614 | if (err) | 1614 | if (err) |
| 1615 | goto out; | 1615 | goto out; |
| 1616 | |||
| 1617 | host_err = fh_want_write(fhp); | ||
| 1618 | if (host_err) | ||
| 1619 | goto out_nfserr; | ||
| 1620 | |||
| 1616 | fh_lock(fhp); | 1621 | fh_lock(fhp); |
| 1617 | dentry = fhp->fh_dentry; | 1622 | dentry = fhp->fh_dentry; |
| 1618 | dnew = lookup_one_len(fname, dentry, flen); | 1623 | dnew = lookup_one_len(fname, dentry, flen); |
| @@ -1620,10 +1625,6 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 1620 | if (IS_ERR(dnew)) | 1625 | if (IS_ERR(dnew)) |
| 1621 | goto out_nfserr; | 1626 | goto out_nfserr; |
| 1622 | 1627 | ||
| 1623 | host_err = fh_want_write(fhp); | ||
| 1624 | if (host_err) | ||
| 1625 | goto out_nfserr; | ||
| 1626 | |||
| 1627 | if (unlikely(path[plen] != 0)) { | 1628 | if (unlikely(path[plen] != 0)) { |
| 1628 | char *path_alloced = kmalloc(plen+1, GFP_KERNEL); | 1629 | char *path_alloced = kmalloc(plen+1, GFP_KERNEL); |
| 1629 | if (path_alloced == NULL) | 1630 | if (path_alloced == NULL) |
| @@ -1683,6 +1684,12 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
| 1683 | if (isdotent(name, len)) | 1684 | if (isdotent(name, len)) |
| 1684 | goto out; | 1685 | goto out; |
| 1685 | 1686 | ||
| 1687 | host_err = fh_want_write(tfhp); | ||
| 1688 | if (host_err) { | ||
| 1689 | err = nfserrno(host_err); | ||
| 1690 | goto out; | ||
| 1691 | } | ||
| 1692 | |||
| 1686 | fh_lock_nested(ffhp, I_MUTEX_PARENT); | 1693 | fh_lock_nested(ffhp, I_MUTEX_PARENT); |
| 1687 | ddir = ffhp->fh_dentry; | 1694 | ddir = ffhp->fh_dentry; |
| 1688 | dirp = ddir->d_inode; | 1695 | dirp = ddir->d_inode; |
| @@ -1694,18 +1701,13 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
| 1694 | 1701 | ||
| 1695 | dold = tfhp->fh_dentry; | 1702 | dold = tfhp->fh_dentry; |
| 1696 | 1703 | ||
| 1697 | host_err = fh_want_write(tfhp); | ||
| 1698 | if (host_err) { | ||
| 1699 | err = nfserrno(host_err); | ||
| 1700 | goto out_dput; | ||
| 1701 | } | ||
| 1702 | err = nfserr_noent; | 1704 | err = nfserr_noent; |
| 1703 | if (!dold->d_inode) | 1705 | if (!dold->d_inode) |
| 1704 | goto out_drop_write; | 1706 | goto out_dput; |
| 1705 | host_err = nfsd_break_lease(dold->d_inode); | 1707 | host_err = nfsd_break_lease(dold->d_inode); |
| 1706 | if (host_err) { | 1708 | if (host_err) { |
| 1707 | err = nfserrno(host_err); | 1709 | err = nfserrno(host_err); |
| 1708 | goto out_drop_write; | 1710 | goto out_dput; |
| 1709 | } | 1711 | } |
| 1710 | host_err = vfs_link(dold, dirp, dnew); | 1712 | host_err = vfs_link(dold, dirp, dnew); |
| 1711 | if (!host_err) { | 1713 | if (!host_err) { |
| @@ -1718,12 +1720,11 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
| 1718 | else | 1720 | else |
| 1719 | err = nfserrno(host_err); | 1721 | err = nfserrno(host_err); |
| 1720 | } | 1722 | } |
| 1721 | out_drop_write: | ||
| 1722 | fh_drop_write(tfhp); | ||
| 1723 | out_dput: | 1723 | out_dput: |
| 1724 | dput(dnew); | 1724 | dput(dnew); |
| 1725 | out_unlock: | 1725 | out_unlock: |
| 1726 | fh_unlock(ffhp); | 1726 | fh_unlock(ffhp); |
| 1727 | fh_drop_write(tfhp); | ||
| 1727 | out: | 1728 | out: |
| 1728 | return err; | 1729 | return err; |
| 1729 | 1730 | ||
| @@ -1766,6 +1767,12 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
| 1766 | if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen)) | 1767 | if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen)) |
| 1767 | goto out; | 1768 | goto out; |
| 1768 | 1769 | ||
| 1770 | host_err = fh_want_write(ffhp); | ||
| 1771 | if (host_err) { | ||
| 1772 | err = nfserrno(host_err); | ||
| 1773 | goto out; | ||
| 1774 | } | ||
| 1775 | |||
| 1769 | /* cannot use fh_lock as we need deadlock protective ordering | 1776 | /* cannot use fh_lock as we need deadlock protective ordering |
| 1770 | * so do it by hand */ | 1777 | * so do it by hand */ |
| 1771 | trap = lock_rename(tdentry, fdentry); | 1778 | trap = lock_rename(tdentry, fdentry); |
| @@ -1796,17 +1803,14 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
| 1796 | host_err = -EXDEV; | 1803 | host_err = -EXDEV; |
| 1797 | if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) | 1804 | if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) |
| 1798 | goto out_dput_new; | 1805 | goto out_dput_new; |
| 1799 | host_err = fh_want_write(ffhp); | ||
| 1800 | if (host_err) | ||
| 1801 | goto out_dput_new; | ||
| 1802 | 1806 | ||
| 1803 | host_err = nfsd_break_lease(odentry->d_inode); | 1807 | host_err = nfsd_break_lease(odentry->d_inode); |
| 1804 | if (host_err) | 1808 | if (host_err) |
| 1805 | goto out_drop_write; | 1809 | goto out_dput_new; |
| 1806 | if (ndentry->d_inode) { | 1810 | if (ndentry->d_inode) { |
| 1807 | host_err = nfsd_break_lease(ndentry->d_inode); | 1811 | host_err = nfsd_break_lease(ndentry->d_inode); |
| 1808 | if (host_err) | 1812 | if (host_err) |
| 1809 | goto out_drop_write; | 1813 | goto out_dput_new; |
| 1810 | } | 1814 | } |
| 1811 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1815 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); |
| 1812 | if (!host_err) { | 1816 | if (!host_err) { |
| @@ -1814,8 +1818,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
| 1814 | if (!host_err) | 1818 | if (!host_err) |
| 1815 | host_err = commit_metadata(ffhp); | 1819 | host_err = commit_metadata(ffhp); |
| 1816 | } | 1820 | } |
| 1817 | out_drop_write: | ||
| 1818 | fh_drop_write(ffhp); | ||
| 1819 | out_dput_new: | 1821 | out_dput_new: |
| 1820 | dput(ndentry); | 1822 | dput(ndentry); |
| 1821 | out_dput_old: | 1823 | out_dput_old: |
| @@ -1831,6 +1833,7 @@ out_drop_write: | |||
| 1831 | fill_post_wcc(tfhp); | 1833 | fill_post_wcc(tfhp); |
| 1832 | unlock_rename(tdentry, fdentry); | 1834 | unlock_rename(tdentry, fdentry); |
| 1833 | ffhp->fh_locked = tfhp->fh_locked = 0; | 1835 | ffhp->fh_locked = tfhp->fh_locked = 0; |
| 1836 | fh_drop_write(ffhp); | ||
| 1834 | 1837 | ||
| 1835 | out: | 1838 | out: |
| 1836 | return err; | 1839 | return err; |
| @@ -1856,6 +1859,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 1856 | if (err) | 1859 | if (err) |
| 1857 | goto out; | 1860 | goto out; |
| 1858 | 1861 | ||
| 1862 | host_err = fh_want_write(fhp); | ||
| 1863 | if (host_err) | ||
| 1864 | goto out_nfserr; | ||
| 1865 | |||
| 1859 | fh_lock_nested(fhp, I_MUTEX_PARENT); | 1866 | fh_lock_nested(fhp, I_MUTEX_PARENT); |
| 1860 | dentry = fhp->fh_dentry; | 1867 | dentry = fhp->fh_dentry; |
| 1861 | dirp = dentry->d_inode; | 1868 | dirp = dentry->d_inode; |
| @@ -1874,21 +1881,15 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
| 1874 | if (!type) | 1881 | if (!type) |
| 1875 | type = rdentry->d_inode->i_mode & S_IFMT; | 1882 | type = rdentry->d_inode->i_mode & S_IFMT; |
| 1876 | 1883 | ||
| 1877 | host_err = fh_want_write(fhp); | ||
| 1878 | if (host_err) | ||
| 1879 | goto out_put; | ||
| 1880 | |||
| 1881 | host_err = nfsd_break_lease(rdentry->d_inode); | 1884 | host_err = nfsd_break_lease(rdentry->d_inode); |
| 1882 | if (host_err) | 1885 | if (host_err) |
| 1883 | goto out_drop_write; | 1886 | goto out_put; |
| 1884 | if (type != S_IFDIR) | 1887 | if (type != S_IFDIR) |
| 1885 | host_err = vfs_unlink(dirp, rdentry); | 1888 | host_err = vfs_unlink(dirp, rdentry); |
| 1886 | else | 1889 | else |
| 1887 | host_err = vfs_rmdir(dirp, rdentry); | 1890 | host_err = vfs_rmdir(dirp, rdentry); |
| 1888 | if (!host_err) | 1891 | if (!host_err) |
| 1889 | host_err = commit_metadata(fhp); | 1892 | host_err = commit_metadata(fhp); |
| 1890 | out_drop_write: | ||
| 1891 | fh_drop_write(fhp); | ||
| 1892 | out_put: | 1893 | out_put: |
| 1893 | dput(rdentry); | 1894 | dput(rdentry); |
| 1894 | 1895 | ||
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index ec0611b2b738..359594c393d2 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h | |||
| @@ -110,12 +110,19 @@ int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *); | |||
| 110 | 110 | ||
| 111 | static inline int fh_want_write(struct svc_fh *fh) | 111 | static inline int fh_want_write(struct svc_fh *fh) |
| 112 | { | 112 | { |
| 113 | return mnt_want_write(fh->fh_export->ex_path.mnt); | 113 | int ret = mnt_want_write(fh->fh_export->ex_path.mnt); |
| 114 | |||
| 115 | if (!ret) | ||
| 116 | fh->fh_want_write = 1; | ||
| 117 | return ret; | ||
| 114 | } | 118 | } |
| 115 | 119 | ||
| 116 | static inline void fh_drop_write(struct svc_fh *fh) | 120 | static inline void fh_drop_write(struct svc_fh *fh) |
| 117 | { | 121 | { |
| 118 | mnt_drop_write(fh->fh_export->ex_path.mnt); | 122 | if (fh->fh_want_write) { |
| 123 | fh->fh_want_write = 0; | ||
| 124 | mnt_drop_write(fh->fh_export->ex_path.mnt); | ||
| 125 | } | ||
| 119 | } | 126 | } |
| 120 | 127 | ||
| 121 | #endif /* LINUX_NFSD_VFS_H */ | 128 | #endif /* LINUX_NFSD_VFS_H */ |
