Fix bug in the original bug of the patch
[ext4-patch-queue.git] / factor-out-xattr-moving
blob4daa1d9920e594270393691a325e9695506a6f2d
1 ext4: factor out xattr moving
3 From: Jan Kara <jack@suse.cz>
5 Factor out function for moving xattrs from inode into external xattr
6 block from ext4_expand_extra_isize_ea(). That function is already quite
7 long and factoring out this rather standalone functionality helps
8 readability.
10 Signed-off-by: Jan Kara <jack@suse.cz>
11 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
12 ---
13  fs/ext4/xattr.c | 159 ++++++++++++++++++++++++++++++--------------------------
14  1 file changed, 85 insertions(+), 74 deletions(-)
16 diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
17 index 82b025c977fc..8f582ae1032d 100644
18 --- a/fs/ext4/xattr.c
19 +++ b/fs/ext4/xattr.c
20 @@ -1340,6 +1340,84 @@ static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry,
21  }
23  /*
24 + * Move xattr pointed to by 'entry' from inode into external xattr block
25 + */
26 +static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode,
27 +                                   struct ext4_inode *raw_inode,
28 +                                   struct ext4_xattr_entry *entry)
30 +       struct ext4_xattr_ibody_find *is = NULL;
31 +       struct ext4_xattr_block_find *bs = NULL;
32 +       char *buffer = NULL, *b_entry_name = NULL;
33 +       size_t value_offs, value_size;
34 +       struct ext4_xattr_info i = {
35 +               .value = NULL,
36 +               .value_len = 0,
37 +               .name_index = entry->e_name_index,
38 +       };
39 +       struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode);
40 +       int error;
42 +       value_offs = le16_to_cpu(entry->e_value_offs);
43 +       value_size = le32_to_cpu(entry->e_value_size);
45 +       is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
46 +       bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
47 +       buffer = kmalloc(value_size, GFP_NOFS);
48 +       b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
49 +       if (!is || !bs || !buffer || !b_entry_name) {
50 +               error = -ENOMEM;
51 +               goto out;
52 +       }
54 +       is->s.not_found = -ENODATA;
55 +       bs->s.not_found = -ENODATA;
56 +       is->iloc.bh = NULL;
57 +       bs->bh = NULL;
59 +       /* Save the entry name and the entry value */
60 +       memcpy(buffer, (void *)IFIRST(header) + value_offs, value_size);
61 +       memcpy(b_entry_name, entry->e_name, entry->e_name_len);
62 +       b_entry_name[entry->e_name_len] = '\0';
63 +       i.name = b_entry_name;
65 +       error = ext4_get_inode_loc(inode, &is->iloc);
66 +       if (error)
67 +               goto out;
69 +       error = ext4_xattr_ibody_find(inode, &i, is);
70 +       if (error)
71 +               goto out;
73 +       /* Remove the chosen entry from the inode */
74 +       error = ext4_xattr_ibody_set(handle, inode, &i, is);
75 +       if (error)
76 +               goto out;
78 +       i.name = b_entry_name;
79 +       i.value = buffer;
80 +       i.value_len = value_size;
81 +       error = ext4_xattr_block_find(inode, &i, bs);
82 +       if (error)
83 +               goto out;
85 +       /* Add entry which was removed from the inode into the block */
86 +       error = ext4_xattr_block_set(handle, inode, &i, bs);
87 +       if (error)
88 +               goto out;
89 +       error = 0;
90 +out:
91 +       kfree(b_entry_name);
92 +       kfree(buffer);
93 +       if (is)
94 +               brelse(is->iloc.bh);
95 +       kfree(is);
96 +       kfree(bs);
98 +       return error;
102   * Expand an inode by new_extra_isize bytes when EAs are present.
103   * Returns 0 on success or negative error number on failure.
104   */
105 @@ -1349,9 +1427,6 @@ int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize,
106         struct ext4_xattr_ibody_header *header;
107         struct ext4_xattr_entry *entry, *last, *first;
108         struct buffer_head *bh = NULL;
109 -       struct ext4_xattr_ibody_find *is = NULL;
110 -       struct ext4_xattr_block_find *bs = NULL;
111 -       char *buffer = NULL, *b_entry_name = NULL;
112         size_t min_offs;
113         size_t ifree, bfree;
114         int total_ino;
115 @@ -1427,27 +1502,11 @@ retry:
116         }
118         while (isize_diff > ifree) {
119 -               size_t offs, size, entry_size;
120                 struct ext4_xattr_entry *small_entry = NULL;
121 -               struct ext4_xattr_info i = {
122 -                       .value = NULL,
123 -                       .value_len = 0,
124 -               };
125 -               unsigned int total_size;  /* EA entry size + value size */
126 +               unsigned int entry_size;        /* EA entry size */
127 +               unsigned int total_size;        /* EA entry size + value size */
128                 unsigned int min_total_size = ~0U;
130 -               is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS);
131 -               bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS);
132 -               if (!is || !bs) {
133 -                       error = -ENOMEM;
134 -                       goto cleanup;
135 -               }
137 -               is->s.not_found = -ENODATA;
138 -               bs->s.not_found = -ENODATA;
139 -               is->iloc.bh = NULL;
140 -               bs->bh = NULL;
142                 last = IFIRST(header);
143                 /* Find the entry best suited to be pushed into EA block */
144                 entry = NULL;
145 @@ -1474,8 +1533,6 @@ retry:
146                                     s_min_extra_isize) {
147                                         tried_min_extra_isize++;
148                                         new_extra_isize = s_min_extra_isize;
149 -                                       kfree(is); is = NULL;
150 -                                       kfree(bs); bs = NULL;
151                                         brelse(bh);
152                                         goto retry;
153                                 }
154 @@ -1483,58 +1540,18 @@ retry:
155                                 goto cleanup;
156                         }
157                 }
158 -               offs = le16_to_cpu(entry->e_value_offs);
159 -               size = le32_to_cpu(entry->e_value_size);
160 -               entry_size = EXT4_XATTR_LEN(entry->e_name_len);
161 -               total_size = entry_size + EXT4_XATTR_SIZE(size);
162 -               i.name_index = entry->e_name_index,
163 -               buffer = kmalloc(EXT4_XATTR_SIZE(size), GFP_NOFS);
164 -               b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS);
165 -               if (!buffer || !b_entry_name) {
166 -                       error = -ENOMEM;
167 -                       goto cleanup;
168 -               }
169 -               /* Save the entry name and the entry value */
170 -               memcpy(buffer, (void *)IFIRST(header) + offs,
171 -                      EXT4_XATTR_SIZE(size));
172 -               memcpy(b_entry_name, entry->e_name, entry->e_name_len);
173 -               b_entry_name[entry->e_name_len] = '\0';
174 -               i.name = b_entry_name;
176 -               error = ext4_get_inode_loc(inode, &is->iloc);
177 -               if (error)
178 -                       goto cleanup;
180 -               error = ext4_xattr_ibody_find(inode, &i, is);
181 +               entry_size = EXT4_XATTR_LEN(entry->e_name_len);
182 +               total_size = entry_size +
183 +                       EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
184 +               error = ext4_xattr_move_to_block(handle, inode, raw_inode,
185 +                                                entry);
186                 if (error)
187                         goto cleanup;
189 -               /* Remove the chosen entry from the inode */
190 -               error = ext4_xattr_ibody_set(handle, inode, &i, is);
191 -               if (error)
192 -                       goto cleanup;
193                 total_ino -= entry_size;
194                 ifree += total_size;
195                 bfree -= total_size;
197 -               i.name = b_entry_name;
198 -               i.value = buffer;
199 -               i.value_len = size;
200 -               error = ext4_xattr_block_find(inode, &i, bs);
201 -               if (error)
202 -                       goto cleanup;
204 -               /* Add entry which was removed from the inode into the block */
205 -               error = ext4_xattr_block_set(handle, inode, &i, bs);
206 -               if (error)
207 -                       goto cleanup;
208 -               kfree(b_entry_name);
209 -               kfree(buffer);
210 -               b_entry_name = NULL;
211 -               buffer = NULL;
212 -               brelse(is->iloc.bh);
213 -               kfree(is);
214 -               kfree(bs);
215         }
217  shift:
218 @@ -1552,12 +1569,6 @@ out:
219         return 0;
221  cleanup:
222 -       kfree(b_entry_name);
223 -       kfree(buffer);
224 -       if (is)
225 -               brelse(is->iloc.bh);
226 -       kfree(is);
227 -       kfree(bs);
228         brelse(bh);
229         /*
230          * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode
231 -- 
232 2.6.6
235 To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
236 the body of a message to majordomo@vger.kernel.org
237 More majordomo info at  http://vger.kernel.org/majordomo-info.html