diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-06 14:31:38 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-03-06 14:31:38 -0500 |
commit | 05c5cb31ec47cacf38db56d9efaa37ca9d473132 (patch) | |
tree | 03f900679819abd8700d5ea93c22e3a59d3af7ca /fs/nfsd/vfs.c | |
parent | 4582a30c2fdca5d2b40f63a20ea082b93230ff2b (diff) | |
parent | 4ea41e2de5bba756858bb40f964e3490b6d1a25c (diff) |
Merge branch 'for-2.6.34' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.34' of git://linux-nfs.org/~bfields/linux: (22 commits)
nfsd4: fix minor memory leak
svcrpc: treat uid's as unsigned
nfsd: ensure sockets are closed on error
Revert "sunrpc: move the close processing after do recvfrom method"
Revert "sunrpc: fix peername failed on closed listener"
sunrpc: remove unnecessary svc_xprt_put
NFSD: NFSv4 callback client should use RPC_TASK_SOFTCONN
xfs_export_operations.commit_metadata
commit_metadata export operation replacing nfsd_sync_dir
lockd: don't clear sm_monitored on nsm_reboot_lookup
lockd: release reference to nsm_handle in nlm_host_rebooted
nfsd: Use vfs_fsync_range() in nfsd_commit
NFSD: Create PF_INET6 listener in write_ports
SUNRPC: NFS kernel APIs shouldn't return ENOENT for "transport not found"
SUNRPC: Bury "#ifdef IPV6" in svc_create_xprt()
NFSD: Support AF_INET6 in svc_addsock() function
SUNRPC: Use rpc_pton() in ip_map_parse()
nfsd: 4.1 has an rfc number
nfsd41: Create the recovery entry for the NFSv4.1 client
nfsd: use vfs_fsync for non-directories
...
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r-- | fs/nfsd/vfs.c | 153 |
1 files changed, 73 insertions, 80 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 8eca17df4f63..a11b0e8678ee 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <linux/jhash.h> | 26 | #include <linux/jhash.h> |
27 | #include <linux/ima.h> | 27 | #include <linux/ima.h> |
28 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
29 | #include <linux/exportfs.h> | ||
30 | #include <linux/writeback.h> | ||
29 | 31 | ||
30 | #ifdef CONFIG_NFSD_V3 | 32 | #ifdef CONFIG_NFSD_V3 |
31 | #include "xdr3.h" | 33 | #include "xdr3.h" |
@@ -270,6 +272,32 @@ out: | |||
270 | return err; | 272 | return err; |
271 | } | 273 | } |
272 | 274 | ||
275 | /* | ||
276 | * Commit metadata changes to stable storage. | ||
277 | */ | ||
278 | static int | ||
279 | commit_metadata(struct svc_fh *fhp) | ||
280 | { | ||
281 | struct inode *inode = fhp->fh_dentry->d_inode; | ||
282 | const struct export_operations *export_ops = inode->i_sb->s_export_op; | ||
283 | int error = 0; | ||
284 | |||
285 | if (!EX_ISSYNC(fhp->fh_export)) | ||
286 | return 0; | ||
287 | |||
288 | if (export_ops->commit_metadata) { | ||
289 | error = export_ops->commit_metadata(inode); | ||
290 | } else { | ||
291 | struct writeback_control wbc = { | ||
292 | .sync_mode = WB_SYNC_ALL, | ||
293 | .nr_to_write = 0, /* metadata only */ | ||
294 | }; | ||
295 | |||
296 | error = sync_inode(inode, &wbc); | ||
297 | } | ||
298 | |||
299 | return error; | ||
300 | } | ||
273 | 301 | ||
274 | /* | 302 | /* |
275 | * Set various file attributes. | 303 | * Set various file attributes. |
@@ -767,43 +795,6 @@ nfsd_close(struct file *filp) | |||
767 | } | 795 | } |
768 | 796 | ||
769 | /* | 797 | /* |
770 | * Sync a file | ||
771 | * As this calls fsync (not fdatasync) there is no need for a write_inode | ||
772 | * after it. | ||
773 | */ | ||
774 | static inline int nfsd_dosync(struct file *filp, struct dentry *dp, | ||
775 | const struct file_operations *fop) | ||
776 | { | ||
777 | struct inode *inode = dp->d_inode; | ||
778 | int (*fsync) (struct file *, struct dentry *, int); | ||
779 | int err; | ||
780 | |||
781 | err = filemap_write_and_wait(inode->i_mapping); | ||
782 | if (err == 0 && fop && (fsync = fop->fsync)) | ||
783 | err = fsync(filp, dp, 0); | ||
784 | return err; | ||
785 | } | ||
786 | |||
787 | static int | ||
788 | nfsd_sync(struct file *filp) | ||
789 | { | ||
790 | int err; | ||
791 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
792 | dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name); | ||
793 | mutex_lock(&inode->i_mutex); | ||
794 | err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op); | ||
795 | mutex_unlock(&inode->i_mutex); | ||
796 | |||
797 | return err; | ||
798 | } | ||
799 | |||
800 | int | ||
801 | nfsd_sync_dir(struct dentry *dp) | ||
802 | { | ||
803 | return nfsd_dosync(NULL, dp, dp->d_inode->i_fop); | ||
804 | } | ||
805 | |||
806 | /* | ||
807 | * Obtain the readahead parameters for the file | 798 | * Obtain the readahead parameters for the file |
808 | * specified by (dev, ino). | 799 | * specified by (dev, ino). |
809 | */ | 800 | */ |
@@ -1006,7 +997,7 @@ static int wait_for_concurrent_writes(struct file *file) | |||
1006 | 997 | ||
1007 | if (inode->i_state & I_DIRTY) { | 998 | if (inode->i_state & I_DIRTY) { |
1008 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); | 999 | dprintk("nfsd: write sync %d\n", task_pid_nr(current)); |
1009 | err = nfsd_sync(file); | 1000 | err = vfs_fsync(file, file->f_path.dentry, 0); |
1010 | } | 1001 | } |
1011 | last_ino = inode->i_ino; | 1002 | last_ino = inode->i_ino; |
1012 | last_dev = inode->i_sb->s_dev; | 1003 | last_dev = inode->i_sb->s_dev; |
@@ -1154,8 +1145,9 @@ out: | |||
1154 | #ifdef CONFIG_NFSD_V3 | 1145 | #ifdef CONFIG_NFSD_V3 |
1155 | /* | 1146 | /* |
1156 | * Commit all pending writes to stable storage. | 1147 | * Commit all pending writes to stable storage. |
1157 | * Strictly speaking, we could sync just the indicated file region here, | 1148 | * |
1158 | * but there's currently no way we can ask the VFS to do so. | 1149 | * Note: we only guarantee that data that lies within the range specified |
1150 | * by the 'offset' and 'count' parameters will be synced. | ||
1159 | * | 1151 | * |
1160 | * Unfortunately we cannot lock the file to make sure we return full WCC | 1152 | * Unfortunately we cannot lock the file to make sure we return full WCC |
1161 | * data to the client, as locking happens lower down in the filesystem. | 1153 | * data to the client, as locking happens lower down in the filesystem. |
@@ -1165,23 +1157,32 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1165 | loff_t offset, unsigned long count) | 1157 | loff_t offset, unsigned long count) |
1166 | { | 1158 | { |
1167 | struct file *file; | 1159 | struct file *file; |
1168 | __be32 err; | 1160 | loff_t end = LLONG_MAX; |
1161 | __be32 err = nfserr_inval; | ||
1169 | 1162 | ||
1170 | if ((u64)count > ~(u64)offset) | 1163 | if (offset < 0) |
1171 | return nfserr_inval; | 1164 | goto out; |
1165 | if (count != 0) { | ||
1166 | end = offset + (loff_t)count - 1; | ||
1167 | if (end < offset) | ||
1168 | goto out; | ||
1169 | } | ||
1172 | 1170 | ||
1173 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); | 1171 | err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_WRITE, &file); |
1174 | if (err) | 1172 | if (err) |
1175 | return err; | 1173 | goto out; |
1176 | if (EX_ISSYNC(fhp->fh_export)) { | 1174 | if (EX_ISSYNC(fhp->fh_export)) { |
1177 | if (file->f_op && file->f_op->fsync) { | 1175 | int err2 = vfs_fsync_range(file, file->f_path.dentry, |
1178 | err = nfserrno(nfsd_sync(file)); | 1176 | offset, end, 0); |
1179 | } else { | 1177 | |
1178 | if (err2 != -EINVAL) | ||
1179 | err = nfserrno(err2); | ||
1180 | else | ||
1180 | err = nfserr_notsupp; | 1181 | err = nfserr_notsupp; |
1181 | } | ||
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | nfsd_close(file); | 1184 | nfsd_close(file); |
1185 | out: | ||
1185 | return err; | 1186 | return err; |
1186 | } | 1187 | } |
1187 | #endif /* CONFIG_NFSD_V3 */ | 1188 | #endif /* CONFIG_NFSD_V3 */ |
@@ -1334,12 +1335,14 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1334 | goto out_nfserr; | 1335 | goto out_nfserr; |
1335 | } | 1336 | } |
1336 | 1337 | ||
1337 | if (EX_ISSYNC(fhp->fh_export)) { | 1338 | err = nfsd_create_setattr(rqstp, resfhp, iap); |
1338 | err = nfserrno(nfsd_sync_dir(dentry)); | ||
1339 | write_inode_now(dchild->d_inode, 1); | ||
1340 | } | ||
1341 | 1339 | ||
1342 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); | 1340 | /* |
1341 | * nfsd_setattr already committed the child. Transactional filesystems | ||
1342 | * had a chance to commit changes for both parent and child | ||
1343 | * simultaneously making the following commit_metadata a noop. | ||
1344 | */ | ||
1345 | err2 = nfserrno(commit_metadata(fhp)); | ||
1343 | if (err2) | 1346 | if (err2) |
1344 | err = err2; | 1347 | err = err2; |
1345 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1348 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
@@ -1371,7 +1374,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1371 | struct dentry *dentry, *dchild = NULL; | 1374 | struct dentry *dentry, *dchild = NULL; |
1372 | struct inode *dirp; | 1375 | struct inode *dirp; |
1373 | __be32 err; | 1376 | __be32 err; |
1374 | __be32 err2; | ||
1375 | int host_err; | 1377 | int host_err; |
1376 | __u32 v_mtime=0, v_atime=0; | 1378 | __u32 v_mtime=0, v_atime=0; |
1377 | 1379 | ||
@@ -1466,11 +1468,6 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1466 | if (created) | 1468 | if (created) |
1467 | *created = 1; | 1469 | *created = 1; |
1468 | 1470 | ||
1469 | if (EX_ISSYNC(fhp->fh_export)) { | ||
1470 | err = nfserrno(nfsd_sync_dir(dentry)); | ||
1471 | /* setattr will sync the child (or not) */ | ||
1472 | } | ||
1473 | |||
1474 | nfsd_check_ignore_resizing(iap); | 1471 | nfsd_check_ignore_resizing(iap); |
1475 | 1472 | ||
1476 | if (createmode == NFS3_CREATE_EXCLUSIVE) { | 1473 | if (createmode == NFS3_CREATE_EXCLUSIVE) { |
@@ -1485,9 +1482,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1485 | } | 1482 | } |
1486 | 1483 | ||
1487 | set_attr: | 1484 | set_attr: |
1488 | err2 = nfsd_create_setattr(rqstp, resfhp, iap); | 1485 | err = nfsd_create_setattr(rqstp, resfhp, iap); |
1489 | if (err2) | 1486 | |
1490 | err = err2; | 1487 | /* |
1488 | * nfsd_setattr already committed the child (and possibly also the parent). | ||
1489 | */ | ||
1490 | if (!err) | ||
1491 | err = nfserrno(commit_metadata(fhp)); | ||
1491 | 1492 | ||
1492 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1493 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
1493 | /* | 1494 | /* |
@@ -1602,12 +1603,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
1602 | } | 1603 | } |
1603 | } else | 1604 | } else |
1604 | host_err = vfs_symlink(dentry->d_inode, dnew, path); | 1605 | host_err = vfs_symlink(dentry->d_inode, dnew, path); |
1605 | |||
1606 | if (!host_err) { | ||
1607 | if (EX_ISSYNC(fhp->fh_export)) | ||
1608 | host_err = nfsd_sync_dir(dentry); | ||
1609 | } | ||
1610 | err = nfserrno(host_err); | 1606 | err = nfserrno(host_err); |
1607 | if (!err) | ||
1608 | err = nfserrno(commit_metadata(fhp)); | ||
1611 | fh_unlock(fhp); | 1609 | fh_unlock(fhp); |
1612 | 1610 | ||
1613 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1611 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
@@ -1669,11 +1667,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, | |||
1669 | } | 1667 | } |
1670 | host_err = vfs_link(dold, dirp, dnew); | 1668 | host_err = vfs_link(dold, dirp, dnew); |
1671 | if (!host_err) { | 1669 | if (!host_err) { |
1672 | if (EX_ISSYNC(ffhp->fh_export)) { | 1670 | err = nfserrno(commit_metadata(ffhp)); |
1673 | err = nfserrno(nfsd_sync_dir(ddir)); | 1671 | if (!err) |
1674 | write_inode_now(dest, 1); | 1672 | err = nfserrno(commit_metadata(tfhp)); |
1675 | } | ||
1676 | err = 0; | ||
1677 | } else { | 1673 | } else { |
1678 | if (host_err == -EXDEV && rqstp->rq_vers == 2) | 1674 | if (host_err == -EXDEV && rqstp->rq_vers == 2) |
1679 | err = nfserr_acces; | 1675 | err = nfserr_acces; |
@@ -1769,10 +1765,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, | |||
1769 | goto out_dput_new; | 1765 | goto out_dput_new; |
1770 | 1766 | ||
1771 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); | 1767 | host_err = vfs_rename(fdir, odentry, tdir, ndentry); |
1772 | if (!host_err && EX_ISSYNC(tfhp->fh_export)) { | 1768 | if (!host_err) { |
1773 | host_err = nfsd_sync_dir(tdentry); | 1769 | host_err = commit_metadata(tfhp); |
1774 | if (!host_err) | 1770 | if (!host_err) |
1775 | host_err = nfsd_sync_dir(fdentry); | 1771 | host_err = commit_metadata(ffhp); |
1776 | } | 1772 | } |
1777 | 1773 | ||
1778 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); | 1774 | mnt_drop_write(ffhp->fh_export->ex_path.mnt); |
@@ -1853,12 +1849,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, | |||
1853 | 1849 | ||
1854 | dput(rdentry); | 1850 | dput(rdentry); |
1855 | 1851 | ||
1856 | if (host_err) | 1852 | if (!host_err) |
1857 | goto out_drop; | 1853 | host_err = commit_metadata(fhp); |
1858 | if (EX_ISSYNC(fhp->fh_export)) | ||
1859 | host_err = nfsd_sync_dir(dentry); | ||
1860 | 1854 | ||
1861 | out_drop: | ||
1862 | mnt_drop_write(fhp->fh_export->ex_path.mnt); | 1855 | mnt_drop_write(fhp->fh_export->ex_path.mnt); |
1863 | out_nfserr: | 1856 | out_nfserr: |
1864 | err = nfserrno(host_err); | 1857 | err = nfserrno(host_err); |