diff options
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 72 |
1 files changed, 62 insertions, 10 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 46f59d5365a0..304bf5f643c9 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -1255,23 +1255,35 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1255 | err = 0; | 1255 | err = 0; |
1256 | switch (type) { | 1256 | switch (type) { |
1257 | case S_IFREG: | 1257 | case S_IFREG: |
1258 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); | ||
1259 | if (host_err) | ||
1260 | goto out_nfserr; | ||
1258 | host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); | 1261 | host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); |
1259 | break; | 1262 | break; |
1260 | case S_IFDIR: | 1263 | case S_IFDIR: |
1264 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); | ||
1265 | if (host_err) | ||
1266 | goto out_nfserr; | ||
1261 | host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); | 1267 | host_err = vfs_mkdir(dirp, dchild, iap->ia_mode); |
1262 | break; | 1268 | break; |
1263 | case S_IFCHR: | 1269 | case S_IFCHR: |
1264 | case S_IFBLK: | 1270 | case S_IFBLK: |
1265 | case S_IFIFO: | 1271 | case S_IFIFO: |
1266 | case S_IFSOCK: | 1272 | case S_IFSOCK: |
1273 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); | ||
1274 | if (host_err) | ||
1275 | goto out_nfserr; | ||
1267 | host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); | 1276 | host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); |
1268 | break; | 1277 | break; |
1269 | default: | 1278 | default: |
1270 | printk("nfsd: bad file type %o in nfsd_create\n", type); | 1279 | printk("nfsd: bad file type %o in nfsd_create\n", type); |
1271 | host_err = -EINVAL; | 1280 | host_err = -EINVAL; |
1281 | goto out_nfserr; | ||
1272 | } | 1282 | } |
1273 | if (host_err < 0) | 1283 | if (host_err < 0) { |
1284 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
1274 | goto out_nfserr; | 1285 | goto out_nfserr; |
1286 | } | ||
1275 | 1287 | ||
1276 | if (EX_ISSYNC(fhp->fh_export)) { | 1288 | if (EX_ISSYNC(fhp->fh_export)) { |
1277 | err = nfserrno(nfsd_sync_dir(dentry)); | 1289 | err = nfserrno(nfsd_sync_dir(dentry)); |
@@ -1282,6 +1294,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1282 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); | 1294 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); |
1283 | if (err2) | 1295 | if (err2) |
1284 | err = err2; | 1296 | err = err2; |
1297 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
1285 | /* | 1298 | /* |
1286 | * Update the file handle to get the new inode info. | 1299 | * Update the file handle to get the new inode info. |
1287 | */ | 1300 | */ |
@@ -1359,6 +1372,9 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1359 | v_atime = verifier[1]&0x7fffffff; | 1372 | v_atime = verifier[1]&0x7fffffff; |
1360 | } | 1373 | } |
1361 | 1374 | ||
1375 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); | ||
1376 | if (host_err) | ||
1377 | goto out_nfserr; | ||
1362 | if (dchild->d_inode) { | 1378 | if (dchild->d_inode) { |
1363 | err = 0; | 1379 | err = 0; |
1364 | 1380 | ||
@@ -1390,12 +1406,15 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1390 | case NFS3_CREATE_GUARDED: | 1406 | case NFS3_CREATE_GUARDED: |
1391 | err = nfserr_exist; | 1407 | err = nfserr_exist; |
1392 | } | 1408 | } |
1409 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
1393 | goto out; | 1410 | goto out; |
1394 | } | 1411 | } |
1395 | 1412 | ||
1396 | host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); | 1413 | host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL); |
1397 | if (host_err < 0) | 1414 | if (host_err < 0) { |
1415 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
1398 | goto out_nfserr; | 1416 | goto out_nfserr; |
1417 | } | ||
1399 | if (created) | 1418 | if (created) |
1400 | *created = 1; | 1419 | *created = 1; |
1401 | 1420 | ||
@@ -1420,6 +1439,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1420 | if (err2) | 1439 | if (err2) |
1421 | err = err2; | 1440 | err = err2; |
1422 | 1441 | ||
1442 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
1423 | /* | 1443 | /* |
1424 | * Update the filehandle to get the new inode info. | 1444 | * Update the filehandle to get the new inode info. |
1425 | */ | 1445 | */ |
@@ -1522,6 +1542,10 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1522 | if (iap && (iap->ia_valid & ATTR_MODE)) | 1542 | if (iap && (iap->ia_valid & ATTR_MODE)) |
1523 | mode = iap->ia_mode & S_IALLUGO; | 1543 | mode = iap->ia_mode & S_IALLUGO; |
1524 | 1544 | ||
1545 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); | ||
1546 | if (host_err) | ||
1547 | goto out_nfserr; | ||
1548 | |||
1525 | if (unlikely(path[plen] != 0)) { | 1549 | if (unlikely(path[plen] != 0)) { |
1526 | char *path_alloced = kmalloc(plen+1, GFP_KERNEL); | 1550 | char *path_alloced = kmalloc(plen+1, GFP_KERNEL); |
1527 | if (path_alloced == NULL) | 1551 | if (path_alloced == NULL) |
@@ -1542,6 +1566,8 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1542 | err = nfserrno(host_err); | 1566 | err = nfserrno(host_err); |
1543 | fh_unlock(fhp); | 1567 | fh_unlock(fhp); |
1544 | 1568 | ||
1569 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
1570 | |||
1545 | cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); | 1571 | cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); |
1546 | dput(dnew); | 1572 | dput(dnew); |
1547 | if (err==0) err = cerr; | 1573 | if (err==0) err = cerr; |
@@ -1592,6 +1618,11 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1592 | dold = tfhp->fh_dentry; | 1618 | dold = tfhp->fh_dentry; |
1593 | dest = dold->d_inode; | 1619 | dest = dold->d_inode; |
1594 | 1620 | ||
1621 | host_err = mnt_want_write(tfhp->fh_export->ex_path.mnt); | ||
1622 | if (host_err) { | ||
1623 | err = nfserrno(host_err); | ||
1624 | goto out_dput; | ||
1625 | } | ||
1595 | host_err = vfs_link(dold, dirp, dnew); | 1626 | host_err = vfs_link(dold, dirp, dnew); |
1596 | if (!host_err) { | 1627 | if (!host_err) { |
1597 | if (EX_ISSYNC(ffhp->fh_export)) { | 1628 | if (EX_ISSYNC(ffhp->fh_export)) { |
@@ -1605,7 +1636,8 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1605 | else | 1636 | else |
1606 | err = nfserrno(host_err); | 1637 | err = nfserrno(host_err); |
1607 | } | 1638 | } |
1608 | 1639 | mnt_drop_write(tfhp->fh_export->ex_path.mnt); | |
1640 | out_dput: | ||
1609 | dput(dnew); | 1641 | dput(dnew); |
1610 | out_unlock: | 1642 | out_unlock: |
1611 | fh_unlock(ffhp); | 1643 | fh_unlock(ffhp); |
@@ -1678,13 +1710,20 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1678 | if (ndentry == trap) | 1710 | if (ndentry == trap) |
1679 | goto out_dput_new; | 1711 | goto out_dput_new; |
1680 | 1712 | ||
1681 | #ifdef MSNFS | 1713 | if (svc_msnfs(ffhp) && |
1682 | if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) && | ||
1683 | ((atomic_read(&odentry->d_count) > 1) | 1714 | ((atomic_read(&odentry->d_count) > 1) |
1684 | || (atomic_read(&ndentry->d_count) > 1))) { | 1715 | || (atomic_read(&ndentry->d_count) > 1))) { |
1685 | host_err = -EPERM; | 1716 | host_err = -EPERM; |
1686 | } else | 1717 | goto out_dput_new; |
1687 | #endif | 1718 | } |
1719 | |||
1720 | host_err = -EXDEV; | ||
1721 | if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) | ||
1722 | goto out_dput_new; | ||
1723 | host_err = mnt_want_write(ffhp->fh_export->ex_path.mnt); | ||
1724 | if (host_err) | ||
1725 | goto out_dput_new; | ||
1726 | |||
1688 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1727 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); |
1689 | if (!host_err && EX_ISSYNC(tfhp->fh_export)) { | 1728 | if (!host_err && EX_ISSYNC(tfhp->fh_export)) { |
1690 | host_err = nfsd_sync_dir(tdentry); | 1729 | host_err = nfsd_sync_dir(tdentry); |
@@ -1692,6 +1731,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1692 | host_err = nfsd_sync_dir(fdentry); | 1731 | host_err = nfsd_sync_dir(fdentry); |
1693 | } | 1732 | } |
1694 | 1733 | ||
1734 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); | ||
1735 | |||
1695 | out_dput_new: | 1736 | out_dput_new: |
1696 | dput(ndentry); | 1737 | dput(ndentry); |
1697 | out_dput_old: | 1738 | out_dput_old: |
@@ -1750,6 +1791,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1750 | if (!type) | 1791 | if (!type) |
1751 | type = rdentry->d_inode->i_mode & S_IFMT; | 1792 | type = rdentry->d_inode->i_mode & S_IFMT; |
1752 | 1793 | ||
1794 | host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); | ||
1795 | if (host_err) | ||
1796 | goto out_nfserr; | ||
1797 | |||
1753 | if (type != S_IFDIR) { /* It's UNLINK */ | 1798 | if (type != S_IFDIR) { /* It's UNLINK */ |
1754 | #ifdef MSNFS | 1799 | #ifdef MSNFS |
1755 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1800 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && |
@@ -1765,10 +1810,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1765 | dput(rdentry); | 1810 | dput(rdentry); |
1766 | 1811 | ||
1767 | if (host_err) | 1812 | if (host_err) |
1768 | goto out_nfserr; | 1813 | goto out_drop; |
1769 | if (EX_ISSYNC(fhp->fh_export)) | 1814 | if (EX_ISSYNC(fhp->fh_export)) |
1770 | host_err = nfsd_sync_dir(dentry); | 1815 | host_err = nfsd_sync_dir(dentry); |
1771 | 1816 | ||
1817 | out_drop: | ||
1818 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
1772 | out_nfserr: | 1819 | out_nfserr: |
1773 | err = nfserrno(host_err); | 1820 | err = nfserrno(host_err); |
1774 | out: | 1821 | out: |
@@ -1865,7 +1912,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
1865 | inode->i_mode, | 1912 | inode->i_mode, |
1866 | IS_IMMUTABLE(inode)? " immut" : "", | 1913 | IS_IMMUTABLE(inode)? " immut" : "", |
1867 | IS_APPEND(inode)? " append" : "", | 1914 | IS_APPEND(inode)? " append" : "", |
1868 | IS_RDONLY(inode)? " ro" : ""); | 1915 | __mnt_is_readonly(exp->ex_path.mnt)? " ro" : ""); |
1869 | dprintk(" owner %d/%d user %d/%d\n", | 1916 | dprintk(" owner %d/%d user %d/%d\n", |
1870 | inode->i_uid, inode->i_gid, current->fsuid, current->fsgid); | 1917 | inode->i_uid, inode->i_gid, current->fsuid, current->fsgid); |
1871 | #endif | 1918 | #endif |
@@ -1876,7 +1923,8 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp, | |||
1876 | */ | 1923 | */ |
1877 | if (!(acc & MAY_LOCAL_ACCESS)) | 1924 | if (!(acc & MAY_LOCAL_ACCESS)) |
1878 | if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { | 1925 | if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { |
1879 | if (exp_rdonly(rqstp, exp) || IS_RDONLY(inode)) | 1926 | if (exp_rdonly(rqstp, exp) || |
1927 | __mnt_is_readonly(exp->ex_path.mnt)) | ||
1880 | return nfserr_rofs; | 1928 | return nfserr_rofs; |
1881 | if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) | 1929 | if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) |
1882 | return nfserr_perm; | 1930 | return nfserr_perm; |
@@ -2039,6 +2087,9 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) | |||
2039 | } else | 2087 | } else |
2040 | size = 0; | 2088 | size = 0; |
2041 | 2089 | ||
2090 | error = mnt_want_write(fhp->fh_export->ex_path.mnt); | ||
2091 | if (error) | ||
2092 | goto getout; | ||
2042 | if (size) | 2093 | if (size) |
2043 | error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0); | 2094 | error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0); |
2044 | else { | 2095 | else { |
@@ -2050,6 +2101,7 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl) | |||
2050 | error = 0; | 2101 | error = 0; |
2051 | } | 2102 | } |
2052 | } | 2103 | } |
2104 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | ||
2053 | 2105 | ||
2054 | getout: | 2106 | getout: |
2055 | kfree(value); | 2107 | kfree(value); |