aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c186
1 files changed, 85 insertions, 101 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 661a6cf8e826..fd0acca5370a 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);
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)) {
@@ -181,16 +181,10 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
181 struct svc_export *exp; 181 struct svc_export *exp;
182 struct dentry *dparent; 182 struct dentry *dparent;
183 struct dentry *dentry; 183 struct dentry *dentry;
184 __be32 err;
185 int host_err; 184 int host_err;
186 185
187 dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name); 186 dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
188 187
189 /* Obtain dentry and export. */
190 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
191 if (err)
192 return err;
193
194 dparent = fhp->fh_dentry; 188 dparent = fhp->fh_dentry;
195 exp = fhp->fh_export; 189 exp = fhp->fh_export;
196 exp_get(exp); 190 exp_get(exp);
@@ -254,6 +248,9 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
254 struct dentry *dentry; 248 struct dentry *dentry;
255 __be32 err; 249 __be32 err;
256 250
251 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
252 if (err)
253 return err;
257 err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry); 254 err = nfsd_lookup_dentry(rqstp, fhp, name, len, &exp, &dentry);
258 if (err) 255 if (err)
259 return err; 256 return err;
@@ -273,6 +270,13 @@ out:
273 return err; 270 return err;
274} 271}
275 272
273static int nfsd_break_lease(struct inode *inode)
274{
275 if (!S_ISREG(inode->i_mode))
276 return 0;
277 return break_lease(inode, O_WRONLY | O_NONBLOCK);
278}
279
276/* 280/*
277 * Commit metadata changes to stable storage. 281 * Commit metadata changes to stable storage.
278 */ 282 */
@@ -281,23 +285,13 @@ commit_metadata(struct svc_fh *fhp)
281{ 285{
282 struct inode *inode = fhp->fh_dentry->d_inode; 286 struct inode *inode = fhp->fh_dentry->d_inode;
283 const struct export_operations *export_ops = inode->i_sb->s_export_op; 287 const struct export_operations *export_ops = inode->i_sb->s_export_op;
284 int error = 0;
285 288
286 if (!EX_ISSYNC(fhp->fh_export)) 289 if (!EX_ISSYNC(fhp->fh_export))
287 return 0; 290 return 0;
288 291
289 if (export_ops->commit_metadata) { 292 if (export_ops->commit_metadata)
290 error = export_ops->commit_metadata(inode); 293 return export_ops->commit_metadata(inode);
291 } else { 294 return sync_inode_metadata(inode, 1);
292 struct writeback_control wbc = {
293 .sync_mode = WB_SYNC_ALL,
294 .nr_to_write = 0, /* metadata only */
295 };
296
297 error = sync_inode(inode, &wbc);
298 }
299
300 return error;
301} 295}
302 296
303/* 297/*
@@ -385,16 +379,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
385 goto out; 379 goto out;
386 } 380 }
387 381
388 /*
389 * If we are changing the size of the file, then
390 * we need to break all leases.
391 */
392 host_err = break_lease(inode, O_WRONLY | O_NONBLOCK);
393 if (host_err == -EWOULDBLOCK)
394 host_err = -ETIMEDOUT;
395 if (host_err) /* ENOMEM or EWOULDBLOCK */
396 goto out_nfserr;
397
398 host_err = get_write_access(inode); 382 host_err = get_write_access(inode);
399 if (host_err) 383 if (host_err)
400 goto out_nfserr; 384 goto out_nfserr;
@@ -435,7 +419,11 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
435 419
436 err = nfserr_notsync; 420 err = nfserr_notsync;
437 if (!check_guard || guardtime == inode->i_ctime.tv_sec) { 421 if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
422 host_err = nfsd_break_lease(inode);
423 if (host_err)
424 goto out_nfserr;
438 fh_lock(fhp); 425 fh_lock(fhp);
426
439 host_err = notify_change(dentry, iap); 427 host_err = notify_change(dentry, iap);
440 err = nfserrno(host_err); 428 err = nfserrno(host_err);
441 fh_unlock(fhp); 429 fh_unlock(fhp);
@@ -708,7 +696,15 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
708} 696}
709#endif /* CONFIG_NFSD_V3 */ 697#endif /* CONFIG_NFSD_V3 */
710 698
699static int nfsd_open_break_lease(struct inode *inode, int access)
700{
701 unsigned int mode;
711 702
703 if (access & NFSD_MAY_NOT_BREAK_LEASE)
704 return 0;
705 mode = (access & NFSD_MAY_WRITE) ? O_WRONLY : O_RDONLY;
706 return break_lease(inode, mode | O_NONBLOCK);
707}
712 708
713/* 709/*
714 * Open an existing file or directory. 710 * Open an existing file or directory.
@@ -756,14 +752,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
756 if (!inode->i_fop) 752 if (!inode->i_fop)
757 goto out; 753 goto out;
758 754
759 /* 755 host_err = nfsd_open_break_lease(inode, access);
760 * Check to see if there are any leases on this file.
761 * This may block while leases are broken.
762 */
763 if (!(access & NFSD_MAY_NOT_BREAK_LEASE))
764 host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0));
765 if (host_err == -EWOULDBLOCK)
766 host_err = -ETIMEDOUT;
767 if (host_err) /* NOMEM or WOULDBLOCK */ 756 if (host_err) /* NOMEM or WOULDBLOCK */
768 goto out_nfserr; 757 goto out_nfserr;
769 758
@@ -819,7 +808,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
819 if (ra->p_count == 0) 808 if (ra->p_count == 0)
820 frap = rap; 809 frap = rap;
821 } 810 }
822 depth = nfsdstats.ra_size*11/10; 811 depth = nfsdstats.ra_size;
823 if (!frap) { 812 if (!frap) {
824 spin_unlock(&rab->pb_lock); 813 spin_unlock(&rab->pb_lock);
825 return NULL; 814 return NULL;
@@ -855,11 +844,6 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
855 struct page **pp = rqstp->rq_respages + rqstp->rq_resused; 844 struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
856 struct page *page = buf->page; 845 struct page *page = buf->page;
857 size_t size; 846 size_t size;
858 int ret;
859
860 ret = buf->ops->confirm(pipe, buf);
861 if (unlikely(ret))
862 return ret;
863 847
864 size = sd->len; 848 size = sd->len;
865 849
@@ -889,29 +873,15 @@ static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe,
889 return __splice_from_pipe(pipe, sd, nfsd_splice_actor); 873 return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
890} 874}
891 875
892static inline int svc_msnfs(struct svc_fh *ffhp)
893{
894#ifdef MSNFS
895 return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS);
896#else
897 return 0;
898#endif
899}
900
901static __be32 876static __be32
902nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, 877nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
903 loff_t offset, struct kvec *vec, int vlen, unsigned long *count) 878 loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
904{ 879{
905 struct inode *inode;
906 mm_segment_t oldfs; 880 mm_segment_t oldfs;
907 __be32 err; 881 __be32 err;
908 int host_err; 882 int host_err;
909 883
910 err = nfserr_perm; 884 err = nfserr_perm;
911 inode = file->f_path.dentry->d_inode;
912
913 if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))
914 goto out;
915 885
916 if (file->f_op->splice_read && rqstp->rq_splice_ok) { 886 if (file->f_op->splice_read && rqstp->rq_splice_ok) {
917 struct splice_desc sd = { 887 struct splice_desc sd = {
@@ -937,7 +907,6 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
937 fsnotify_access(file); 907 fsnotify_access(file);
938 } else 908 } else
939 err = nfserrno(host_err); 909 err = nfserrno(host_err);
940out:
941 return err; 910 return err;
942} 911}
943 912
@@ -1002,14 +971,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
1002 int stable = *stablep; 971 int stable = *stablep;
1003 int use_wgather; 972 int use_wgather;
1004 973
1005#ifdef MSNFS
1006 err = nfserr_perm;
1007
1008 if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
1009 (!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt)))
1010 goto out;
1011#endif
1012
1013 dentry = file->f_path.dentry; 974 dentry = file->f_path.dentry;
1014 inode = dentry->d_inode; 975 inode = dentry->d_inode;
1015 exp = fhp->fh_export; 976 exp = fhp->fh_export;
@@ -1060,7 +1021,6 @@ out_nfserr:
1060 err = 0; 1021 err = 0;
1061 else 1022 else
1062 err = nfserrno(host_err); 1023 err = nfserrno(host_err);
1063out:
1064 return err; 1024 return err;
1065} 1025}
1066 1026
@@ -1378,11 +1338,18 @@ out_nfserr:
1378} 1338}
1379 1339
1380#ifdef CONFIG_NFSD_V3 1340#ifdef CONFIG_NFSD_V3
1341
1342static inline int nfsd_create_is_exclusive(int createmode)
1343{
1344 return createmode == NFS3_CREATE_EXCLUSIVE
1345 || createmode == NFS4_CREATE_EXCLUSIVE4_1;
1346}
1347
1381/* 1348/*
1382 * NFSv3 version of nfsd_create 1349 * NFSv3 and NFSv4 version of nfsd_create
1383 */ 1350 */
1384__be32 1351__be32
1385nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, 1352do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
1386 char *fname, int flen, struct iattr *iap, 1353 char *fname, int flen, struct iattr *iap,
1387 struct svc_fh *resfhp, int createmode, u32 *verifier, 1354 struct svc_fh *resfhp, int createmode, u32 *verifier,
1388 int *truncp, int *created) 1355 int *truncp, int *created)
@@ -1401,7 +1368,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1401 goto out; 1368 goto out;
1402 if (!(iap->ia_valid & ATTR_MODE)) 1369 if (!(iap->ia_valid & ATTR_MODE))
1403 iap->ia_mode = 0; 1370 iap->ia_mode = 0;
1404 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); 1371 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
1405 if (err) 1372 if (err)
1406 goto out; 1373 goto out;
1407 1374
@@ -1423,11 +1390,18 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1423 if (IS_ERR(dchild)) 1390 if (IS_ERR(dchild))
1424 goto out_nfserr; 1391 goto out_nfserr;
1425 1392
1393 /* If file doesn't exist, check for permissions to create one */
1394 if (!dchild->d_inode) {
1395 err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
1396 if (err)
1397 goto out;
1398 }
1399
1426 err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); 1400 err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
1427 if (err) 1401 if (err)
1428 goto out; 1402 goto out;
1429 1403
1430 if (createmode == NFS3_CREATE_EXCLUSIVE) { 1404 if (nfsd_create_is_exclusive(createmode)) {
1431 /* solaris7 gets confused (bugid 4218508) if these have 1405 /* solaris7 gets confused (bugid 4218508) if these have
1432 * the high bit set, so just clear the high bits. If this is 1406 * the high bit set, so just clear the high bits. If this is
1433 * ever changed to use different attrs for storing the 1407 * ever changed to use different attrs for storing the
@@ -1468,6 +1442,11 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1468 && dchild->d_inode->i_atime.tv_sec == v_atime 1442 && dchild->d_inode->i_atime.tv_sec == v_atime
1469 && dchild->d_inode->i_size == 0 ) 1443 && dchild->d_inode->i_size == 0 )
1470 break; 1444 break;
1445 case NFS4_CREATE_EXCLUSIVE4_1:
1446 if ( dchild->d_inode->i_mtime.tv_sec == v_mtime
1447 && dchild->d_inode->i_atime.tv_sec == v_atime
1448 && dchild->d_inode->i_size == 0 )
1449 goto set_attr;
1471 /* fallthru */ 1450 /* fallthru */
1472 case NFS3_CREATE_GUARDED: 1451 case NFS3_CREATE_GUARDED:
1473 err = nfserr_exist; 1452 err = nfserr_exist;
@@ -1486,7 +1465,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
1486 1465
1487 nfsd_check_ignore_resizing(iap); 1466 nfsd_check_ignore_resizing(iap);
1488 1467
1489 if (createmode == NFS3_CREATE_EXCLUSIVE) { 1468 if (nfsd_create_is_exclusive(createmode)) {
1490 /* Cram the verifier into atime/mtime */ 1469 /* Cram the verifier into atime/mtime */
1491 iap->ia_valid = ATTR_MTIME|ATTR_ATIME 1470 iap->ia_valid = ATTR_MTIME|ATTR_ATIME
1492 | ATTR_MTIME_SET|ATTR_ATIME_SET; 1471 | ATTR_MTIME_SET|ATTR_ATIME_SET;
@@ -1680,6 +1659,14 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
1680 err = nfserrno(host_err); 1659 err = nfserrno(host_err);
1681 goto out_dput; 1660 goto out_dput;
1682 } 1661 }
1662 err = nfserr_noent;
1663 if (!dold->d_inode)
1664 goto out_drop_write;
1665 host_err = nfsd_break_lease(dold->d_inode);
1666 if (host_err) {
1667 err = nfserrno(host_err);
1668 goto out_drop_write;
1669 }
1683 host_err = vfs_link(dold, dirp, dnew); 1670 host_err = vfs_link(dold, dirp, dnew);
1684 if (!host_err) { 1671 if (!host_err) {
1685 err = nfserrno(commit_metadata(ffhp)); 1672 err = nfserrno(commit_metadata(ffhp));
@@ -1691,6 +1678,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
1691 else 1678 else
1692 err = nfserrno(host_err); 1679 err = nfserrno(host_err);
1693 } 1680 }
1681out_drop_write:
1694 mnt_drop_write(tfhp->fh_export->ex_path.mnt); 1682 mnt_drop_write(tfhp->fh_export->ex_path.mnt);
1695out_dput: 1683out_dput:
1696 dput(dnew); 1684 dput(dnew);
@@ -1765,13 +1753,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
1765 if (ndentry == trap) 1753 if (ndentry == trap)
1766 goto out_dput_new; 1754 goto out_dput_new;
1767 1755
1768 if (svc_msnfs(ffhp) &&
1769 ((atomic_read(&odentry->d_count) > 1)
1770 || (atomic_read(&ndentry->d_count) > 1))) {
1771 host_err = -EPERM;
1772 goto out_dput_new;
1773 }
1774
1775 host_err = -EXDEV; 1756 host_err = -EXDEV;
1776 if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt) 1757 if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt)
1777 goto out_dput_new; 1758 goto out_dput_new;
@@ -1779,15 +1760,22 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
1779 if (host_err) 1760 if (host_err)
1780 goto out_dput_new; 1761 goto out_dput_new;
1781 1762
1763 host_err = nfsd_break_lease(odentry->d_inode);
1764 if (host_err)
1765 goto out_drop_write;
1766 if (ndentry->d_inode) {
1767 host_err = nfsd_break_lease(ndentry->d_inode);
1768 if (host_err)
1769 goto out_drop_write;
1770 }
1782 host_err = vfs_rename(fdir, odentry, tdir, ndentry); 1771 host_err = vfs_rename(fdir, odentry, tdir, ndentry);
1783 if (!host_err) { 1772 if (!host_err) {
1784 host_err = commit_metadata(tfhp); 1773 host_err = commit_metadata(tfhp);
1785 if (!host_err) 1774 if (!host_err)
1786 host_err = commit_metadata(ffhp); 1775 host_err = commit_metadata(ffhp);
1787 } 1776 }
1788 1777out_drop_write:
1789 mnt_drop_write(ffhp->fh_export->ex_path.mnt); 1778 mnt_drop_write(ffhp->fh_export->ex_path.mnt);
1790
1791 out_dput_new: 1779 out_dput_new:
1792 dput(ndentry); 1780 dput(ndentry);
1793 out_dput_old: 1781 out_dput_old:
@@ -1848,26 +1836,22 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
1848 1836
1849 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt); 1837 host_err = mnt_want_write(fhp->fh_export->ex_path.mnt);
1850 if (host_err) 1838 if (host_err)
1851 goto out_nfserr; 1839 goto out_put;
1852 1840
1853 if (type != S_IFDIR) { /* It's UNLINK */ 1841 host_err = nfsd_break_lease(rdentry->d_inode);
1854#ifdef MSNFS 1842 if (host_err)
1855 if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) && 1843 goto out_drop_write;
1856 (atomic_read(&rdentry->d_count) > 1)) { 1844 if (type != S_IFDIR)
1857 host_err = -EPERM;
1858 } else
1859#endif
1860 host_err = vfs_unlink(dirp, rdentry); 1845 host_err = vfs_unlink(dirp, rdentry);
1861 } else { /* It's RMDIR */ 1846 else
1862 host_err = vfs_rmdir(dirp, rdentry); 1847 host_err = vfs_rmdir(dirp, rdentry);
1863 }
1864
1865 dput(rdentry);
1866
1867 if (!host_err) 1848 if (!host_err)
1868 host_err = commit_metadata(fhp); 1849 host_err = commit_metadata(fhp);
1869 1850out_drop_write:
1870 mnt_drop_write(fhp->fh_export->ex_path.mnt); 1851 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1852out_put:
1853 dput(rdentry);
1854
1871out_nfserr: 1855out_nfserr:
1872 err = nfserrno(host_err); 1856 err = nfserrno(host_err);
1873out: 1857out:
@@ -2062,7 +2046,7 @@ nfsd_permission(struct svc_rqst *rqstp, struct svc_export *exp,
2062 struct inode *inode = dentry->d_inode; 2046 struct inode *inode = dentry->d_inode;
2063 int err; 2047 int err;
2064 2048
2065 if (acc == NFSD_MAY_NOP) 2049 if ((acc & NFSD_MAY_MASK) == NFSD_MAY_NOP)
2066 return 0; 2050 return 0;
2067#if 0 2051#if 0
2068 dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n", 2052 dprintk("nfsd: permission 0x%x%s%s%s%s%s%s%s mode 0%o%s%s%s\n",