]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/2.6.32.17/0015-ext4-Add-flag-to-files-with-blocks-intentionally-pas.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 2.6.32.17 / 0015-ext4-Add-flag-to-files-with-blocks-intentionally-pas.patch
CommitLineData
7d777456
GKH
1From 9d176d321904553ab92a5df99e25ccb268a5560e Mon Sep 17 00:00:00 2001
2From: Jiaying Zhang <jiayingz@google.com>
3Date: Sun, 30 May 2010 22:49:29 -0400
4Subject: ext4: Add flag to files with blocks intentionally past EOF
5
6commit c8d46e41bc744c8fa0092112af3942fcd46c8b18 upstream (as of v2.6.33-git11)
7
8fallocate() may potentially instantiate blocks past EOF, depending
9on the flags used when it is called.
10
11e2fsck currently has a test for blocks past i_size, and it
12sometimes trips up - noticeably on xfstests 013 which runs fsstress.
13
14This patch from Jiayang does fix it up - it (along with
15e2fsprogs updates and other patches recently from Aneesh) has
16survived many fsstress runs in a row.
17
18Signed-off-by: Eric Sandeen <sandeen@redhat.com>
19Signed-off-by: Jiaying Zhang <jiayingz@google.com>
20Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
21Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
22---
23 fs/ext4/ext4.h | 6 ++++--
24 fs/ext4/extents.c | 22 +++++++++++++++++++++-
25 fs/ext4/inode.c | 9 ++++++++-
26 fs/ext4/ioctl.c | 9 +++++++++
27 4 files changed, 42 insertions(+), 4 deletions(-)
28
29--- a/fs/ext4/ext4.h
30+++ b/fs/ext4/ext4.h
31@@ -284,10 +284,12 @@ struct flex_groups {
32 #define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
33 #define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
34 #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
35+#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
36+#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */
37 #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
38
39-#define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */
40-#define EXT4_FL_USER_MODIFIABLE 0x000B80FF /* User modifiable flags */
41+#define EXT4_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */
42+#define EXT4_FL_USER_MODIFIABLE 0x004B80FF /* User modifiable flags */
43
44 /* Flags that should be inherited by new inodes from their parent. */
45 #define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
46--- a/fs/ext4/extents.c
47+++ b/fs/ext4/extents.c
48@@ -3191,7 +3191,7 @@ int ext4_ext_get_blocks(handle_t *handle
49 {
50 struct ext4_ext_path *path = NULL;
51 struct ext4_extent_header *eh;
52- struct ext4_extent newex, *ex;
53+ struct ext4_extent newex, *ex, *last_ex;
54 ext4_fsblk_t newblock;
55 int err = 0, depth, ret, cache_type;
56 unsigned int allocated = 0;
57@@ -3372,6 +3372,19 @@ int ext4_ext_get_blocks(handle_t *handle
58 EXT4_STATE_DIO_UNWRITTEN);
59 }
60 }
61+
62+ if (unlikely(EXT4_I(inode)->i_flags & EXT4_EOFBLOCKS_FL)) {
63+ if (eh->eh_entries) {
64+ last_ex = EXT_LAST_EXTENT(eh);
65+ if (iblock + ar.len > le32_to_cpu(last_ex->ee_block)
66+ + ext4_ext_get_actual_len(last_ex))
67+ EXT4_I(inode)->i_flags &= ~EXT4_EOFBLOCKS_FL;
68+ } else {
69+ WARN_ON(eh->eh_entries == 0);
70+ ext4_error(inode->i_sb, __func__,
71+ "inode#%lu, eh->eh_entries = 0!", inode->i_ino);
72+ }
73+ }
74 err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
75 if (err) {
76 /* free data blocks we just allocated */
77@@ -3505,6 +3518,13 @@ static void ext4_falloc_update_inode(str
78 i_size_write(inode, new_size);
79 if (new_size > EXT4_I(inode)->i_disksize)
80 ext4_update_i_disksize(inode, new_size);
81+ } else {
82+ /*
83+ * Mark that we allocate beyond EOF so the subsequent truncate
84+ * can proceed even if the new size is the same as i_size.
85+ */
86+ if (new_size > i_size_read(inode))
87+ EXT4_I(inode)->i_flags |= EXT4_EOFBLOCKS_FL;
88 }
89
90 }
91--- a/fs/ext4/inode.c
92+++ b/fs/ext4/inode.c
93@@ -4490,6 +4490,8 @@ void ext4_truncate(struct inode *inode)
94 if (!ext4_can_truncate(inode))
95 return;
96
97+ EXT4_I(inode)->i_flags &= ~EXT4_EOFBLOCKS_FL;
98+
99 if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC))
100 ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE);
101
102@@ -5345,7 +5347,9 @@ int ext4_setattr(struct dentry *dentry,
103 }
104
105 if (S_ISREG(inode->i_mode) &&
106- attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
107+ attr->ia_valid & ATTR_SIZE &&
108+ (attr->ia_size < inode->i_size ||
109+ (EXT4_I(inode)->i_flags & EXT4_EOFBLOCKS_FL))) {
110 handle_t *handle;
111
112 handle = ext4_journal_start(inode, 3);
113@@ -5376,6 +5380,9 @@ int ext4_setattr(struct dentry *dentry,
114 goto err_out;
115 }
116 }
117+ /* ext4_truncate will clear the flag */
118+ if ((EXT4_I(inode)->i_flags & EXT4_EOFBLOCKS_FL))
119+ ext4_truncate(inode);
120 }
121
122 rc = inode_setattr(inode, attr);
123--- a/fs/ext4/ioctl.c
124+++ b/fs/ext4/ioctl.c
125@@ -92,6 +92,15 @@ long ext4_ioctl(struct file *filp, unsig
126 flags &= ~EXT4_EXTENTS_FL;
127 }
128
129+ if (flags & EXT4_EOFBLOCKS_FL) {
130+ /* we don't support adding EOFBLOCKS flag */
131+ if (!(oldflags & EXT4_EOFBLOCKS_FL)) {
132+ err = -EOPNOTSUPP;
133+ goto flags_out;
134+ }
135+ } else if (oldflags & EXT4_EOFBLOCKS_FL)
136+ ext4_truncate(inode);
137+
138 handle = ext4_journal_start(inode, 1);
139 if (IS_ERR(handle)) {
140 err = PTR_ERR(handle);