1 ext4: move i_size,i_disksize update routines to helper function
3 From: Dmitry Monakhov <dmonakhov@openvz.org>
5 Cc: stable@vger.kernel.org # needed for bug fix patches
6 Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
7 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
9 fs/ext4/ext4.h | 16 ++++++++++++++++
10 fs/ext4/extents.c | 17 ++++-------------
11 fs/ext4/inode.c | 34 ++++++++--------------------------
12 3 files changed, 28 insertions(+), 39 deletions(-)
14 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
15 index 5b19760..0badae0 100644
18 @@ -2454,6 +2454,22 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
19 up_write(&EXT4_I(inode)->i_data_sem);
22 +/* Update i_size, i_disksize. Requires i_mutex to avoid races with truncate */
23 +static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize)
27 + if (newsize > inode->i_size) {
28 + i_size_write(inode, newsize);
31 + if (newsize > EXT4_I(inode)->i_disksize) {
32 + ext4_update_i_disksize(inode, newsize);
38 struct ext4_group_info {
39 unsigned long bb_state;
40 struct rb_root bb_free_root;
41 diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
42 index 76c2df3..f0e6934 100644
43 --- a/fs/ext4/extents.c
44 +++ b/fs/ext4/extents.c
45 @@ -4839,12 +4839,8 @@ static long ext4_zero_range(struct file *file, loff_t offset,
48 inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
51 - if (new_size > i_size_read(inode))
52 - i_size_write(inode, new_size);
53 - if (new_size > EXT4_I(inode)->i_disksize)
54 - ext4_update_i_disksize(inode, new_size);
55 + ext4_update_inode_size(inode, new_size);
58 * Mark that we allocate beyond EOF so the subsequent truncate
59 @@ -4886,7 +4882,6 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
64 unsigned int blkbits = inode->i_blkbits;
66 /* Return error if mode is not supported */
67 @@ -4945,15 +4940,11 @@ long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
71 - tv = inode->i_ctime = ext4_current_time(inode);
72 + inode->i_ctime = ext4_current_time(inode);
75 - if (new_size > i_size_read(inode)) {
76 - i_size_write(inode, new_size);
77 - inode->i_mtime = tv;
79 - if (new_size > EXT4_I(inode)->i_disksize)
80 - ext4_update_i_disksize(inode, new_size);
81 + if (ext4_update_inode_size(inode, new_size) & 0x1)
82 + inode->i_mtime = inode->i_ctime;
85 * Mark that we allocate beyond EOF so the subsequent truncate
86 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
87 index 367a60c..b1ddd93 100644
90 @@ -1055,27 +1055,11 @@ static int ext4_write_end(struct file *file,
92 copied = block_write_end(file, mapping, pos,
93 len, copied, page, fsdata);
96 - * No need to use i_size_read() here, the i_size
97 - * cannot change under us because we hole i_mutex.
99 - * But it's important to update i_size while still holding page lock:
100 + * it's important to update i_size while still holding page lock:
101 * page writeout could otherwise come in and zero beyond i_size.
103 - if (pos + copied > inode->i_size) {
104 - i_size_write(inode, pos + copied);
105 - i_size_changed = 1;
108 - if (pos + copied > EXT4_I(inode)->i_disksize) {
109 - /* We need to mark inode dirty even if
110 - * new_i_size is less that inode->i_size
111 - * but greater than i_disksize. (hint delalloc)
113 - ext4_update_i_disksize(inode, (pos + copied));
114 - i_size_changed = 1;
116 + i_size_changed = ext4_update_inode_size(inode, pos + copied);
118 page_cache_release(page);
120 @@ -1123,7 +1107,7 @@ static int ext4_journalled_write_end(struct file *file,
125 + int size_changed = 0;
127 trace_ext4_journalled_write_end(inode, pos, len, copied);
128 from = pos & (PAGE_CACHE_SIZE - 1);
129 @@ -1146,20 +1130,18 @@ static int ext4_journalled_write_end(struct file *file,
131 SetPageUptodate(page);
133 - new_i_size = pos + copied;
134 - if (new_i_size > inode->i_size)
135 - i_size_write(inode, pos+copied);
136 + size_changed = ext4_update_inode_size(inode, pos + copied);
137 ext4_set_inode_state(inode, EXT4_STATE_JDATA);
138 EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid;
139 - if (new_i_size > EXT4_I(inode)->i_disksize) {
140 - ext4_update_i_disksize(inode, new_i_size);
142 + page_cache_release(page);
144 + if (size_changed) {
145 ret2 = ext4_mark_inode_dirty(handle, inode);
151 - page_cache_release(page);
152 if (pos + len > inode->i_size && ext4_can_truncate(inode))
153 /* if we have allocated more blocks and copied
154 * less. We will have blocks allocated outside