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.c106
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 */
279static int
280commit_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 */
779int
780nfsd_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
1858out_drop:
1859 mnt_drop_write(fhp->fh_export->ex_path.mnt); 1857 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1860out_nfserr: 1858out_nfserr:
1861 err = nfserrno(host_err); 1859 err = nfserrno(host_err);