aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-03-06 14:31:38 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2010-03-06 14:31:38 -0500
commit05c5cb31ec47cacf38db56d9efaa37ca9d473132 (patch)
tree03f900679819abd8700d5ea93c22e3a59d3af7ca /fs/nfsd/vfs.c
parent4582a30c2fdca5d2b40f63a20ea082b93230ff2b (diff)
parent4ea41e2de5bba756858bb40f964e3490b6d1a25c (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.c153
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 */
278static int
279commit_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 */
774static 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
787static int
788nfsd_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
800int
801nfsd_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);
1185out:
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
1861out_drop:
1862 mnt_drop_write(fhp->fh_export->ex_path.mnt); 1855 mnt_drop_write(fhp->fh_export->ex_path.mnt);
1863out_nfserr: 1856out_nfserr:
1864 err = nfserrno(host_err); 1857 err = nfserrno(host_err);