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/nfsd | |
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/nfsd')
-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 */ |