diff options
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 95 |
1 files changed, 33 insertions, 62 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 3a359023c9f7..641117f2188d 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -1,4 +1,3 @@ | |||
1 | #define MSNFS /* HACK HACK */ | ||
2 | /* | 1 | /* |
3 | * File operations used by nfsd. Some of these have been ripped from | 2 | * File operations used by nfsd. Some of these have been ripped from |
4 | * other parts of the kernel because they weren't exported, others | 3 | * other parts of the kernel because they weren't exported, others |
@@ -35,8 +34,8 @@ | |||
35 | #endif /* CONFIG_NFSD_V3 */ | 34 | #endif /* CONFIG_NFSD_V3 */ |
36 | 35 | ||
37 | #ifdef CONFIG_NFSD_V4 | 36 | #ifdef CONFIG_NFSD_V4 |
38 | #include <linux/nfs4_acl.h> | 37 | #include "acl.h" |
39 | #include <linux/nfsd_idmap.h> | 38 | #include "idmap.h" |
40 | #endif /* CONFIG_NFSD_V4 */ | 39 | #endif /* CONFIG_NFSD_V4 */ |
41 | 40 | ||
42 | #include "nfsd.h" | 41 | #include "nfsd.h" |
@@ -88,8 +87,9 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |||
88 | .dentry = dget(dentry)}; | 87 | .dentry = dget(dentry)}; |
89 | int err = 0; | 88 | int err = 0; |
90 | 89 | ||
91 | while (d_mountpoint(path.dentry) && follow_down(&path)) | 90 | err = follow_down(&path, false); |
92 | ; | 91 | if (err < 0) |
92 | goto out; | ||
93 | 93 | ||
94 | exp2 = rqst_exp_get_by_name(rqstp, &path); | 94 | exp2 = rqst_exp_get_by_name(rqstp, &path); |
95 | if (IS_ERR(exp2)) { | 95 | if (IS_ERR(exp2)) { |
@@ -273,6 +273,13 @@ out: | |||
273 | return err; | 273 | return err; |
274 | } | 274 | } |
275 | 275 | ||
276 | static int nfsd_break_lease(struct inode *inode) | ||
277 | { | ||
278 | if (!S_ISREG(inode->i_mode)) | ||
279 | return 0; | ||
280 | return break_lease(inode, O_WRONLY | O_NONBLOCK); | ||
281 | } | ||
282 | |||
276 | /* | 283 | /* |
277 | * Commit metadata changes to stable storage. | 284 | * Commit metadata changes to stable storage. |
278 | */ | 285 | */ |
@@ -375,16 +382,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
375 | goto out; | 382 | goto out; |
376 | } | 383 | } |
377 | 384 | ||
378 | /* | ||
379 | * If we are changing the size of the file, then | ||
380 | * we need to break all leases. | ||
381 | */ | ||
382 | host_err = break_lease(inode, O_WRONLY | O_NONBLOCK); | ||
383 | if (host_err == -EWOULDBLOCK) | ||
384 | host_err = -ETIMEDOUT; | ||
385 | if (host_err) /* ENOMEM or EWOULDBLOCK */ | ||
386 | goto out_nfserr; | ||
387 | |||
388 | host_err = get_write_access(inode); | 385 | host_err = get_write_access(inode); |
389 | if (host_err) | 386 | if (host_err) |
390 | goto out_nfserr; | 387 | goto out_nfserr; |
@@ -425,7 +422,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, | |||
425 | 422 | ||
426 | err = nfserr_notsync; | 423 | err = nfserr_notsync; |
427 | if (!check_guard || guardtime == inode->i_ctime.tv_sec) { | 424 | if (!check_guard || guardtime == inode->i_ctime.tv_sec) { |
425 | host_err = nfsd_break_lease(inode); | ||
426 | if (host_err) | ||
427 | goto out_nfserr; | ||
428 | fh_lock(fhp); | 428 | fh_lock(fhp); |
429 | |||
429 | host_err = notify_change(dentry, iap); | 430 | host_err = notify_change(dentry, iap); |
430 | err = nfserrno(host_err); | 431 | err = nfserrno(host_err); |
431 | fh_unlock(fhp); | 432 | fh_unlock(fhp); |
@@ -752,8 +753,6 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
752 | */ | 753 | */ |
753 | if (!(access & NFSD_MAY_NOT_BREAK_LEASE)) | 754 | if (!(access & NFSD_MAY_NOT_BREAK_LEASE)) |
754 | host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0)); | 755 | host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0)); |
755 | if (host_err == -EWOULDBLOCK) | ||
756 | host_err = -ETIMEDOUT; | ||
757 | if (host_err) /* NOMEM or WOULDBLOCK */ | 756 | if (host_err) /* NOMEM or WOULDBLOCK */ |
758 | goto out_nfserr; | 757 | goto out_nfserr; |
759 | 758 | ||
@@ -845,11 +844,6 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
845 | struct page **pp = rqstp->rq_respages + rqstp->rq_resused; | 844 | struct page **pp = rqstp->rq_respages + rqstp->rq_resused; |
846 | struct page *page = buf->page; | 845 | struct page *page = buf->page; |
847 | size_t size; | 846 | size_t size; |
848 | int ret; | ||
849 | |||
850 | ret = buf->ops->confirm(pipe, buf); | ||
851 | if (unlikely(ret)) | ||
852 | return ret; | ||
853 | 847 | ||
854 | size = sd->len; | 848 | size = sd->len; |
855 | 849 | ||
@@ -879,15 +873,6 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe, | |||
879 | return __splice_from_pipe(pipe, sd, nfsd_splice_actor); | 873 | return __splice_from_pipe(pipe, sd, nfsd_splice_actor); |
880 | } | 874 | } |
881 | 875 | ||
882 | static inline int svc_msnfs(struct svc_fh *ffhp) | ||
883 | { | ||
884 | #ifdef MSNFS | ||
885 | return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS); | ||
886 | #else | ||
887 | return 0; | ||
888 | #endif | ||
889 | } | ||
890 | |||
891 | static __be32 | 876 | static __be32 |
892 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | 877 | nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, |
893 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) | 878 | loff_t offset, struct kvec *vec, int vlen, unsigned long *count) |
@@ -900,9 +885,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
900 | err = nfserr_perm; | 885 | err = nfserr_perm; |
901 | inode = file->f_path.dentry->d_inode; | 886 | inode = file->f_path.dentry->d_inode; |
902 | 887 | ||
903 | if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count)) | ||
904 | goto out; | ||
905 | |||
906 | if (file->f_op->splice_read && rqstp->rq_splice_ok) { | 888 | if (file->f_op->splice_read && rqstp->rq_splice_ok) { |
907 | struct splice_desc sd = { | 889 | struct splice_desc sd = { |
908 | .len = 0, | 890 | .len = 0, |
@@ -927,7 +909,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
927 | fsnotify_access(file); | 909 | fsnotify_access(file); |
928 | } else | 910 | } else |
929 | err = nfserrno(host_err); | 911 | err = nfserrno(host_err); |
930 | out: | ||
931 | return err; | 912 | return err; |
932 | } | 913 | } |
933 | 914 | ||
@@ -992,14 +973,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
992 | int stable = *stablep; | 973 | int stable = *stablep; |
993 | int use_wgather; | 974 | int use_wgather; |
994 | 975 | ||
995 | #ifdef MSNFS | ||
996 | err = nfserr_perm; | ||
997 | |||
998 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | ||
999 | (!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt))) | ||
1000 | goto out; | ||
1001 | #endif | ||
1002 | |||
1003 | dentry = file->f_path.dentry; | 976 | dentry = file->f_path.dentry; |
1004 | inode = dentry->d_inode; | 977 | inode = dentry->d_inode; |
1005 | exp = fhp->fh_export; | 978 | exp = fhp->fh_export; |
@@ -1050,7 +1023,6 @@ out_nfserr: | |||
1050 | err = 0; | 1023 | err = 0; |
1051 | else | 1024 | else |
1052 | err = nfserrno(host_err); | 1025 | err = nfserrno(host_err); |
1053 | out: | ||
1054 | return err; | 1026 | return err; |
1055 | } | 1027 | } |
1056 | 1028 | ||
@@ -1670,6 +1642,12 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1670 | err = nfserrno(host_err); | 1642 | err = nfserrno(host_err); |
1671 | goto out_dput; | 1643 | goto out_dput; |
1672 | } | 1644 | } |
1645 | err = nfserr_noent; | ||
1646 | if (!dold->d_inode) | ||
1647 | goto out_drop_write; | ||
1648 | host_err = nfsd_break_lease(dold->d_inode); | ||
1649 | if (host_err) | ||
1650 | goto out_drop_write; | ||
1673 | host_err = vfs_link(dold, dirp, dnew); | 1651 | host_err = vfs_link(dold, dirp, dnew); |
1674 | if (!host_err) { | 1652 | if (!host_err) { |
1675 | err = nfserrno(commit_metadata(ffhp)); | 1653 | err = nfserrno(commit_metadata(ffhp)); |
@@ -1681,6 +1659,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1681 | else | 1659 | else |
1682 | err = nfserrno(host_err); | 1660 | err = nfserrno(host_err); |
1683 | } | 1661 | } |
1662 | out_drop_write: | ||
1684 | mnt_drop_write(tfhp->fh_export->ex_path.mnt); | 1663 | mnt_drop_write(tfhp->fh_export->ex_path.mnt); |
1685 | out_dput: | 1664 | out_dput: |
1686 | dput(dnew); | 1665 | dput(dnew); |
@@ -1755,12 +1734,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1755 | if (ndentry == trap) | 1734 | if (ndentry == trap) |
1756 | goto out_dput_new; | 1735 | goto out_dput_new; |
1757 | 1736 | ||
1758 | if (svc_msnfs(ffhp) && | ||
1759 | ((odentry->d_count > 1) || (ndentry->d_count > 1))) { | ||
1760 | host_err = -EPERM; | ||
1761 | goto out_dput_new; | ||
1762 | } | ||
1763 | |||
1764 | host_err = -EXDEV; | 1737 | host_err = -EXDEV; |
1765 | if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) | 1738 | if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) |
1766 | goto out_dput_new; | 1739 | goto out_dput_new; |
@@ -1768,15 +1741,17 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1768 | if (host_err) | 1741 | if (host_err) |
1769 | goto out_dput_new; | 1742 | goto out_dput_new; |
1770 | 1743 | ||
1744 | host_err = nfsd_break_lease(odentry->d_inode); | ||
1745 | if (host_err) | ||
1746 | goto out_drop_write; | ||
1771 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1747 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); |
1772 | if (!host_err) { | 1748 | if (!host_err) { |
1773 | host_err = commit_metadata(tfhp); | 1749 | host_err = commit_metadata(tfhp); |
1774 | if (!host_err) | 1750 | if (!host_err) |
1775 | host_err = commit_metadata(ffhp); | 1751 | host_err = commit_metadata(ffhp); |
1776 | } | 1752 | } |
1777 | 1753 | out_drop_write: | |
1778 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); | 1754 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); |
1779 | |||
1780 | out_dput_new: | 1755 | out_dput_new: |
1781 | dput(ndentry); | 1756 | dput(ndentry); |
1782 | out_dput_old: | 1757 | out_dput_old: |
@@ -1839,18 +1814,14 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1839 | if (host_err) | 1814 | if (host_err) |
1840 | goto out_nfserr; | 1815 | goto out_nfserr; |
1841 | 1816 | ||
1842 | if (type != S_IFDIR) { /* It's UNLINK */ | 1817 | host_err = nfsd_break_lease(rdentry->d_inode); |
1843 | #ifdef MSNFS | 1818 | if (host_err) |
1844 | if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && | 1819 | goto out_put; |
1845 | (rdentry->d_count > 1)) { | 1820 | if (type != S_IFDIR) |
1846 | host_err = -EPERM; | ||
1847 | } else | ||
1848 | #endif | ||
1849 | host_err = vfs_unlink(dirp, rdentry); | 1821 | host_err = vfs_unlink(dirp, rdentry); |
1850 | } else { /* It's RMDIR */ | 1822 | else |
1851 | host_err = vfs_rmdir(dirp, rdentry); | 1823 | host_err = vfs_rmdir(dirp, rdentry); |
1852 | } | 1824 | out_put: |
1853 | |||
1854 | dput(rdentry); | 1825 | dput(rdentry); |
1855 | 1826 | ||
1856 | if (!host_err) | 1827 | if (!host_err) |