summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Monakhov <dmonakhov@openvz.org>2014-08-23 17:48:28 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-09-05 16:36:38 -0700
commit43fc7fe25e51c6e9c22b872292cf2327a0fd37a6 (patch)
treeab49d0b87481da811efbd567737cbdba6210e517
parent3099fab527ba36c6ddf309db16108fe65225239e (diff)
ext4: move i_size,i_disksize update routines to helper function
commit 4631dbf677ded0419fee35ca7408285dabfaef1a upstream. Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--fs/ext4/ext4.h16
-rw-r--r--fs/ext4/extents.c17
-rw-r--r--fs/ext4/inode.c34
3 files changed, 28 insertions, 39 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 6ecd11ade40f..1bbe7c315138 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -2453,6 +2453,22 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
up_write(&EXT4_I(inode)->i_data_sem);
}
+/* Update i_size, i_disksize. Requires i_mutex to avoid races with truncate */
+static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize)
+{
+ int changed = 0;
+
+ if (newsize > inode->i_size) {
+ i_size_write(inode, newsize);
+ changed = 1;
+ }
+ if (newsize > EXT4_I(inode)->i_disksize) {
+ ext4_update_i_disksize(inode, newsize);
+ changed |= 2;
+ }
+ return changed;
+}
+
struct ext4_group_info {
unsigned long bb_state;
struct rb_root bb_free_root;
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 4da228a0e6d0..b9a7bd3d561e 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -4838,12 +4838,8 @@ static long ext4_zero_range(struct file *file, loff_t offset,
}
inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
-
if (new_size) {
- if (new_size > i_size_read(inode))
- i_size_write(inode, new_size);
- if (new_size > EXT4_I(inode)->i_disksize)
- ext4_update_i_disksize(inode, new_size);
+ ext4_update_inode_size(inode, new_size);
} else {
/*
* Mark that we allocate beyond EOF so the subsequent truncate
@@ -4885,7 +4881,6 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
int ret = 0;
int flags;
ext4_lblk_t lblk;
- struct timespec tv;
unsigned int blkbits = inode->i_blkbits;
/* Return error if mode is not supported */
@@ -4944,15 +4939,11 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
if (IS_ERR(handle))
goto out;
- tv = inode->i_ctime = ext4_current_time(inode);
+ inode->i_ctime = ext4_current_time(inode);
if (new_size) {
- if (new_size > i_size_read(inode)) {
- i_size_write(inode, new_size);
- inode->i_mtime = tv;
- }
- if (new_size > EXT4_I(inode)->i_disksize)
- ext4_update_i_disksize(inode, new_size);
+ if (ext4_update_inode_size(inode, new_size) & 0x1)
+ inode->i_mtime = inode->i_ctime;
} else {
/*
* Mark that we allocate beyond EOF so the subsequent truncate
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index b431a63c452d..962bc77a1324 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1092,27 +1092,11 @@ static int ext4_write_end(struct file *file,
} else
copied = block_write_end(file, mapping, pos,
len, copied, page, fsdata);
-
/*
- * No need to use i_size_read() here, the i_size
- * cannot change under us because we hole i_mutex.
- *
- * But it's important to update i_size while still holding page lock:
+ * it's important to update i_size while still holding page lock:
* page writeout could otherwise come in and zero beyond i_size.
*/
- if (pos + copied > inode->i_size) {
- i_size_write(inode, pos + copied);
- i_size_changed = 1;
- }
-
- if (pos + copied > EXT4_I(inode)->i_disksize) {
- /* We need to mark inode dirty even if
- * new_i_size is less that inode->i_size
- * but greater than i_disksize. (hint delalloc)
- */
- ext4_update_i_disksize(inode, (pos + copied));
- i_size_changed = 1;
- }
+ i_size_changed = ext4_update_inode_size(inode, pos + copied);
unlock_page(page);
page_cache_release(page);
@@ -1160,7 +1144,7 @@ static int ext4_journalled_write_end(struct file *file,
int ret = 0, ret2;
int partial = 0;
unsigned from, to;
- loff_t new_i_size;
+ int size_changed = 0;
trace_ext4_journalled_write_end(inode, pos, len, copied);
from = pos & (PAGE_CACHE_SIZE - 1);
@@ -1183,20 +1167,18 @@ static int ext4_journalled_write_end(struct file *file,
if (!partial)
SetPageUptodate(page);
}
- new_i_size = pos + copied;
- if (new_i_size > inode->i_size)
- i_size_write(inode, pos+copied);
+ size_changed = ext4_update_inode_size(inode, pos + copied);
ext4_set_inode_state(inode, EXT4_STATE_JDATA);
EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid;
- if (new_i_size > EXT4_I(inode)->i_disksize) {
- ext4_update_i_disksize(inode, new_i_size);
+ unlock_page(page);
+ page_cache_release(page);
+
+ if (size_changed) {
ret2 = ext4_mark_inode_dirty(handle, inode);
if (!ret)
ret = ret2;
}
- unlock_page(page);
- page_cache_release(page);
if (pos + len > inode->i_size && ext4_can_truncate(inode))
/* if we have allocated more blocks and copied
* less. We will have blocks allocated outside