aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2008-12-22 15:11:15 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2009-01-05 11:54:28 -0500
commit4c728ef583b3d82266584da5cb068294c09df31e (patch)
tree1252fa82b5a7cf60c0898c3da810228b4c34ebb3
parent6110e3abbff8b785907d4db50240e63c1be726e3 (diff)
add a vfs_fsync helper
Fsync currently has a fdatawrite/fdatawait pair around the method call, and a mutex_lock/unlock of the inode mutex. All callers of fsync have to duplicate this, but we have a few and most of them don't quite get it right. This patch adds a new vfs_fsync that takes care of this. It's a little more complicated as usual as ->fsync might get a NULL file pointer and just a dentry from nfsd, but otherwise gets afile and we want to take the mapping and file operations from it when it is there. Notes on the fsync callers: - ecryptfs wasn't calling filemap_fdatawrite / filemap_fdatawait on the lower file - coda wasn't calling filemap_fdatawrite / filemap_fdatawait on the host file, and returning 0 when ->fsync was missing - shm wasn't calling either filemap_fdatawrite / filemap_fdatawait nor taking i_mutex. Now given that shared memory doesn't have disk backing not doing anything in fsync seems fine and I left it out of the vfs_fsync conversion for now, but in that case we might just not pass it through to the lower file at all but just call the no-op simple_sync_file directly. [and now actually export vfs_fsync] Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r--drivers/usb/gadget/file_storage.c18
-rw-r--r--fs/coda/file.c12
-rw-r--r--fs/ecryptfs/file.c15
-rw-r--r--fs/nfsd/vfs.c35
-rw-r--r--fs/sync.c48
-rw-r--r--include/linux/fs.h2
-rw-r--r--mm/msync.c2
7 files changed, 48 insertions, 84 deletions
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index c4e62a6297d7..2e71368f45b4 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1863,26 +1863,10 @@ static int do_write(struct fsg_dev *fsg)
1863static int fsync_sub(struct lun *curlun) 1863static int fsync_sub(struct lun *curlun)
1864{ 1864{
1865 struct file *filp = curlun->filp; 1865 struct file *filp = curlun->filp;
1866 struct inode *inode;
1867 int rc, err;
1868 1866
1869 if (curlun->ro || !filp) 1867 if (curlun->ro || !filp)
1870 return 0; 1868 return 0;
1871 if (!filp->f_op->fsync) 1869 return vfs_fsync(filp, filp->f_path.dentry, 1);
1872 return -EINVAL;
1873
1874 inode = filp->f_path.dentry->d_inode;
1875 mutex_lock(&inode->i_mutex);
1876 rc = filemap_fdatawrite(inode->i_mapping);
1877 err = filp->f_op->fsync(filp, filp->f_path.dentry, 1);
1878 if (!rc)
1879 rc = err;
1880 err = filemap_fdatawait(inode->i_mapping);
1881 if (!rc)
1882 rc = err;
1883 mutex_unlock(&inode->i_mutex);
1884 VLDBG(curlun, "fdatasync -> %d\n", rc);
1885 return rc;
1886} 1870}
1887 1871
1888static void fsync_all(struct fsg_dev *fsg) 1872static void fsync_all(struct fsg_dev *fsg)
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 466303db2df6..6a347fbc998a 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -201,8 +201,7 @@ int coda_release(struct inode *coda_inode, struct file *coda_file)
201int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync) 201int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
202{ 202{
203 struct file *host_file; 203 struct file *host_file;
204 struct dentry *host_dentry; 204 struct inode *coda_inode = coda_dentry->d_inode;
205 struct inode *host_inode, *coda_inode = coda_dentry->d_inode;
206 struct coda_file_info *cfi; 205 struct coda_file_info *cfi;
207 int err = 0; 206 int err = 0;
208 207
@@ -214,14 +213,7 @@ int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
214 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 213 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
215 host_file = cfi->cfi_container; 214 host_file = cfi->cfi_container;
216 215
217 if (host_file->f_op && host_file->f_op->fsync) { 216 err = vfs_fsync(host_file, host_file->f_path.dentry, datasync);
218 host_dentry = host_file->f_path.dentry;
219 host_inode = host_dentry->d_inode;
220 mutex_lock(&host_inode->i_mutex);
221 err = host_file->f_op->fsync(host_file, host_dentry, datasync);
222 mutex_unlock(&host_inode->i_mutex);
223 }
224
225 if ( !err && !datasync ) { 217 if ( !err && !datasync ) {
226 lock_kernel(); 218 lock_kernel();
227 err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); 219 err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index eb3dc4c7ac06..713834371229 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -275,18 +275,9 @@ static int ecryptfs_release(struct inode *inode, struct file *file)
275static int 275static int
276ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync) 276ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
277{ 277{
278 struct file *lower_file = ecryptfs_file_to_lower(file); 278 return vfs_fsync(ecryptfs_file_to_lower(file),
279 struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); 279 ecryptfs_dentry_to_lower(dentry),
280 struct inode *lower_inode = lower_dentry->d_inode; 280 datasync);
281 int rc = -EINVAL;
282
283 if (lower_inode->i_fop->fsync) {
284 mutex_lock(&lower_inode->i_mutex);
285 rc = lower_inode->i_fop->fsync(lower_file, lower_dentry,
286 datasync);
287 mutex_unlock(&lower_inode->i_mutex);
288 }
289 return rc;
290} 281}
291 282
292static int ecryptfs_fasync(int fd, struct file *file, int flag) 283static int ecryptfs_fasync(int fd, struct file *file, int flag)
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 5245a3965004..44aa92aba891 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -744,45 +744,16 @@ nfsd_close(struct file *filp)
744 fput(filp); 744 fput(filp);
745} 745}
746 746
747/*
748 * Sync a file
749 * As this calls fsync (not fdatasync) there is no need for a write_inode
750 * after it.
751 */
752static inline int nfsd_dosync(struct file *filp, struct dentry *dp,
753 const struct file_operations *fop)
754{
755 struct inode *inode = dp->d_inode;
756 int (*fsync) (struct file *, struct dentry *, int);
757 int err;
758
759 err = filemap_fdatawrite(inode->i_mapping);
760 if (err == 0 && fop && (fsync = fop->fsync))
761 err = fsync(filp, dp, 0);
762 if (err == 0)
763 err = filemap_fdatawait(inode->i_mapping);
764
765 return err;
766}
767
768
769static int 747static int
770nfsd_sync(struct file *filp) 748nfsd_sync(struct file *filp)
771{ 749{
772 int err; 750 return vfs_fsync(filp, filp->f_path.dentry, 0);
773 struct inode *inode = filp->f_path.dentry->d_inode;
774 dprintk("nfsd: sync file %s\n", filp->f_path.dentry->d_name.name);
775 mutex_lock(&inode->i_mutex);
776 err=nfsd_dosync(filp, filp->f_path.dentry, filp->f_op);
777 mutex_unlock(&inode->i_mutex);
778
779 return err;
780} 751}
781 752
782int 753int
783nfsd_sync_dir(struct dentry *dp) 754nfsd_sync_dir(struct dentry *dentry)
784{ 755{
785 return nfsd_dosync(NULL, dp, dp->d_inode->i_fop); 756 return vfs_fsync(NULL, dentry, 0);
786} 757}
787 758
788/* 759/*
diff --git a/fs/sync.c b/fs/sync.c
index 2967562d416f..0921d6d4b5e6 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -75,14 +75,39 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
75 return ret; 75 return ret;
76} 76}
77 77
78long do_fsync(struct file *file, int datasync) 78/**
79 * vfs_fsync - perform a fsync or fdatasync on a file
80 * @file: file to sync
81 * @dentry: dentry of @file
82 * @data: only perform a fdatasync operation
83 *
84 * Write back data and metadata for @file to disk. If @datasync is
85 * set only metadata needed to access modified file data is written.
86 *
87 * In case this function is called from nfsd @file may be %NULL and
88 * only @dentry is set. This can only happen when the filesystem
89 * implements the export_operations API.
90 */
91int vfs_fsync(struct file *file, struct dentry *dentry, int datasync)
79{ 92{
80 int ret; 93 const struct file_operations *fop;
81 int err; 94 struct address_space *mapping;
82 struct address_space *mapping = file->f_mapping; 95 int err, ret;
96
97 /*
98 * Get mapping and operations from the file in case we have
99 * as file, or get the default values for them in case we
100 * don't have a struct file available. Damn nfsd..
101 */
102 if (file) {
103 mapping = file->f_mapping;
104 fop = file->f_op;
105 } else {
106 mapping = dentry->d_inode->i_mapping;
107 fop = dentry->d_inode->i_fop;
108 }
83 109
84 if (!file->f_op || !file->f_op->fsync) { 110 if (!fop || !fop->fsync) {
85 /* Why? We can still call filemap_fdatawrite */
86 ret = -EINVAL; 111 ret = -EINVAL;
87 goto out; 112 goto out;
88 } 113 }
@@ -94,7 +119,7 @@ long do_fsync(struct file *file, int datasync)
94 * livelocks in fsync_buffers_list(). 119 * livelocks in fsync_buffers_list().
95 */ 120 */
96 mutex_lock(&mapping->host->i_mutex); 121 mutex_lock(&mapping->host->i_mutex);
97 err = file->f_op->fsync(file, file->f_path.dentry, datasync); 122 err = fop->fsync(file, dentry, datasync);
98 if (!ret) 123 if (!ret)
99 ret = err; 124 ret = err;
100 mutex_unlock(&mapping->host->i_mutex); 125 mutex_unlock(&mapping->host->i_mutex);
@@ -104,15 +129,16 @@ long do_fsync(struct file *file, int datasync)
104out: 129out:
105 return ret; 130 return ret;
106} 131}
132EXPORT_SYMBOL(vfs_fsync);
107 133
108static long __do_fsync(unsigned int fd, int datasync) 134static int do_fsync(unsigned int fd, int datasync)
109{ 135{
110 struct file *file; 136 struct file *file;
111 int ret = -EBADF; 137 int ret = -EBADF;
112 138
113 file = fget(fd); 139 file = fget(fd);
114 if (file) { 140 if (file) {
115 ret = do_fsync(file, datasync); 141 ret = vfs_fsync(file, file->f_path.dentry, datasync);
116 fput(file); 142 fput(file);
117 } 143 }
118 return ret; 144 return ret;
@@ -120,12 +146,12 @@ static long __do_fsync(unsigned int fd, int datasync)
120 146
121asmlinkage long sys_fsync(unsigned int fd) 147asmlinkage long sys_fsync(unsigned int fd)
122{ 148{
123 return __do_fsync(fd, 0); 149 return do_fsync(fd, 0);
124} 150}
125 151
126asmlinkage long sys_fdatasync(unsigned int fd) 152asmlinkage long sys_fdatasync(unsigned int fd)
127{ 153{
128 return __do_fsync(fd, 1); 154 return do_fsync(fd, 1);
129} 155}
130 156
131/* 157/*
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e2170ee21e18..9ad9eac9eb0c 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1827,7 +1827,7 @@ extern int __filemap_fdatawrite_range(struct address_space *mapping,
1827extern int filemap_fdatawrite_range(struct address_space *mapping, 1827extern int filemap_fdatawrite_range(struct address_space *mapping,
1828 loff_t start, loff_t end); 1828 loff_t start, loff_t end);
1829 1829
1830extern long do_fsync(struct file *file, int datasync); 1830extern int vfs_fsync(struct file *file, struct dentry *dentry, int datasync);
1831extern void sync_supers(void); 1831extern void sync_supers(void);
1832extern void sync_filesystems(int wait); 1832extern void sync_filesystems(int wait);
1833extern void __fsync_super(struct super_block *sb); 1833extern void __fsync_super(struct super_block *sb);
diff --git a/mm/msync.c b/mm/msync.c
index 144a7570535d..07dae08cf31c 100644
--- a/mm/msync.c
+++ b/mm/msync.c
@@ -82,7 +82,7 @@ asmlinkage long sys_msync(unsigned long start, size_t len, int flags)
82 (vma->vm_flags & VM_SHARED)) { 82 (vma->vm_flags & VM_SHARED)) {
83 get_file(file); 83 get_file(file);
84 up_read(&mm->mmap_sem); 84 up_read(&mm->mmap_sem);
85 error = do_fsync(file, 0); 85 error = vfs_fsync(file, file->f_path.dentry, 0);
86 fput(file); 86 fput(file);
87 if (error || start >= end) 87 if (error || start >= end)
88 goto out; 88 goto out;