diff options
Diffstat (limited to 'fs/ext4/fsync.c')
-rw-r--r-- | fs/ext4/fsync.c | 38 |
1 files changed, 35 insertions, 3 deletions
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index ce66d2fe826c..da3bed3e0c29 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
@@ -151,6 +151,32 @@ static int ext4_sync_parent(struct inode *inode) | |||
151 | return ret; | 151 | return ret; |
152 | } | 152 | } |
153 | 153 | ||
154 | /** | ||
155 | * __sync_file - generic_file_fsync without the locking and filemap_write | ||
156 | * @inode: inode to sync | ||
157 | * @datasync: only sync essential metadata if true | ||
158 | * | ||
159 | * This is just generic_file_fsync without the locking. This is needed for | ||
160 | * nojournal mode to make sure this inodes data/metadata makes it to disk | ||
161 | * properly. The i_mutex should be held already. | ||
162 | */ | ||
163 | static int __sync_inode(struct inode *inode, int datasync) | ||
164 | { | ||
165 | int err; | ||
166 | int ret; | ||
167 | |||
168 | ret = sync_mapping_buffers(inode->i_mapping); | ||
169 | if (!(inode->i_state & I_DIRTY)) | ||
170 | return ret; | ||
171 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
172 | return ret; | ||
173 | |||
174 | err = sync_inode_metadata(inode, 1); | ||
175 | if (ret == 0) | ||
176 | ret = err; | ||
177 | return ret; | ||
178 | } | ||
179 | |||
154 | /* | 180 | /* |
155 | * akpm: A new design for ext4_sync_file(). | 181 | * akpm: A new design for ext4_sync_file(). |
156 | * | 182 | * |
@@ -165,7 +191,7 @@ static int ext4_sync_parent(struct inode *inode) | |||
165 | * i_mutex lock is held when entering and exiting this function | 191 | * i_mutex lock is held when entering and exiting this function |
166 | */ | 192 | */ |
167 | 193 | ||
168 | int ext4_sync_file(struct file *file, int datasync) | 194 | int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) |
169 | { | 195 | { |
170 | struct inode *inode = file->f_mapping->host; | 196 | struct inode *inode = file->f_mapping->host; |
171 | struct ext4_inode_info *ei = EXT4_I(inode); | 197 | struct ext4_inode_info *ei = EXT4_I(inode); |
@@ -178,15 +204,20 @@ int ext4_sync_file(struct file *file, int datasync) | |||
178 | 204 | ||
179 | trace_ext4_sync_file_enter(file, datasync); | 205 | trace_ext4_sync_file_enter(file, datasync); |
180 | 206 | ||
207 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
208 | if (ret) | ||
209 | return ret; | ||
210 | mutex_lock(&inode->i_mutex); | ||
211 | |||
181 | if (inode->i_sb->s_flags & MS_RDONLY) | 212 | if (inode->i_sb->s_flags & MS_RDONLY) |
182 | return 0; | 213 | goto out; |
183 | 214 | ||
184 | ret = ext4_flush_completed_IO(inode); | 215 | ret = ext4_flush_completed_IO(inode); |
185 | if (ret < 0) | 216 | if (ret < 0) |
186 | goto out; | 217 | goto out; |
187 | 218 | ||
188 | if (!journal) { | 219 | if (!journal) { |
189 | ret = generic_file_fsync(file, datasync); | 220 | ret = __sync_inode(inode, datasync); |
190 | if (!ret && !list_empty(&inode->i_dentry)) | 221 | if (!ret && !list_empty(&inode->i_dentry)) |
191 | ret = ext4_sync_parent(inode); | 222 | ret = ext4_sync_parent(inode); |
192 | goto out; | 223 | goto out; |
@@ -220,6 +251,7 @@ int ext4_sync_file(struct file *file, int datasync) | |||
220 | if (needs_barrier) | 251 | if (needs_barrier) |
221 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | 252 | blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); |
222 | out: | 253 | out: |
254 | mutex_unlock(&inode->i_mutex); | ||
223 | trace_ext4_sync_file_exit(inode, ret); | 255 | trace_ext4_sync_file_exit(inode, ret); |
224 | return ret; | 256 | return ret; |
225 | } | 257 | } |