diff options
| -rw-r--r-- | fs/nfsd/nfs4recover.c | 4 | ||||
| -rw-r--r-- | fs/nfsd/vfs.c | 106 | ||||
| -rw-r--r-- | include/linux/exportfs.h | 5 |
3 files changed, 58 insertions, 57 deletions
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 5a754f7b71ed..98fb98e330b4 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c | |||
| @@ -119,9 +119,7 @@ out_no_tfm: | |||
| 119 | static void | 119 | static void |
| 120 | nfsd4_sync_rec_dir(void) | 120 | nfsd4_sync_rec_dir(void) |
| 121 | { | 121 | { |
| 122 | mutex_lock(&rec_dir.dentry->d_inode->i_mutex); | 122 | vfs_fsync(NULL, rec_dir.dentry, 0); |
| 123 | nfsd_sync_dir(rec_dir.dentry); | ||
| 124 | mutex_unlock(&rec_dir.dentry->d_inode->i_mutex); | ||
| 125 | } | 123 | } |
| 126 | 124 | ||
| 127 | int | 125 | int |
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); |
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index dc12f416a49f..a9cd507f8cd2 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h | |||
| @@ -96,6 +96,7 @@ struct fid { | |||
| 96 | * @fh_to_parent: find the implied object's parent and get a dentry for it | 96 | * @fh_to_parent: find the implied object's parent and get a dentry for it |
| 97 | * @get_name: find the name for a given inode in a given directory | 97 | * @get_name: find the name for a given inode in a given directory |
| 98 | * @get_parent: find the parent of a given directory | 98 | * @get_parent: find the parent of a given directory |
| 99 | * @commit_metadata: commit metadata changes to stable storage | ||
| 99 | * | 100 | * |
| 100 | * See Documentation/filesystems/nfs/Exporting for details on how to use | 101 | * See Documentation/filesystems/nfs/Exporting for details on how to use |
| 101 | * this interface correctly. | 102 | * this interface correctly. |
| @@ -137,6 +138,9 @@ struct fid { | |||
| 137 | * is also a directory. In the event that it cannot be found, or storage | 138 | * is also a directory. In the event that it cannot be found, or storage |
| 138 | * space cannot be allocated, a %ERR_PTR should be returned. | 139 | * space cannot be allocated, a %ERR_PTR should be returned. |
| 139 | * | 140 | * |
| 141 | * commit_metadata: | ||
| 142 | * @commit_metadata should commit metadata changes to stable storage. | ||
| 143 | * | ||
| 140 | * Locking rules: | 144 | * Locking rules: |
| 141 | * get_parent is called with child->d_inode->i_mutex down | 145 | * get_parent is called with child->d_inode->i_mutex down |
| 142 | * get_name is not (which is possibly inconsistent) | 146 | * get_name is not (which is possibly inconsistent) |
| @@ -152,6 +156,7 @@ struct export_operations { | |||
| 152 | int (*get_name)(struct dentry *parent, char *name, | 156 | int (*get_name)(struct dentry *parent, char *name, |
| 153 | struct dentry *child); | 157 | struct dentry *child); |
| 154 | struct dentry * (*get_parent)(struct dentry *child); | 158 | struct dentry * (*get_parent)(struct dentry *child); |
| 159 | int (*commit_metadata)(struct inode *inode); | ||
| 155 | }; | 160 | }; |
| 156 | 161 | ||
| 157 | extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, | 162 | extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, |
