diff options
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 186 |
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 | ||
273 | static 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 | ||
699 | static 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 | ||
892 | static 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 | |||
901 | static __be32 | 876 | static __be32 |
902 | 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, |
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); |
940 | out: | ||
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); |
1063 | out: | ||
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 | |||
1342 | static 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 |
1385 | nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | 1352 | do_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 | } |
1681 | out_drop_write: | ||
1694 | mnt_drop_write(tfhp->fh_export->ex_path.mnt); | 1682 | mnt_drop_write(tfhp->fh_export->ex_path.mnt); |
1695 | out_dput: | 1683 | out_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 | 1777 | out_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 | 1850 | out_drop_write: | |
1870 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1851 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
1852 | out_put: | ||
1853 | dput(rdentry); | ||
1854 | |||
1871 | out_nfserr: | 1855 | out_nfserr: |
1872 | err = nfserrno(host_err); | 1856 | err = nfserrno(host_err); |
1873 | out: | 1857 | out: |
@@ -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", |