diff options
author | Christoph Hellwig <hch@lst.de> | 2008-12-22 15:11:15 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2009-01-05 11:54:28 -0500 |
commit | 4c728ef583b3d82266584da5cb068294c09df31e (patch) | |
tree | 1252fa82b5a7cf60c0898c3da810228b4c34ebb3 /fs/sync.c | |
parent | 6110e3abbff8b785907d4db50240e63c1be726e3 (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>
Diffstat (limited to 'fs/sync.c')
-rw-r--r-- | fs/sync.c | 48 |
1 files changed, 37 insertions, 11 deletions
@@ -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 | ||
78 | long 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 | */ | ||
91 | int 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) | |||
104 | out: | 129 | out: |
105 | return ret; | 130 | return ret; |
106 | } | 131 | } |
132 | EXPORT_SYMBOL(vfs_fsync); | ||
107 | 133 | ||
108 | static long __do_fsync(unsigned int fd, int datasync) | 134 | static 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 | ||
121 | asmlinkage long sys_fsync(unsigned int fd) | 147 | asmlinkage long sys_fsync(unsigned int fd) |
122 | { | 148 | { |
123 | return __do_fsync(fd, 0); | 149 | return do_fsync(fd, 0); |
124 | } | 150 | } |
125 | 151 | ||
126 | asmlinkage long sys_fdatasync(unsigned int fd) | 152 | asmlinkage 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 | /* |