aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-06-12 10:20:33 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-30 17:02:51 -0400
commit4a55c1017b8dcfd0554734ce3f19374d5b522d59 (patch)
tree11bb9456d121ff1cc0adad10da12b25083823a19 /fs/nfsd
parente7848683ae7ded0a4a8964122a47da9104a98337 (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.c9
-rw-r--r--fs/nfsd/nfsfh.c1
-rw-r--r--fs/nfsd/nfsproc.c9
-rw-r--r--fs/nfsd/vfs.c79
-rw-r--r--fs/nfsd/vfs.h11
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);
181out_put: 181out_put:
182 dput(dentry); 182 dput(dentry);
183out_unlock: 183out_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,
330out_unlock: 337out_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);
334done: 341done:
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 }
1721out_drop_write:
1722 fh_drop_write(tfhp);
1723out_dput: 1723out_dput:
1724 dput(dnew); 1724 dput(dnew);
1725out_unlock: 1725out_unlock:
1726 fh_unlock(ffhp); 1726 fh_unlock(ffhp);
1727 fh_drop_write(tfhp);
1727out: 1728out:
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 }
1817out_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
1835out: 1838out:
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);
1890out_drop_write:
1891 fh_drop_write(fhp);
1892out_put: 1893out_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
111static inline int fh_want_write(struct svc_fh *fh) 111static 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
116static inline void fh_drop_write(struct svc_fh *fh) 120static 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 */