diff options
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 106 |
1 files changed, 52 insertions, 54 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index ed024d329056..8afdba5082e8 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/jhash.h> | 27 | #include <linux/jhash.h> |
28 | #include <linux/ima.h> | 28 | #include <linux/ima.h> |
29 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
30 | #include <linux/exportfs.h> | ||
31 | #include <linux/writeback.h> | ||
30 | 32 | ||
31 | #ifdef CONFIG_NFSD_V3 | 33 | #ifdef CONFIG_NFSD_V3 |
32 | #include "xdr3.h" | 34 | #include "xdr3.h" |
@@ -271,6 +273,32 @@ out: | |||
271 | return err; | 273 | return err; |
272 | } | 274 | } |
273 | 275 | ||
276 | /* | ||
277 | * Commit metadata changes to stable storage. | ||
278 | */ | ||
279 | static int | ||
280 | commit_metadata(struct svc_fh *fhp) | ||
281 | { | ||
282 | struct inode *inode = fhp->fh_dentry->d_inode; | ||
283 | const struct export_operations *export_ops = inode->i_sb->s_export_op; | ||
284 | int error = 0; | ||
285 | |||
286 | if (!EX_ISSYNC(fhp->fh_export)) | ||
287 | return 0; | ||
288 | |||
289 | if (export_ops->commit_metadata) { | ||
290 | error = export_ops->commit_metadata(inode); | ||
291 | } else { | ||
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 | } | ||
274 | 302 | ||
275 | /* | 303 | /* |
276 | * Set various file attributes. | 304 | * Set various file attributes. |
@@ -769,28 +797,6 @@ nfsd_close(struct file *filp) | |||
769 | } | 797 | } |
770 | 798 | ||
771 | /* | 799 | /* |
772 | * Sync a directory to disk. | ||
773 | * | ||
774 | * We can't just call vfs_fsync because our requirements are slightly odd: | ||
775 | * | ||
776 | * a) we do not have a file struct available | ||
777 | * b) we expect to have i_mutex already held by the caller | ||
778 | */ | ||
779 | int | ||
780 | nfsd_sync_dir(struct dentry *dentry) | ||
781 | { | ||
782 | struct inode *inode = dentry->d_inode; | ||
783 | int error; | ||
784 | |||
785 | WARN_ON(!mutex_is_locked(&inode->i_mutex)); | ||
786 | |||
787 | error = filemap_write_and_wait(inode->i_mapping); | ||
788 | if (!error && inode->i_fop->fsync) | ||
789 | error = inode->i_fop->fsync(NULL, dentry, 0); | ||
790 | return error; | ||
791 | } | ||
792 | |||
793 | /* | ||
794 | * Obtain the readahead parameters for the file | 800 | * Obtain the readahead parameters for the file |
795 | * specified by (dev, ino). | 801 | * specified by (dev, ino). |
796 | */ | 802 | */ |
@@ -1331,12 +1337,14 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1331 | goto out_nfserr; | 1337 | goto out_nfserr; |
1332 | } | 1338 | } |
1333 | 1339 | ||
1334 | if (EX_ISSYNC(fhp->fh_export)) { | 1340 | err = nfsd_create_setattr(rqstp, resfhp, iap); |
1335 | err = nfserrno(nfsd_sync_dir(dentry)); | ||
1336 | write_inode_now(dchild->d_inode, 1); | ||
1337 | } | ||
1338 | 1341 | ||
1339 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); | 1342 | /* |
1343 | * nfsd_setattr already committed the child. Transactional filesystems | ||
1344 | * had a chance to commit changes for both parent and child | ||
1345 | * simultaneously making the following commit_metadata a noop. | ||
1346 | */ | ||
1347 | err2 = nfserrno(commit_metadata(fhp)); | ||
1340 | if (err2) | 1348 | if (err2) |
1341 | err = err2; | 1349 | err = err2; |
1342 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1350 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
@@ -1368,7 +1376,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1368 | struct dentry *dentry, *dchild = NULL; | 1376 | struct dentry *dentry, *dchild = NULL; |
1369 | struct inode *dirp; | 1377 | struct inode *dirp; |
1370 | __be32 err; | 1378 | __be32 err; |
1371 | __be32 err2; | ||
1372 | int host_err; | 1379 | int host_err; |
1373 | __u32 v_mtime=0, v_atime=0; | 1380 | __u32 v_mtime=0, v_atime=0; |
1374 | 1381 | ||
@@ -1463,11 +1470,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1463 | if (created) | 1470 | if (created) |
1464 | *created = 1; | 1471 | *created = 1; |
1465 | 1472 | ||
1466 | if (EX_ISSYNC(fhp->fh_export)) { | ||
1467 | err = nfserrno(nfsd_sync_dir(dentry)); | ||
1468 | /* setattr will sync the child (or not) */ | ||
1469 | } | ||
1470 | |||
1471 | nfsd_check_ignore_resizing(iap); | 1473 | nfsd_check_ignore_resizing(iap); |
1472 | 1474 | ||
1473 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1475 | if (createmode == NFS3_CREATE_EXCLUSIVE) { |
@@ -1482,9 +1484,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1482 | } | 1484 | } |
1483 | 1485 | ||
1484 | set_attr: | 1486 | set_attr: |
1485 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); | 1487 | err = nfsd_create_setattr(rqstp, resfhp, iap); |
1486 | if (err2) | 1488 | |
1487 | err = err2; | 1489 | /* |
1490 | * nfsd_setattr already committed the child (and possibly also the parent). | ||
1491 | */ | ||
1492 | if (!err) | ||
1493 | err = nfserrno(commit_metadata(fhp)); | ||
1488 | 1494 | ||
1489 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1495 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
1490 | /* | 1496 | /* |
@@ -1599,12 +1605,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1599 | } | 1605 | } |
1600 | } else | 1606 | } else |
1601 | host_err = vfs_symlink(dentry->d_inode, dnew, path); | 1607 | host_err = vfs_symlink(dentry->d_inode, dnew, path); |
1602 | |||
1603 | if (!host_err) { | ||
1604 | if (EX_ISSYNC(fhp->fh_export)) | ||
1605 | host_err = nfsd_sync_dir(dentry); | ||
1606 | } | ||
1607 | err = nfserrno(host_err); | 1608 | err = nfserrno(host_err); |
1609 | if (!err) | ||
1610 | err = nfserrno(commit_metadata(fhp)); | ||
1608 | fh_unlock(fhp); | 1611 | fh_unlock(fhp); |
1609 | 1612 | ||
1610 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1613 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
@@ -1666,11 +1669,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1666 | } | 1669 | } |
1667 | host_err = vfs_link(dold, dirp, dnew); | 1670 | host_err = vfs_link(dold, dirp, dnew); |
1668 | if (!host_err) { | 1671 | if (!host_err) { |
1669 | if (EX_ISSYNC(ffhp->fh_export)) { | 1672 | err = nfserrno(commit_metadata(ffhp)); |
1670 | err = nfserrno(nfsd_sync_dir(ddir)); | 1673 | if (!err) |
1671 | write_inode_now(dest, 1); | 1674 | err = nfserrno(commit_metadata(tfhp)); |
1672 | } | ||
1673 | err = 0; | ||
1674 | } else { | 1675 | } else { |
1675 | if (host_err == -EXDEV && rqstp->rq_vers == 2) | 1676 | if (host_err == -EXDEV && rqstp->rq_vers == 2) |
1676 | err = nfserr_acces; | 1677 | err = nfserr_acces; |
@@ -1766,10 +1767,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1766 | goto out_dput_new; | 1767 | goto out_dput_new; |
1767 | 1768 | ||
1768 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1769 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); |
1769 | if (!host_err && EX_ISSYNC(tfhp->fh_export)) { | 1770 | if (!host_err) { |
1770 | host_err = nfsd_sync_dir(tdentry); | 1771 | host_err = commit_metadata(tfhp); |
1771 | if (!host_err) | 1772 | if (!host_err) |
1772 | host_err = nfsd_sync_dir(fdentry); | 1773 | host_err = commit_metadata(ffhp); |
1773 | } | 1774 | } |
1774 | 1775 | ||
1775 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); | 1776 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); |
@@ -1850,12 +1851,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1850 | 1851 | ||
1851 | dput(rdentry); | 1852 | dput(rdentry); |
1852 | 1853 | ||
1853 | if (host_err) | 1854 | if (!host_err) |
1854 | goto out_drop; | 1855 | host_err = commit_metadata(fhp); |
1855 | if (EX_ISSYNC(fhp->fh_export)) | ||
1856 | host_err = nfsd_sync_dir(dentry); | ||
1857 | 1856 | ||
1858 | out_drop: | ||
1859 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1857 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
1860 | out_nfserr: | 1858 | out_nfserr: |
1861 | err = nfserrno(host_err); | 1859 | err = nfserrno(host_err); |