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); |
