aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorTao Ma <boyu.mt@taobao.com>2012-12-10 14:04:46 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-12-10 14:04:46 -0500
commit67cf5b09a46f72e048501b84996f2f77bc42e947 (patch)
treea03218e2d47fc2ea9875fbd245e5b7ec3985e25e /fs/ext4
parent879b38257bf2b6fa8406693a3b5b5a0649e7c594 (diff)
ext4: add the basic function for inline data support
Implement inline data with xattr. Now we use "system.data" to store xattr, and the xattr will be extended if the i_size is increased while we don't release the space during truncate. Signed-off-by: Tao Ma <boyu.mt@taobao.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/Makefile2
-rw-r--r--fs/ext4/ext4.h10
-rw-r--r--fs/ext4/inline.c466
-rw-r--r--fs/ext4/inode.c5
-rw-r--r--fs/ext4/xattr.h54
5 files changed, 534 insertions, 3 deletions
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 41f22be2ffa4..3d96d5698538 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -9,6 +9,6 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \
9 ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \ 9 ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \
10 mmp.o indirect.o extents_status.o 10 mmp.o indirect.o extents_status.o
11 11
12ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o 12ext4-$(CONFIG_EXT4_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o inline.o
13ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o 13ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o
14ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o 14ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 2e9ffa9100bb..c827e47d556c 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -402,6 +402,7 @@ struct flex_groups {
402#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ 402#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
403#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */ 403#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
404#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */ 404#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */
405#define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */
405#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ 406#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
406 407
407#define EXT4_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */ 408#define EXT4_FL_USER_VISIBLE 0x004BDFFF /* User visible flags */
@@ -458,6 +459,7 @@ enum {
458 EXT4_INODE_EXTENTS = 19, /* Inode uses extents */ 459 EXT4_INODE_EXTENTS = 19, /* Inode uses extents */
459 EXT4_INODE_EA_INODE = 21, /* Inode used for large EA */ 460 EXT4_INODE_EA_INODE = 21, /* Inode used for large EA */
460 EXT4_INODE_EOFBLOCKS = 22, /* Blocks allocated beyond EOF */ 461 EXT4_INODE_EOFBLOCKS = 22, /* Blocks allocated beyond EOF */
462 EXT4_INODE_INLINE_DATA = 28, /* Data in inode. */
461 EXT4_INODE_RESERVED = 31, /* reserved for ext4 lib */ 463 EXT4_INODE_RESERVED = 31, /* reserved for ext4 lib */
462}; 464};
463 465
@@ -504,6 +506,7 @@ static inline void ext4_check_flag_values(void)
504 CHECK_FLAG_VALUE(EXTENTS); 506 CHECK_FLAG_VALUE(EXTENTS);
505 CHECK_FLAG_VALUE(EA_INODE); 507 CHECK_FLAG_VALUE(EA_INODE);
506 CHECK_FLAG_VALUE(EOFBLOCKS); 508 CHECK_FLAG_VALUE(EOFBLOCKS);
509 CHECK_FLAG_VALUE(INLINE_DATA);
507 CHECK_FLAG_VALUE(RESERVED); 510 CHECK_FLAG_VALUE(RESERVED);
508} 511}
509 512
@@ -918,6 +921,10 @@ struct ext4_inode_info {
918 /* on-disk additional length */ 921 /* on-disk additional length */
919 __u16 i_extra_isize; 922 __u16 i_extra_isize;
920 923
924 /* Indicate the inline data space. */
925 u16 i_inline_off;
926 u16 i_inline_size;
927
921#ifdef CONFIG_QUOTA 928#ifdef CONFIG_QUOTA
922 /* quota space reservation, managed internally by quota code */ 929 /* quota space reservation, managed internally by quota code */
923 qsize_t i_reserved_quota; 930 qsize_t i_reserved_quota;
@@ -1376,6 +1383,7 @@ enum {
1376 EXT4_STATE_DELALLOC_RESERVED, /* blks already reserved for delalloc */ 1383 EXT4_STATE_DELALLOC_RESERVED, /* blks already reserved for delalloc */
1377 EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read 1384 EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read
1378 nolocking */ 1385 nolocking */
1386 EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */
1379}; 1387};
1380 1388
1381#define EXT4_INODE_BIT_FNS(name, field, offset) \ 1389#define EXT4_INODE_BIT_FNS(name, field, offset) \
@@ -1497,7 +1505,7 @@ static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
1497#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */ 1505#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */
1498#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */ 1506#define EXT4_FEATURE_INCOMPAT_BG_USE_META_CSUM 0x2000 /* use crc32c for bg */
1499#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ 1507#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
1500#define EXT4_FEATURE_INCOMPAT_INLINEDATA 0x8000 /* data in inode */ 1508#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
1501 1509
1502#define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR 1510#define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR
1503#define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ 1511#define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c
new file mode 100644
index 000000000000..bec68b364832
--- /dev/null
+++ b/fs/ext4/inline.c
@@ -0,0 +1,466 @@
1/*
2 * Copyright (c) 2012 Taobao.
3 * Written by Tao Ma <boyu.mt@taobao.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2.1 of the GNU Lesser General Public License
7 * as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14#include "ext4_jbd2.h"
15#include "ext4.h"
16#include "xattr.h"
17
18#define EXT4_XATTR_SYSTEM_DATA "data"
19#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS))
20
21int ext4_get_inline_size(struct inode *inode)
22{
23 if (EXT4_I(inode)->i_inline_off)
24 return EXT4_I(inode)->i_inline_size;
25
26 return 0;
27}
28
29static int get_max_inline_xattr_value_size(struct inode *inode,
30 struct ext4_iloc *iloc)
31{
32 struct ext4_xattr_ibody_header *header;
33 struct ext4_xattr_entry *entry;
34 struct ext4_inode *raw_inode;
35 int free, min_offs;
36
37 min_offs = EXT4_SB(inode->i_sb)->s_inode_size -
38 EXT4_GOOD_OLD_INODE_SIZE -
39 EXT4_I(inode)->i_extra_isize -
40 sizeof(struct ext4_xattr_ibody_header);
41
42 /*
43 * We need to subtract another sizeof(__u32) since an in-inode xattr
44 * needs an empty 4 bytes to indicate the gap between the xattr entry
45 * and the name/value pair.
46 */
47 if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR))
48 return EXT4_XATTR_SIZE(min_offs -
49 EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)) -
50 EXT4_XATTR_ROUND - sizeof(__u32));
51
52 raw_inode = ext4_raw_inode(iloc);
53 header = IHDR(inode, raw_inode);
54 entry = IFIRST(header);
55
56 /* Compute min_offs. */
57 for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
58 if (!entry->e_value_block && entry->e_value_size) {
59 size_t offs = le16_to_cpu(entry->e_value_offs);
60 if (offs < min_offs)
61 min_offs = offs;
62 }
63 }
64 free = min_offs -
65 ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32);
66
67 if (EXT4_I(inode)->i_inline_off) {
68 entry = (struct ext4_xattr_entry *)
69 ((void *)raw_inode + EXT4_I(inode)->i_inline_off);
70
71 free += le32_to_cpu(entry->e_value_size);
72 goto out;
73 }
74
75 free -= EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA));
76
77 if (free > EXT4_XATTR_ROUND)
78 free = EXT4_XATTR_SIZE(free - EXT4_XATTR_ROUND);
79 else
80 free = 0;
81
82out:
83 return free;
84}
85
86/*
87 * Get the maximum size we now can store in an inode.
88 * If we can't find the space for a xattr entry, don't use the space
89 * of the extents since we have no space to indicate the inline data.
90 */
91int ext4_get_max_inline_size(struct inode *inode)
92{
93 int error, max_inline_size;
94 struct ext4_iloc iloc;
95
96 if (EXT4_I(inode)->i_extra_isize == 0)
97 return 0;
98
99 error = ext4_get_inode_loc(inode, &iloc);
100 if (error) {
101 ext4_error_inode(inode, __func__, __LINE__, 0,
102 "can't get inode location %lu",
103 inode->i_ino);
104 return 0;
105 }
106
107 down_read(&EXT4_I(inode)->xattr_sem);
108 max_inline_size = get_max_inline_xattr_value_size(inode, &iloc);
109 up_read(&EXT4_I(inode)->xattr_sem);
110
111 brelse(iloc.bh);
112
113 if (!max_inline_size)
114 return 0;
115
116 return max_inline_size + EXT4_MIN_INLINE_DATA_SIZE;
117}
118
119int ext4_has_inline_data(struct inode *inode)
120{
121 return ext4_test_inode_flag(inode, EXT4_INODE_INLINE_DATA) &&
122 EXT4_I(inode)->i_inline_off;
123}
124
125/*
126 * this function does not take xattr_sem, which is OK because it is
127 * currently only used in a code path coming form ext4_iget, before
128 * the new inode has been unlocked
129 */
130int ext4_find_inline_data_nolock(struct inode *inode)
131{
132 struct ext4_xattr_ibody_find is = {
133 .s = { .not_found = -ENODATA, },
134 };
135 struct ext4_xattr_info i = {
136 .name_index = EXT4_XATTR_INDEX_SYSTEM,
137 .name = EXT4_XATTR_SYSTEM_DATA,
138 };
139 int error;
140
141 if (EXT4_I(inode)->i_extra_isize == 0)
142 return 0;
143
144 error = ext4_get_inode_loc(inode, &is.iloc);
145 if (error)
146 return error;
147
148 error = ext4_xattr_ibody_find(inode, &i, &is);
149 if (error)
150 goto out;
151
152 if (!is.s.not_found) {
153 EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here -
154 (void *)ext4_raw_inode(&is.iloc));
155 EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE +
156 le32_to_cpu(is.s.here->e_value_size);
157 ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
158 }
159out:
160 brelse(is.iloc.bh);
161 return error;
162}
163
164static int ext4_read_inline_data(struct inode *inode, void *buffer,
165 unsigned int len,
166 struct ext4_iloc *iloc)
167{
168 struct ext4_xattr_entry *entry;
169 struct ext4_xattr_ibody_header *header;
170 int cp_len = 0;
171 struct ext4_inode *raw_inode;
172
173 if (!len)
174 return 0;
175
176 BUG_ON(len > EXT4_I(inode)->i_inline_size);
177
178 cp_len = len < EXT4_MIN_INLINE_DATA_SIZE ?
179 len : EXT4_MIN_INLINE_DATA_SIZE;
180
181 raw_inode = ext4_raw_inode(iloc);
182 memcpy(buffer, (void *)(raw_inode->i_block), cp_len);
183
184 len -= cp_len;
185 buffer += cp_len;
186
187 if (!len)
188 goto out;
189
190 header = IHDR(inode, raw_inode);
191 entry = (struct ext4_xattr_entry *)((void *)raw_inode +
192 EXT4_I(inode)->i_inline_off);
193 len = min_t(unsigned int, len,
194 (unsigned int)le32_to_cpu(entry->e_value_size));
195
196 memcpy(buffer,
197 (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs), len);
198 cp_len += len;
199
200out:
201 return cp_len;
202}
203
204/*
205 * write the buffer to the inline inode.
206 * If 'create' is set, we don't need to do the extra copy in the xattr
207 * value since it is already handled by ext4_xattr_ibody_set. That saves
208 * us one memcpy.
209 */
210void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc,
211 void *buffer, loff_t pos, unsigned int len)
212{
213 struct ext4_xattr_entry *entry;
214 struct ext4_xattr_ibody_header *header;
215 struct ext4_inode *raw_inode;
216 int cp_len = 0;
217
218 BUG_ON(!EXT4_I(inode)->i_inline_off);
219 BUG_ON(pos + len > EXT4_I(inode)->i_inline_size);
220
221 raw_inode = ext4_raw_inode(iloc);
222 buffer += pos;
223
224 if (pos < EXT4_MIN_INLINE_DATA_SIZE) {
225 cp_len = pos + len > EXT4_MIN_INLINE_DATA_SIZE ?
226 EXT4_MIN_INLINE_DATA_SIZE - pos : len;
227 memcpy((void *)raw_inode->i_block + pos, buffer, cp_len);
228
229 len -= cp_len;
230 buffer += cp_len;
231 pos += cp_len;
232 }
233
234 if (!len)
235 return;
236
237 pos -= EXT4_MIN_INLINE_DATA_SIZE;
238 header = IHDR(inode, raw_inode);
239 entry = (struct ext4_xattr_entry *)((void *)raw_inode +
240 EXT4_I(inode)->i_inline_off);
241
242 memcpy((void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs) + pos,
243 buffer, len);
244}
245
246static int ext4_create_inline_data(handle_t *handle,
247 struct inode *inode, unsigned len)
248{
249 int error;
250 void *value = NULL;
251 struct ext4_xattr_ibody_find is = {
252 .s = { .not_found = -ENODATA, },
253 };
254 struct ext4_xattr_info i = {
255 .name_index = EXT4_XATTR_INDEX_SYSTEM,
256 .name = EXT4_XATTR_SYSTEM_DATA,
257 };
258
259 error = ext4_get_inode_loc(inode, &is.iloc);
260 if (error)
261 return error;
262
263 error = ext4_journal_get_write_access(handle, is.iloc.bh);
264 if (error)
265 goto out;
266
267 if (len > EXT4_MIN_INLINE_DATA_SIZE) {
268 value = (void *)empty_zero_page;
269 len -= EXT4_MIN_INLINE_DATA_SIZE;
270 } else {
271 value = "";
272 len = 0;
273 }
274
275 /* Insert the the xttr entry. */
276 i.value = value;
277 i.value_len = len;
278
279 error = ext4_xattr_ibody_find(inode, &i, &is);
280 if (error)
281 goto out;
282
283 BUG_ON(!is.s.not_found);
284
285 error = ext4_xattr_ibody_set(handle, inode, &i, &is);
286 if (error) {
287 if (error == -ENOSPC)
288 ext4_clear_inode_state(inode,
289 EXT4_STATE_MAY_INLINE_DATA);
290 goto out;
291 }
292
293 memset((void *)ext4_raw_inode(&is.iloc)->i_block,
294 0, EXT4_MIN_INLINE_DATA_SIZE);
295
296 EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here -
297 (void *)ext4_raw_inode(&is.iloc));
298 EXT4_I(inode)->i_inline_size = len + EXT4_MIN_INLINE_DATA_SIZE;
299 ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
300 ext4_set_inode_flag(inode, EXT4_INODE_INLINE_DATA);
301 get_bh(is.iloc.bh);
302 error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
303
304out:
305 brelse(is.iloc.bh);
306 return error;
307}
308
309static int ext4_update_inline_data(handle_t *handle, struct inode *inode,
310 unsigned int len)
311{
312 int error;
313 void *value = NULL;
314 struct ext4_xattr_ibody_find is = {
315 .s = { .not_found = -ENODATA, },
316 };
317 struct ext4_xattr_info i = {
318 .name_index = EXT4_XATTR_INDEX_SYSTEM,
319 .name = EXT4_XATTR_SYSTEM_DATA,
320 };
321
322 /* If the old space is ok, write the data directly. */
323 if (len <= EXT4_I(inode)->i_inline_size)
324 return 0;
325
326 error = ext4_get_inode_loc(inode, &is.iloc);
327 if (error)
328 return error;
329
330 error = ext4_xattr_ibody_find(inode, &i, &is);
331 if (error)
332 goto out;
333
334 BUG_ON(is.s.not_found);
335
336 len -= EXT4_MIN_INLINE_DATA_SIZE;
337 value = kzalloc(len, GFP_NOFS);
338 if (!value)
339 goto out;
340
341 error = ext4_xattr_ibody_get(inode, i.name_index, i.name,
342 value, len);
343 if (error == -ENODATA)
344 goto out;
345
346 error = ext4_journal_get_write_access(handle, is.iloc.bh);
347 if (error)
348 goto out;
349
350 /* Update the xttr entry. */
351 i.value = value;
352 i.value_len = len;
353
354 error = ext4_xattr_ibody_set(handle, inode, &i, &is);
355 if (error)
356 goto out;
357
358 EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here -
359 (void *)ext4_raw_inode(&is.iloc));
360 EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE +
361 le32_to_cpu(is.s.here->e_value_size);
362 ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
363 get_bh(is.iloc.bh);
364 error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
365
366out:
367 kfree(value);
368 brelse(is.iloc.bh);
369 return error;
370}
371
372int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
373 unsigned int len)
374{
375 int ret, size;
376 struct ext4_inode_info *ei = EXT4_I(inode);
377
378 if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA))
379 return -ENOSPC;
380
381 size = ext4_get_max_inline_size(inode);
382 if (size < len)
383 return -ENOSPC;
384
385 down_write(&EXT4_I(inode)->xattr_sem);
386
387 if (ei->i_inline_off)
388 ret = ext4_update_inline_data(handle, inode, len);
389 else
390 ret = ext4_create_inline_data(handle, inode, len);
391
392 up_write(&EXT4_I(inode)->xattr_sem);
393
394 return ret;
395}
396
397static int ext4_destroy_inline_data_nolock(handle_t *handle,
398 struct inode *inode)
399{
400 struct ext4_inode_info *ei = EXT4_I(inode);
401 struct ext4_xattr_ibody_find is = {
402 .s = { .not_found = 0, },
403 };
404 struct ext4_xattr_info i = {
405 .name_index = EXT4_XATTR_INDEX_SYSTEM,
406 .name = EXT4_XATTR_SYSTEM_DATA,
407 .value = NULL,
408 .value_len = 0,
409 };
410 int error;
411
412 if (!ei->i_inline_off)
413 return 0;
414
415 error = ext4_get_inode_loc(inode, &is.iloc);
416 if (error)
417 return error;
418
419 error = ext4_xattr_ibody_find(inode, &i, &is);
420 if (error)
421 goto out;
422
423 error = ext4_journal_get_write_access(handle, is.iloc.bh);
424 if (error)
425 goto out;
426
427 error = ext4_xattr_ibody_set(handle, inode, &i, &is);
428 if (error)
429 goto out;
430
431 memset((void *)ext4_raw_inode(&is.iloc)->i_block,
432 0, EXT4_MIN_INLINE_DATA_SIZE);
433
434 if (EXT4_HAS_INCOMPAT_FEATURE(inode->i_sb,
435 EXT4_FEATURE_INCOMPAT_EXTENTS)) {
436 if (S_ISDIR(inode->i_mode) ||
437 S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) {
438 ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS);
439 ext4_ext_tree_init(handle, inode);
440 }
441 }
442 ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA);
443
444 get_bh(is.iloc.bh);
445 error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
446
447 EXT4_I(inode)->i_inline_off = 0;
448 EXT4_I(inode)->i_inline_size = 0;
449 ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA);
450out:
451 brelse(is.iloc.bh);
452 if (error == -ENODATA)
453 error = 0;
454 return error;
455}
456
457int ext4_destroy_inline_data(handle_t *handle, struct inode *inode)
458{
459 int ret;
460
461 down_write(&EXT4_I(inode)->xattr_sem);
462 ret = ext4_destroy_inline_data_nolock(handle, inode);
463 up_write(&EXT4_I(inode)->xattr_sem);
464
465 return ret;
466}
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index befa005711a1..e23f114e2cfe 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -3706,8 +3706,10 @@ static inline void ext4_iget_extra_inode(struct inode *inode,
3706{ 3706{
3707 __le32 *magic = (void *)raw_inode + 3707 __le32 *magic = (void *)raw_inode +
3708 EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize; 3708 EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize;
3709 if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) 3709 if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) {
3710 ext4_set_inode_state(inode, EXT4_STATE_XATTR); 3710 ext4_set_inode_state(inode, EXT4_STATE_XATTR);
3711 ext4_find_inline_data_nolock(inode);
3712 }
3711} 3713}
3712 3714
3713struct inode *ext4_iget(struct super_block *sb, unsigned long ino) 3715struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
@@ -3780,6 +3782,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
3780 set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); 3782 set_nlink(inode, le16_to_cpu(raw_inode->i_links_count));
3781 3783
3782 ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ 3784 ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */
3785 ei->i_inline_off = 0;
3783 ei->i_dir_start_lookup = 0; 3786 ei->i_dir_start_lookup = 0;
3784 ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); 3787 ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
3785 /* We now have enough fields to check if the inode was active or not. 3788 /* We now have enough fields to check if the inode was active or not.
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 40ca7a6f5eec..7ae0d05156e3 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -21,6 +21,7 @@
21#define EXT4_XATTR_INDEX_TRUSTED 4 21#define EXT4_XATTR_INDEX_TRUSTED 4
22#define EXT4_XATTR_INDEX_LUSTRE 5 22#define EXT4_XATTR_INDEX_LUSTRE 5
23#define EXT4_XATTR_INDEX_SECURITY 6 23#define EXT4_XATTR_INDEX_SECURITY 6
24#define EXT4_XATTR_INDEX_SYSTEM 7
24 25
25struct ext4_xattr_header { 26struct ext4_xattr_header {
26 __le32 h_magic; /* magic number for identification */ 27 __le32 h_magic; /* magic number for identification */
@@ -125,6 +126,19 @@ extern int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
125 struct ext4_xattr_info *i, 126 struct ext4_xattr_info *i,
126 struct ext4_xattr_ibody_find *is); 127 struct ext4_xattr_ibody_find *is);
127 128
129extern int ext4_has_inline_data(struct inode *inode);
130extern int ext4_get_inline_size(struct inode *inode);
131extern int ext4_get_max_inline_size(struct inode *inode);
132extern int ext4_find_inline_data_nolock(struct inode *inode);
133extern void ext4_write_inline_data(struct inode *inode,
134 struct ext4_iloc *iloc,
135 void *buffer, loff_t pos,
136 unsigned int len);
137extern int ext4_prepare_inline_data(handle_t *handle, struct inode *inode,
138 unsigned int len);
139extern int ext4_init_inline_data(handle_t *handle, struct inode *inode,
140 unsigned int len);
141extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode);
128# else /* CONFIG_EXT4_FS_XATTR */ 142# else /* CONFIG_EXT4_FS_XATTR */
129 143
130static inline int 144static inline int
@@ -201,6 +215,46 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index,
201 return -EOPNOTSUPP; 215 return -EOPNOTSUPP;
202} 216}
203 217
218static inline int ext4_find_inline_data_nolock(struct inode *inode)
219{
220 return 0;
221}
222
223static inline int ext4_has_inline_data(struct inode *inode)
224{
225 return 0;
226}
227
228static inline int ext4_get_inline_size(struct inode *inode)
229{
230 return 0;
231}
232
233static inline int ext4_get_max_inline_size(struct inode *inode)
234{
235 return 0;
236}
237
238static inline void ext4_write_inline_data(struct inode *inode,
239 struct ext4_iloc *iloc,
240 void *buffer, loff_t pos,
241 unsigned int len)
242{
243 return;
244}
245
246static inline int ext4_init_inline_data(handle_t *handle,
247 struct inode *inode,
248 unsigned int len)
249{
250 return 0;
251}
252
253static inline int ext4_destroy_inline_data(handle_t *handle,
254 struct inode *inode)
255{
256 return 0;
257}
204# endif /* CONFIG_EXT4_FS_XATTR */ 258# endif /* CONFIG_EXT4_FS_XATTR */
205 259
206#ifdef CONFIG_EXT4_FS_SECURITY 260#ifdef CONFIG_EXT4_FS_SECURITY