diff options
author | Andreas Dilger <andreas.dilger@intel.com> | 2017-06-21 21:10:32 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2017-06-21 21:10:32 -0400 |
commit | e50e5129f384ae282adebfb561189cdb19b81cee (patch) | |
tree | d386e2df251f3faa23af1236f8c129bb6ea25b9d /fs/ext4 | |
parent | e08ac99fa2a25626f573cfa377ef3ddedf2cfe8f (diff) |
ext4: xattr-in-inode support
Large xattr support is implemented for EXT4_FEATURE_INCOMPAT_EA_INODE.
If the size of an xattr value is larger than will fit in a single
external block, then the xattr value will be saved into the body
of an external xattr inode.
The also helps support a larger number of xattr, since only the headers
will be stored in the in-inode space or the single external block.
The inode is referenced from the xattr header via "e_value_inum",
which was formerly "e_value_block", but that field was never used.
The e_value_size still contains the xattr size so that listing
xattrs does not need to look up the inode if the data is not accessed.
struct ext4_xattr_entry {
__u8 e_name_len; /* length of name */
__u8 e_name_index; /* attribute name index */
__le16 e_value_offs; /* offset in disk block of value */
__le32 e_value_inum; /* inode in which value is stored */
__le32 e_value_size; /* size of attribute value */
__le32 e_hash; /* hash value of name and value */
char e_name[0]; /* attribute name */
};
The xattr inode is marked with the EXT4_EA_INODE_FL flag and also
holds a back-reference to the owning inode in its i_mtime field,
allowing the ext4/e2fsck to verify the correct inode is accessed.
[ Applied fix by Dan Carpenter to avoid freeing an ERR_PTR. ]
Lustre-Jira: https://jira.hpdd.intel.com/browse/LU-80
Lustre-bugzilla: https://bugzilla.lustre.org/show_bug.cgi?id=4424
Signed-off-by: Kalpak Shah <kalpak.shah@sun.com>
Signed-off-by: James Simmons <uja.ornl@gmail.com>
Signed-off-by: Andreas Dilger <andreas.dilger@intel.com>
Signed-off-by: Tahsin Erdogan <tahsin@google.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/ext4.h | 12 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 1 | ||||
-rw-r--r-- | fs/ext4/inline.c | 2 | ||||
-rw-r--r-- | fs/ext4/inode.c | 49 | ||||
-rw-r--r-- | fs/ext4/xattr.c | 563 | ||||
-rw-r--r-- | fs/ext4/xattr.h | 33 |
6 files changed, 604 insertions, 56 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index f17a4e7075be..41e26ad86fc3 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1797,6 +1797,7 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT) | |||
1797 | EXT4_FEATURE_INCOMPAT_EXTENTS| \ | 1797 | EXT4_FEATURE_INCOMPAT_EXTENTS| \ |
1798 | EXT4_FEATURE_INCOMPAT_64BIT| \ | 1798 | EXT4_FEATURE_INCOMPAT_64BIT| \ |
1799 | EXT4_FEATURE_INCOMPAT_FLEX_BG| \ | 1799 | EXT4_FEATURE_INCOMPAT_FLEX_BG| \ |
1800 | EXT4_FEATURE_INCOMPAT_EA_INODE| \ | ||
1800 | EXT4_FEATURE_INCOMPAT_MMP | \ | 1801 | EXT4_FEATURE_INCOMPAT_MMP | \ |
1801 | EXT4_FEATURE_INCOMPAT_INLINE_DATA | \ | 1802 | EXT4_FEATURE_INCOMPAT_INLINE_DATA | \ |
1802 | EXT4_FEATURE_INCOMPAT_ENCRYPT | \ | 1803 | EXT4_FEATURE_INCOMPAT_ENCRYPT | \ |
@@ -2231,6 +2232,12 @@ struct mmpd_data { | |||
2231 | #define EXT4_MMP_MAX_CHECK_INTERVAL 300UL | 2232 | #define EXT4_MMP_MAX_CHECK_INTERVAL 300UL |
2232 | 2233 | ||
2233 | /* | 2234 | /* |
2235 | * Maximum size of xattr attributes for FEATURE_INCOMPAT_EA_INODE 1Mb | ||
2236 | * This limit is arbitrary, but is reasonable for the xattr API. | ||
2237 | */ | ||
2238 | #define EXT4_XATTR_MAX_LARGE_EA_SIZE (1024 * 1024) | ||
2239 | |||
2240 | /* | ||
2234 | * Function prototypes | 2241 | * Function prototypes |
2235 | */ | 2242 | */ |
2236 | 2243 | ||
@@ -2242,6 +2249,10 @@ struct mmpd_data { | |||
2242 | # define ATTRIB_NORET __attribute__((noreturn)) | 2249 | # define ATTRIB_NORET __attribute__((noreturn)) |
2243 | # define NORET_AND noreturn, | 2250 | # define NORET_AND noreturn, |
2244 | 2251 | ||
2252 | struct ext4_xattr_ino_array { | ||
2253 | unsigned int xia_count; /* # of used item in the array */ | ||
2254 | unsigned int xia_inodes[0]; | ||
2255 | }; | ||
2245 | /* bitmap.c */ | 2256 | /* bitmap.c */ |
2246 | extern unsigned int ext4_count_free(char *bitmap, unsigned numchars); | 2257 | extern unsigned int ext4_count_free(char *bitmap, unsigned numchars); |
2247 | void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, | 2258 | void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, |
@@ -2489,6 +2500,7 @@ extern int ext4_truncate_restart_trans(handle_t *, struct inode *, int nblocks); | |||
2489 | extern void ext4_set_inode_flags(struct inode *); | 2500 | extern void ext4_set_inode_flags(struct inode *); |
2490 | extern int ext4_alloc_da_blocks(struct inode *inode); | 2501 | extern int ext4_alloc_da_blocks(struct inode *inode); |
2491 | extern void ext4_set_aops(struct inode *inode); | 2502 | extern void ext4_set_aops(struct inode *inode); |
2503 | extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int chunk); | ||
2492 | extern int ext4_writepage_trans_blocks(struct inode *); | 2504 | extern int ext4_writepage_trans_blocks(struct inode *); |
2493 | extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); | 2505 | extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); |
2494 | extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode, | 2506 | extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode, |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 98ac2f1f23b3..e2eb3cc06820 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
@@ -294,7 +294,6 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) | |||
294 | * as writing the quota to disk may need the lock as well. | 294 | * as writing the quota to disk may need the lock as well. |
295 | */ | 295 | */ |
296 | dquot_initialize(inode); | 296 | dquot_initialize(inode); |
297 | ext4_xattr_delete_inode(handle, inode); | ||
298 | dquot_free_inode(inode); | 297 | dquot_free_inode(inode); |
299 | dquot_drop(inode); | 298 | dquot_drop(inode); |
300 | 299 | ||
diff --git a/fs/ext4/inline.c b/fs/ext4/inline.c index 8d141c0c8ff9..28c5c3abddb3 100644 --- a/fs/ext4/inline.c +++ b/fs/ext4/inline.c | |||
@@ -61,7 +61,7 @@ static int get_max_inline_xattr_value_size(struct inode *inode, | |||
61 | 61 | ||
62 | /* Compute min_offs. */ | 62 | /* Compute min_offs. */ |
63 | for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { | 63 | for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { |
64 | if (!entry->e_value_block && entry->e_value_size) { | 64 | if (!entry->e_value_inum && entry->e_value_size) { |
65 | size_t offs = le16_to_cpu(entry->e_value_offs); | 65 | size_t offs = le16_to_cpu(entry->e_value_offs); |
66 | if (offs < min_offs) | 66 | if (offs < min_offs) |
67 | min_offs = offs; | 67 | min_offs = offs; |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 47604d1352fc..986efd9511ac 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -139,8 +139,6 @@ static void ext4_invalidatepage(struct page *page, unsigned int offset, | |||
139 | unsigned int length); | 139 | unsigned int length); |
140 | static int __ext4_journalled_writepage(struct page *page, unsigned int len); | 140 | static int __ext4_journalled_writepage(struct page *page, unsigned int len); |
141 | static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh); | 141 | static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh); |
142 | static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, | ||
143 | int pextents); | ||
144 | 142 | ||
145 | /* | 143 | /* |
146 | * Test whether an inode is a fast symlink. | 144 | * Test whether an inode is a fast symlink. |
@@ -189,6 +187,8 @@ void ext4_evict_inode(struct inode *inode) | |||
189 | { | 187 | { |
190 | handle_t *handle; | 188 | handle_t *handle; |
191 | int err; | 189 | int err; |
190 | int extra_credits = 3; | ||
191 | struct ext4_xattr_ino_array *lea_ino_array = NULL; | ||
192 | 192 | ||
193 | trace_ext4_evict_inode(inode); | 193 | trace_ext4_evict_inode(inode); |
194 | 194 | ||
@@ -238,8 +238,8 @@ void ext4_evict_inode(struct inode *inode) | |||
238 | * protection against it | 238 | * protection against it |
239 | */ | 239 | */ |
240 | sb_start_intwrite(inode->i_sb); | 240 | sb_start_intwrite(inode->i_sb); |
241 | handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, | 241 | |
242 | ext4_blocks_for_truncate(inode)+3); | 242 | handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, extra_credits); |
243 | if (IS_ERR(handle)) { | 243 | if (IS_ERR(handle)) { |
244 | ext4_std_error(inode->i_sb, PTR_ERR(handle)); | 244 | ext4_std_error(inode->i_sb, PTR_ERR(handle)); |
245 | /* | 245 | /* |
@@ -251,9 +251,36 @@ void ext4_evict_inode(struct inode *inode) | |||
251 | sb_end_intwrite(inode->i_sb); | 251 | sb_end_intwrite(inode->i_sb); |
252 | goto no_delete; | 252 | goto no_delete; |
253 | } | 253 | } |
254 | |||
255 | if (IS_SYNC(inode)) | 254 | if (IS_SYNC(inode)) |
256 | ext4_handle_sync(handle); | 255 | ext4_handle_sync(handle); |
256 | |||
257 | /* | ||
258 | * Delete xattr inode before deleting the main inode. | ||
259 | */ | ||
260 | err = ext4_xattr_delete_inode(handle, inode, &lea_ino_array); | ||
261 | if (err) { | ||
262 | ext4_warning(inode->i_sb, | ||
263 | "couldn't delete inode's xattr (err %d)", err); | ||
264 | goto stop_handle; | ||
265 | } | ||
266 | |||
267 | if (!IS_NOQUOTA(inode)) | ||
268 | extra_credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); | ||
269 | |||
270 | if (!ext4_handle_has_enough_credits(handle, | ||
271 | ext4_blocks_for_truncate(inode) + extra_credits)) { | ||
272 | err = ext4_journal_extend(handle, | ||
273 | ext4_blocks_for_truncate(inode) + extra_credits); | ||
274 | if (err > 0) | ||
275 | err = ext4_journal_restart(handle, | ||
276 | ext4_blocks_for_truncate(inode) + extra_credits); | ||
277 | if (err != 0) { | ||
278 | ext4_warning(inode->i_sb, | ||
279 | "couldn't extend journal (err %d)", err); | ||
280 | goto stop_handle; | ||
281 | } | ||
282 | } | ||
283 | |||
257 | inode->i_size = 0; | 284 | inode->i_size = 0; |
258 | err = ext4_mark_inode_dirty(handle, inode); | 285 | err = ext4_mark_inode_dirty(handle, inode); |
259 | if (err) { | 286 | if (err) { |
@@ -277,10 +304,10 @@ void ext4_evict_inode(struct inode *inode) | |||
277 | * enough credits left in the handle to remove the inode from | 304 | * enough credits left in the handle to remove the inode from |
278 | * the orphan list and set the dtime field. | 305 | * the orphan list and set the dtime field. |
279 | */ | 306 | */ |
280 | if (!ext4_handle_has_enough_credits(handle, 3)) { | 307 | if (!ext4_handle_has_enough_credits(handle, extra_credits)) { |
281 | err = ext4_journal_extend(handle, 3); | 308 | err = ext4_journal_extend(handle, extra_credits); |
282 | if (err > 0) | 309 | if (err > 0) |
283 | err = ext4_journal_restart(handle, 3); | 310 | err = ext4_journal_restart(handle, extra_credits); |
284 | if (err != 0) { | 311 | if (err != 0) { |
285 | ext4_warning(inode->i_sb, | 312 | ext4_warning(inode->i_sb, |
286 | "couldn't extend journal (err %d)", err); | 313 | "couldn't extend journal (err %d)", err); |
@@ -315,8 +342,12 @@ void ext4_evict_inode(struct inode *inode) | |||
315 | ext4_clear_inode(inode); | 342 | ext4_clear_inode(inode); |
316 | else | 343 | else |
317 | ext4_free_inode(handle, inode); | 344 | ext4_free_inode(handle, inode); |
345 | |||
318 | ext4_journal_stop(handle); | 346 | ext4_journal_stop(handle); |
319 | sb_end_intwrite(inode->i_sb); | 347 | sb_end_intwrite(inode->i_sb); |
348 | |||
349 | if (lea_ino_array != NULL) | ||
350 | ext4_xattr_inode_array_free(inode, lea_ino_array); | ||
320 | return; | 351 | return; |
321 | no_delete: | 352 | no_delete: |
322 | ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ | 353 | ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ |
@@ -5504,7 +5535,7 @@ static int ext4_index_trans_blocks(struct inode *inode, int lblocks, | |||
5504 | * | 5535 | * |
5505 | * Also account for superblock, inode, quota and xattr blocks | 5536 | * Also account for superblock, inode, quota and xattr blocks |
5506 | */ | 5537 | */ |
5507 | static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, | 5538 | int ext4_meta_trans_blocks(struct inode *inode, int lblocks, |
5508 | int pextents) | 5539 | int pextents) |
5509 | { | 5540 | { |
5510 | ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb); | 5541 | ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb); |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index 5d3c2536641c..7dd80d16f98e 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
@@ -177,9 +177,8 @@ ext4_xattr_check_entries(struct ext4_xattr_entry *entry, void *end, | |||
177 | 177 | ||
178 | /* Check the values */ | 178 | /* Check the values */ |
179 | while (!IS_LAST_ENTRY(entry)) { | 179 | while (!IS_LAST_ENTRY(entry)) { |
180 | if (entry->e_value_block != 0) | 180 | if (entry->e_value_size != 0 && |
181 | return -EFSCORRUPTED; | 181 | entry->e_value_inum == 0) { |
182 | if (entry->e_value_size != 0) { | ||
183 | u16 offs = le16_to_cpu(entry->e_value_offs); | 182 | u16 offs = le16_to_cpu(entry->e_value_offs); |
184 | u32 size = le32_to_cpu(entry->e_value_size); | 183 | u32 size = le32_to_cpu(entry->e_value_size); |
185 | void *value; | 184 | void *value; |
@@ -269,6 +268,99 @@ ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index, | |||
269 | return cmp ? -ENODATA : 0; | 268 | return cmp ? -ENODATA : 0; |
270 | } | 269 | } |
271 | 270 | ||
271 | /* | ||
272 | * Read the EA value from an inode. | ||
273 | */ | ||
274 | static int | ||
275 | ext4_xattr_inode_read(struct inode *ea_inode, void *buf, size_t *size) | ||
276 | { | ||
277 | unsigned long block = 0; | ||
278 | struct buffer_head *bh = NULL; | ||
279 | int blocksize; | ||
280 | size_t csize, ret_size = 0; | ||
281 | |||
282 | if (*size == 0) | ||
283 | return 0; | ||
284 | |||
285 | blocksize = ea_inode->i_sb->s_blocksize; | ||
286 | |||
287 | while (ret_size < *size) { | ||
288 | csize = (*size - ret_size) > blocksize ? blocksize : | ||
289 | *size - ret_size; | ||
290 | bh = ext4_bread(NULL, ea_inode, block, 0); | ||
291 | if (IS_ERR(bh)) { | ||
292 | *size = ret_size; | ||
293 | return PTR_ERR(bh); | ||
294 | } | ||
295 | memcpy(buf, bh->b_data, csize); | ||
296 | brelse(bh); | ||
297 | |||
298 | buf += csize; | ||
299 | block += 1; | ||
300 | ret_size += csize; | ||
301 | } | ||
302 | |||
303 | *size = ret_size; | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | struct inode *ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino, int *err) | ||
309 | { | ||
310 | struct inode *ea_inode = NULL; | ||
311 | |||
312 | ea_inode = ext4_iget(parent->i_sb, ea_ino); | ||
313 | if (IS_ERR(ea_inode) || is_bad_inode(ea_inode)) { | ||
314 | int rc = IS_ERR(ea_inode) ? PTR_ERR(ea_inode) : 0; | ||
315 | ext4_error(parent->i_sb, "error while reading EA inode %lu " | ||
316 | "/ %d %d", ea_ino, rc, is_bad_inode(ea_inode)); | ||
317 | *err = rc != 0 ? rc : -EIO; | ||
318 | return NULL; | ||
319 | } | ||
320 | |||
321 | if (EXT4_XATTR_INODE_GET_PARENT(ea_inode) != parent->i_ino || | ||
322 | ea_inode->i_generation != parent->i_generation) { | ||
323 | ext4_error(parent->i_sb, "Backpointer from EA inode %lu " | ||
324 | "to parent invalid.", ea_ino); | ||
325 | *err = -EINVAL; | ||
326 | goto error; | ||
327 | } | ||
328 | |||
329 | if (!(EXT4_I(ea_inode)->i_flags & EXT4_EA_INODE_FL)) { | ||
330 | ext4_error(parent->i_sb, "EA inode %lu does not have " | ||
331 | "EXT4_EA_INODE_FL flag set.\n", ea_ino); | ||
332 | *err = -EINVAL; | ||
333 | goto error; | ||
334 | } | ||
335 | |||
336 | *err = 0; | ||
337 | return ea_inode; | ||
338 | |||
339 | error: | ||
340 | iput(ea_inode); | ||
341 | return NULL; | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * Read the value from the EA inode. | ||
346 | */ | ||
347 | static int | ||
348 | ext4_xattr_inode_get(struct inode *inode, unsigned long ea_ino, void *buffer, | ||
349 | size_t *size) | ||
350 | { | ||
351 | struct inode *ea_inode = NULL; | ||
352 | int err; | ||
353 | |||
354 | ea_inode = ext4_xattr_inode_iget(inode, ea_ino, &err); | ||
355 | if (err) | ||
356 | return err; | ||
357 | |||
358 | err = ext4_xattr_inode_read(ea_inode, buffer, size); | ||
359 | iput(ea_inode); | ||
360 | |||
361 | return err; | ||
362 | } | ||
363 | |||
272 | static int | 364 | static int |
273 | ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, | 365 | ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, |
274 | void *buffer, size_t buffer_size) | 366 | void *buffer, size_t buffer_size) |
@@ -308,8 +400,16 @@ ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, | |||
308 | error = -ERANGE; | 400 | error = -ERANGE; |
309 | if (size > buffer_size) | 401 | if (size > buffer_size) |
310 | goto cleanup; | 402 | goto cleanup; |
311 | memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), | 403 | if (entry->e_value_inum) { |
312 | size); | 404 | error = ext4_xattr_inode_get(inode, |
405 | le32_to_cpu(entry->e_value_inum), | ||
406 | buffer, &size); | ||
407 | if (error) | ||
408 | goto cleanup; | ||
409 | } else { | ||
410 | memcpy(buffer, bh->b_data + | ||
411 | le16_to_cpu(entry->e_value_offs), size); | ||
412 | } | ||
313 | } | 413 | } |
314 | error = size; | 414 | error = size; |
315 | 415 | ||
@@ -350,8 +450,16 @@ ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, | |||
350 | error = -ERANGE; | 450 | error = -ERANGE; |
351 | if (size > buffer_size) | 451 | if (size > buffer_size) |
352 | goto cleanup; | 452 | goto cleanup; |
353 | memcpy(buffer, (void *)IFIRST(header) + | 453 | if (entry->e_value_inum) { |
354 | le16_to_cpu(entry->e_value_offs), size); | 454 | error = ext4_xattr_inode_get(inode, |
455 | le32_to_cpu(entry->e_value_inum), | ||
456 | buffer, &size); | ||
457 | if (error) | ||
458 | goto cleanup; | ||
459 | } else { | ||
460 | memcpy(buffer, (void *)IFIRST(header) + | ||
461 | le16_to_cpu(entry->e_value_offs), size); | ||
462 | } | ||
355 | } | 463 | } |
356 | error = size; | 464 | error = size; |
357 | 465 | ||
@@ -620,7 +728,7 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last, | |||
620 | size_t *min_offs, void *base, int *total) | 728 | size_t *min_offs, void *base, int *total) |
621 | { | 729 | { |
622 | for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { | 730 | for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { |
623 | if (last->e_value_size) { | 731 | if (!last->e_value_inum && last->e_value_size) { |
624 | size_t offs = le16_to_cpu(last->e_value_offs); | 732 | size_t offs = le16_to_cpu(last->e_value_offs); |
625 | if (offs < *min_offs) | 733 | if (offs < *min_offs) |
626 | *min_offs = offs; | 734 | *min_offs = offs; |
@@ -631,16 +739,171 @@ static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last, | |||
631 | return (*min_offs - ((void *)last - base) - sizeof(__u32)); | 739 | return (*min_offs - ((void *)last - base) - sizeof(__u32)); |
632 | } | 740 | } |
633 | 741 | ||
634 | static int | 742 | /* |
635 | ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) | 743 | * Write the value of the EA in an inode. |
744 | */ | ||
745 | static int ext4_xattr_inode_write(handle_t *handle, struct inode *ea_inode, | ||
746 | const void *buf, int bufsize) | ||
747 | { | ||
748 | struct buffer_head *bh = NULL; | ||
749 | unsigned long block = 0; | ||
750 | unsigned blocksize = ea_inode->i_sb->s_blocksize; | ||
751 | unsigned max_blocks = (bufsize + blocksize - 1) >> ea_inode->i_blkbits; | ||
752 | int csize, wsize = 0; | ||
753 | int ret = 0; | ||
754 | int retries = 0; | ||
755 | |||
756 | retry: | ||
757 | while (ret >= 0 && ret < max_blocks) { | ||
758 | struct ext4_map_blocks map; | ||
759 | map.m_lblk = block += ret; | ||
760 | map.m_len = max_blocks -= ret; | ||
761 | |||
762 | ret = ext4_map_blocks(handle, ea_inode, &map, | ||
763 | EXT4_GET_BLOCKS_CREATE); | ||
764 | if (ret <= 0) { | ||
765 | ext4_mark_inode_dirty(handle, ea_inode); | ||
766 | if (ret == -ENOSPC && | ||
767 | ext4_should_retry_alloc(ea_inode->i_sb, &retries)) { | ||
768 | ret = 0; | ||
769 | goto retry; | ||
770 | } | ||
771 | break; | ||
772 | } | ||
773 | } | ||
774 | |||
775 | if (ret < 0) | ||
776 | return ret; | ||
777 | |||
778 | block = 0; | ||
779 | while (wsize < bufsize) { | ||
780 | if (bh != NULL) | ||
781 | brelse(bh); | ||
782 | csize = (bufsize - wsize) > blocksize ? blocksize : | ||
783 | bufsize - wsize; | ||
784 | bh = ext4_getblk(handle, ea_inode, block, 0); | ||
785 | if (IS_ERR(bh)) | ||
786 | return PTR_ERR(bh); | ||
787 | ret = ext4_journal_get_write_access(handle, bh); | ||
788 | if (ret) | ||
789 | goto out; | ||
790 | |||
791 | memcpy(bh->b_data, buf, csize); | ||
792 | set_buffer_uptodate(bh); | ||
793 | ext4_handle_dirty_metadata(handle, ea_inode, bh); | ||
794 | |||
795 | buf += csize; | ||
796 | wsize += csize; | ||
797 | block += 1; | ||
798 | } | ||
799 | |||
800 | inode_lock(ea_inode); | ||
801 | i_size_write(ea_inode, wsize); | ||
802 | ext4_update_i_disksize(ea_inode, wsize); | ||
803 | inode_unlock(ea_inode); | ||
804 | |||
805 | ext4_mark_inode_dirty(handle, ea_inode); | ||
806 | |||
807 | out: | ||
808 | brelse(bh); | ||
809 | |||
810 | return ret; | ||
811 | } | ||
812 | |||
813 | /* | ||
814 | * Create an inode to store the value of a large EA. | ||
815 | */ | ||
816 | static struct inode *ext4_xattr_inode_create(handle_t *handle, | ||
817 | struct inode *inode) | ||
818 | { | ||
819 | struct inode *ea_inode = NULL; | ||
820 | |||
821 | /* | ||
822 | * Let the next inode be the goal, so we try and allocate the EA inode | ||
823 | * in the same group, or nearby one. | ||
824 | */ | ||
825 | ea_inode = ext4_new_inode(handle, inode->i_sb->s_root->d_inode, | ||
826 | S_IFREG | 0600, NULL, inode->i_ino + 1, NULL); | ||
827 | if (!IS_ERR(ea_inode)) { | ||
828 | ea_inode->i_op = &ext4_file_inode_operations; | ||
829 | ea_inode->i_fop = &ext4_file_operations; | ||
830 | ext4_set_aops(ea_inode); | ||
831 | ea_inode->i_generation = inode->i_generation; | ||
832 | EXT4_I(ea_inode)->i_flags |= EXT4_EA_INODE_FL; | ||
833 | |||
834 | /* | ||
835 | * A back-pointer from EA inode to parent inode will be useful | ||
836 | * for e2fsck. | ||
837 | */ | ||
838 | EXT4_XATTR_INODE_SET_PARENT(ea_inode, inode->i_ino); | ||
839 | unlock_new_inode(ea_inode); | ||
840 | } | ||
841 | |||
842 | return ea_inode; | ||
843 | } | ||
844 | |||
845 | /* | ||
846 | * Unlink the inode storing the value of the EA. | ||
847 | */ | ||
848 | int ext4_xattr_inode_unlink(struct inode *inode, unsigned long ea_ino) | ||
849 | { | ||
850 | struct inode *ea_inode = NULL; | ||
851 | int err; | ||
852 | |||
853 | ea_inode = ext4_xattr_inode_iget(inode, ea_ino, &err); | ||
854 | if (err) | ||
855 | return err; | ||
856 | |||
857 | clear_nlink(ea_inode); | ||
858 | iput(ea_inode); | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | /* | ||
864 | * Add value of the EA in an inode. | ||
865 | */ | ||
866 | static int ext4_xattr_inode_set(handle_t *handle, struct inode *inode, | ||
867 | unsigned long *ea_ino, const void *value, | ||
868 | size_t value_len) | ||
869 | { | ||
870 | struct inode *ea_inode; | ||
871 | int err; | ||
872 | |||
873 | /* Create an inode for the EA value */ | ||
874 | ea_inode = ext4_xattr_inode_create(handle, inode); | ||
875 | if (IS_ERR(ea_inode)) | ||
876 | return PTR_ERR(ea_inode); | ||
877 | |||
878 | err = ext4_xattr_inode_write(handle, ea_inode, value, value_len); | ||
879 | if (err) | ||
880 | clear_nlink(ea_inode); | ||
881 | else | ||
882 | *ea_ino = ea_inode->i_ino; | ||
883 | |||
884 | iput(ea_inode); | ||
885 | |||
886 | return err; | ||
887 | } | ||
888 | |||
889 | static int ext4_xattr_set_entry(struct ext4_xattr_info *i, | ||
890 | struct ext4_xattr_search *s, | ||
891 | handle_t *handle, struct inode *inode) | ||
636 | { | 892 | { |
637 | struct ext4_xattr_entry *last; | 893 | struct ext4_xattr_entry *last; |
638 | size_t free, min_offs = s->end - s->base, name_len = strlen(i->name); | 894 | size_t free, min_offs = s->end - s->base, name_len = strlen(i->name); |
895 | int in_inode = i->in_inode; | ||
896 | int rc; | ||
897 | |||
898 | if (ext4_has_feature_ea_inode(inode->i_sb) && | ||
899 | (EXT4_XATTR_SIZE(i->value_len) > | ||
900 | EXT4_XATTR_MIN_LARGE_EA_SIZE(inode->i_sb->s_blocksize))) | ||
901 | in_inode = 1; | ||
639 | 902 | ||
640 | /* Compute min_offs and last. */ | 903 | /* Compute min_offs and last. */ |
641 | last = s->first; | 904 | last = s->first; |
642 | for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { | 905 | for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { |
643 | if (last->e_value_size) { | 906 | if (!last->e_value_inum && last->e_value_size) { |
644 | size_t offs = le16_to_cpu(last->e_value_offs); | 907 | size_t offs = le16_to_cpu(last->e_value_offs); |
645 | if (offs < min_offs) | 908 | if (offs < min_offs) |
646 | min_offs = offs; | 909 | min_offs = offs; |
@@ -648,15 +911,20 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) | |||
648 | } | 911 | } |
649 | free = min_offs - ((void *)last - s->base) - sizeof(__u32); | 912 | free = min_offs - ((void *)last - s->base) - sizeof(__u32); |
650 | if (!s->not_found) { | 913 | if (!s->not_found) { |
651 | if (s->here->e_value_size) { | 914 | if (!in_inode && |
915 | !s->here->e_value_inum && s->here->e_value_size) { | ||
652 | size_t size = le32_to_cpu(s->here->e_value_size); | 916 | size_t size = le32_to_cpu(s->here->e_value_size); |
653 | free += EXT4_XATTR_SIZE(size); | 917 | free += EXT4_XATTR_SIZE(size); |
654 | } | 918 | } |
655 | free += EXT4_XATTR_LEN(name_len); | 919 | free += EXT4_XATTR_LEN(name_len); |
656 | } | 920 | } |
657 | if (i->value) { | 921 | if (i->value) { |
658 | if (free < EXT4_XATTR_LEN(name_len) + | 922 | size_t value_len = EXT4_XATTR_SIZE(i->value_len); |
659 | EXT4_XATTR_SIZE(i->value_len)) | 923 | |
924 | if (in_inode) | ||
925 | value_len = 0; | ||
926 | |||
927 | if (free < EXT4_XATTR_LEN(name_len) + value_len) | ||
660 | return -ENOSPC; | 928 | return -ENOSPC; |
661 | } | 929 | } |
662 | 930 | ||
@@ -670,7 +938,8 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) | |||
670 | s->here->e_name_len = name_len; | 938 | s->here->e_name_len = name_len; |
671 | memcpy(s->here->e_name, i->name, name_len); | 939 | memcpy(s->here->e_name, i->name, name_len); |
672 | } else { | 940 | } else { |
673 | if (s->here->e_value_size) { | 941 | if (!s->here->e_value_inum && s->here->e_value_size && |
942 | s->here->e_value_offs > 0) { | ||
674 | void *first_val = s->base + min_offs; | 943 | void *first_val = s->base + min_offs; |
675 | size_t offs = le16_to_cpu(s->here->e_value_offs); | 944 | size_t offs = le16_to_cpu(s->here->e_value_offs); |
676 | void *val = s->base + offs; | 945 | void *val = s->base + offs; |
@@ -704,12 +973,18 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) | |||
704 | last = s->first; | 973 | last = s->first; |
705 | while (!IS_LAST_ENTRY(last)) { | 974 | while (!IS_LAST_ENTRY(last)) { |
706 | size_t o = le16_to_cpu(last->e_value_offs); | 975 | size_t o = le16_to_cpu(last->e_value_offs); |
707 | if (last->e_value_size && o < offs) | 976 | if (!last->e_value_inum && |
977 | last->e_value_size && o < offs) | ||
708 | last->e_value_offs = | 978 | last->e_value_offs = |
709 | cpu_to_le16(o + size); | 979 | cpu_to_le16(o + size); |
710 | last = EXT4_XATTR_NEXT(last); | 980 | last = EXT4_XATTR_NEXT(last); |
711 | } | 981 | } |
712 | } | 982 | } |
983 | if (s->here->e_value_inum) { | ||
984 | ext4_xattr_inode_unlink(inode, | ||
985 | le32_to_cpu(s->here->e_value_inum)); | ||
986 | s->here->e_value_inum = 0; | ||
987 | } | ||
713 | if (!i->value) { | 988 | if (!i->value) { |
714 | /* Remove the old name. */ | 989 | /* Remove the old name. */ |
715 | size_t size = EXT4_XATTR_LEN(name_len); | 990 | size_t size = EXT4_XATTR_LEN(name_len); |
@@ -722,11 +997,20 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) | |||
722 | 997 | ||
723 | if (i->value) { | 998 | if (i->value) { |
724 | /* Insert the new value. */ | 999 | /* Insert the new value. */ |
725 | s->here->e_value_size = cpu_to_le32(i->value_len); | 1000 | if (in_inode) { |
726 | if (i->value_len) { | 1001 | unsigned long ea_ino = |
1002 | le32_to_cpu(s->here->e_value_inum); | ||
1003 | rc = ext4_xattr_inode_set(handle, inode, &ea_ino, | ||
1004 | i->value, i->value_len); | ||
1005 | if (rc) | ||
1006 | goto out; | ||
1007 | s->here->e_value_inum = cpu_to_le32(ea_ino); | ||
1008 | s->here->e_value_offs = 0; | ||
1009 | } else if (i->value_len) { | ||
727 | size_t size = EXT4_XATTR_SIZE(i->value_len); | 1010 | size_t size = EXT4_XATTR_SIZE(i->value_len); |
728 | void *val = s->base + min_offs - size; | 1011 | void *val = s->base + min_offs - size; |
729 | s->here->e_value_offs = cpu_to_le16(min_offs - size); | 1012 | s->here->e_value_offs = cpu_to_le16(min_offs - size); |
1013 | s->here->e_value_inum = 0; | ||
730 | if (i->value == EXT4_ZERO_XATTR_VALUE) { | 1014 | if (i->value == EXT4_ZERO_XATTR_VALUE) { |
731 | memset(val, 0, size); | 1015 | memset(val, 0, size); |
732 | } else { | 1016 | } else { |
@@ -736,8 +1020,11 @@ ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) | |||
736 | memcpy(val, i->value, i->value_len); | 1020 | memcpy(val, i->value, i->value_len); |
737 | } | 1021 | } |
738 | } | 1022 | } |
1023 | s->here->e_value_size = cpu_to_le32(i->value_len); | ||
739 | } | 1024 | } |
740 | return 0; | 1025 | |
1026 | out: | ||
1027 | return rc; | ||
741 | } | 1028 | } |
742 | 1029 | ||
743 | struct ext4_xattr_block_find { | 1030 | struct ext4_xattr_block_find { |
@@ -801,8 +1088,6 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
801 | 1088 | ||
802 | #define header(x) ((struct ext4_xattr_header *)(x)) | 1089 | #define header(x) ((struct ext4_xattr_header *)(x)) |
803 | 1090 | ||
804 | if (i->value && i->value_len > sb->s_blocksize) | ||
805 | return -ENOSPC; | ||
806 | if (s->base) { | 1091 | if (s->base) { |
807 | BUFFER_TRACE(bs->bh, "get_write_access"); | 1092 | BUFFER_TRACE(bs->bh, "get_write_access"); |
808 | error = ext4_journal_get_write_access(handle, bs->bh); | 1093 | error = ext4_journal_get_write_access(handle, bs->bh); |
@@ -821,7 +1106,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
821 | mb_cache_entry_delete_block(ext4_mb_cache, hash, | 1106 | mb_cache_entry_delete_block(ext4_mb_cache, hash, |
822 | bs->bh->b_blocknr); | 1107 | bs->bh->b_blocknr); |
823 | ea_bdebug(bs->bh, "modifying in-place"); | 1108 | ea_bdebug(bs->bh, "modifying in-place"); |
824 | error = ext4_xattr_set_entry(i, s); | 1109 | error = ext4_xattr_set_entry(i, s, handle, inode); |
825 | if (!error) { | 1110 | if (!error) { |
826 | if (!IS_LAST_ENTRY(s->first)) | 1111 | if (!IS_LAST_ENTRY(s->first)) |
827 | ext4_xattr_rehash(header(s->base), | 1112 | ext4_xattr_rehash(header(s->base), |
@@ -870,7 +1155,7 @@ ext4_xattr_block_set(handle_t *handle, struct inode *inode, | |||
870 | s->end = s->base + sb->s_blocksize; | 1155 | s->end = s->base + sb->s_blocksize; |
871 | } | 1156 | } |
872 | 1157 | ||
873 | error = ext4_xattr_set_entry(i, s); | 1158 | error = ext4_xattr_set_entry(i, s, handle, inode); |
874 | if (error == -EFSCORRUPTED) | 1159 | if (error == -EFSCORRUPTED) |
875 | goto bad_block; | 1160 | goto bad_block; |
876 | if (error) | 1161 | if (error) |
@@ -1070,7 +1355,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, | |||
1070 | 1355 | ||
1071 | if (EXT4_I(inode)->i_extra_isize == 0) | 1356 | if (EXT4_I(inode)->i_extra_isize == 0) |
1072 | return -ENOSPC; | 1357 | return -ENOSPC; |
1073 | error = ext4_xattr_set_entry(i, s); | 1358 | error = ext4_xattr_set_entry(i, s, handle, inode); |
1074 | if (error) { | 1359 | if (error) { |
1075 | if (error == -ENOSPC && | 1360 | if (error == -ENOSPC && |
1076 | ext4_has_inline_data(inode)) { | 1361 | ext4_has_inline_data(inode)) { |
@@ -1082,7 +1367,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, | |||
1082 | error = ext4_xattr_ibody_find(inode, i, is); | 1367 | error = ext4_xattr_ibody_find(inode, i, is); |
1083 | if (error) | 1368 | if (error) |
1084 | return error; | 1369 | return error; |
1085 | error = ext4_xattr_set_entry(i, s); | 1370 | error = ext4_xattr_set_entry(i, s, handle, inode); |
1086 | } | 1371 | } |
1087 | if (error) | 1372 | if (error) |
1088 | return error; | 1373 | return error; |
@@ -1098,7 +1383,7 @@ int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, | |||
1098 | return 0; | 1383 | return 0; |
1099 | } | 1384 | } |
1100 | 1385 | ||
1101 | static int ext4_xattr_ibody_set(struct inode *inode, | 1386 | static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, |
1102 | struct ext4_xattr_info *i, | 1387 | struct ext4_xattr_info *i, |
1103 | struct ext4_xattr_ibody_find *is) | 1388 | struct ext4_xattr_ibody_find *is) |
1104 | { | 1389 | { |
@@ -1108,7 +1393,7 @@ static int ext4_xattr_ibody_set(struct inode *inode, | |||
1108 | 1393 | ||
1109 | if (EXT4_I(inode)->i_extra_isize == 0) | 1394 | if (EXT4_I(inode)->i_extra_isize == 0) |
1110 | return -ENOSPC; | 1395 | return -ENOSPC; |
1111 | error = ext4_xattr_set_entry(i, s); | 1396 | error = ext4_xattr_set_entry(i, s, handle, inode); |
1112 | if (error) | 1397 | if (error) |
1113 | return error; | 1398 | return error; |
1114 | header = IHDR(inode, ext4_raw_inode(&is->iloc)); | 1399 | header = IHDR(inode, ext4_raw_inode(&is->iloc)); |
@@ -1155,7 +1440,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, | |||
1155 | .name = name, | 1440 | .name = name, |
1156 | .value = value, | 1441 | .value = value, |
1157 | .value_len = value_len, | 1442 | .value_len = value_len, |
1158 | 1443 | .in_inode = 0, | |
1159 | }; | 1444 | }; |
1160 | struct ext4_xattr_ibody_find is = { | 1445 | struct ext4_xattr_ibody_find is = { |
1161 | .s = { .not_found = -ENODATA, }, | 1446 | .s = { .not_found = -ENODATA, }, |
@@ -1204,7 +1489,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, | |||
1204 | } | 1489 | } |
1205 | if (!value) { | 1490 | if (!value) { |
1206 | if (!is.s.not_found) | 1491 | if (!is.s.not_found) |
1207 | error = ext4_xattr_ibody_set(inode, &i, &is); | 1492 | error = ext4_xattr_ibody_set(handle, inode, &i, &is); |
1208 | else if (!bs.s.not_found) | 1493 | else if (!bs.s.not_found) |
1209 | error = ext4_xattr_block_set(handle, inode, &i, &bs); | 1494 | error = ext4_xattr_block_set(handle, inode, &i, &bs); |
1210 | } else { | 1495 | } else { |
@@ -1215,7 +1500,7 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, | |||
1215 | if (!bs.s.not_found && ext4_xattr_value_same(&bs.s, &i)) | 1500 | if (!bs.s.not_found && ext4_xattr_value_same(&bs.s, &i)) |
1216 | goto cleanup; | 1501 | goto cleanup; |
1217 | 1502 | ||
1218 | error = ext4_xattr_ibody_set(inode, &i, &is); | 1503 | error = ext4_xattr_ibody_set(handle, inode, &i, &is); |
1219 | if (!error && !bs.s.not_found) { | 1504 | if (!error && !bs.s.not_found) { |
1220 | i.value = NULL; | 1505 | i.value = NULL; |
1221 | error = ext4_xattr_block_set(handle, inode, &i, &bs); | 1506 | error = ext4_xattr_block_set(handle, inode, &i, &bs); |
@@ -1226,11 +1511,20 @@ ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, | |||
1226 | goto cleanup; | 1511 | goto cleanup; |
1227 | } | 1512 | } |
1228 | error = ext4_xattr_block_set(handle, inode, &i, &bs); | 1513 | error = ext4_xattr_block_set(handle, inode, &i, &bs); |
1514 | if (ext4_has_feature_ea_inode(inode->i_sb) && | ||
1515 | error == -ENOSPC) { | ||
1516 | /* xattr not fit to block, store at external | ||
1517 | * inode */ | ||
1518 | i.in_inode = 1; | ||
1519 | error = ext4_xattr_ibody_set(handle, inode, | ||
1520 | &i, &is); | ||
1521 | } | ||
1229 | if (error) | 1522 | if (error) |
1230 | goto cleanup; | 1523 | goto cleanup; |
1231 | if (!is.s.not_found) { | 1524 | if (!is.s.not_found) { |
1232 | i.value = NULL; | 1525 | i.value = NULL; |
1233 | error = ext4_xattr_ibody_set(inode, &i, &is); | 1526 | error = ext4_xattr_ibody_set(handle, inode, &i, |
1527 | &is); | ||
1234 | } | 1528 | } |
1235 | } | 1529 | } |
1236 | } | 1530 | } |
@@ -1269,12 +1563,26 @@ ext4_xattr_set(struct inode *inode, int name_index, const char *name, | |||
1269 | const void *value, size_t value_len, int flags) | 1563 | const void *value, size_t value_len, int flags) |
1270 | { | 1564 | { |
1271 | handle_t *handle; | 1565 | handle_t *handle; |
1566 | struct super_block *sb = inode->i_sb; | ||
1272 | int error, retries = 0; | 1567 | int error, retries = 0; |
1273 | int credits = ext4_jbd2_credits_xattr(inode); | 1568 | int credits = ext4_jbd2_credits_xattr(inode); |
1274 | 1569 | ||
1275 | error = dquot_initialize(inode); | 1570 | error = dquot_initialize(inode); |
1276 | if (error) | 1571 | if (error) |
1277 | return error; | 1572 | return error; |
1573 | |||
1574 | if ((value_len >= EXT4_XATTR_MIN_LARGE_EA_SIZE(sb->s_blocksize)) && | ||
1575 | ext4_has_feature_ea_inode(sb)) { | ||
1576 | int nrblocks = (value_len + sb->s_blocksize - 1) >> | ||
1577 | sb->s_blocksize_bits; | ||
1578 | |||
1579 | /* For new inode */ | ||
1580 | credits += EXT4_SINGLEDATA_TRANS_BLOCKS(sb) + 3; | ||
1581 | |||
1582 | /* For data blocks of EA inode */ | ||
1583 | credits += ext4_meta_trans_blocks(inode, nrblocks, 0); | ||
1584 | } | ||
1585 | |||
1278 | retry: | 1586 | retry: |
1279 | handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); | 1587 | handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); |
1280 | if (IS_ERR(handle)) { | 1588 | if (IS_ERR(handle)) { |
@@ -1286,7 +1594,7 @@ retry: | |||
1286 | value, value_len, flags); | 1594 | value, value_len, flags); |
1287 | error2 = ext4_journal_stop(handle); | 1595 | error2 = ext4_journal_stop(handle); |
1288 | if (error == -ENOSPC && | 1596 | if (error == -ENOSPC && |
1289 | ext4_should_retry_alloc(inode->i_sb, &retries)) | 1597 | ext4_should_retry_alloc(sb, &retries)) |
1290 | goto retry; | 1598 | goto retry; |
1291 | if (error == 0) | 1599 | if (error == 0) |
1292 | error = error2; | 1600 | error = error2; |
@@ -1311,7 +1619,7 @@ static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry, | |||
1311 | 1619 | ||
1312 | /* Adjust the value offsets of the entries */ | 1620 | /* Adjust the value offsets of the entries */ |
1313 | for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { | 1621 | for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { |
1314 | if (last->e_value_size) { | 1622 | if (!last->e_value_inum && last->e_value_size) { |
1315 | new_offs = le16_to_cpu(last->e_value_offs) + | 1623 | new_offs = le16_to_cpu(last->e_value_offs) + |
1316 | value_offs_shift; | 1624 | value_offs_shift; |
1317 | last->e_value_offs = cpu_to_le16(new_offs); | 1625 | last->e_value_offs = cpu_to_le16(new_offs); |
@@ -1372,7 +1680,7 @@ static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode, | |||
1372 | goto out; | 1680 | goto out; |
1373 | 1681 | ||
1374 | /* Remove the chosen entry from the inode */ | 1682 | /* Remove the chosen entry from the inode */ |
1375 | error = ext4_xattr_ibody_set(inode, &i, is); | 1683 | error = ext4_xattr_ibody_set(handle, inode, &i, is); |
1376 | if (error) | 1684 | if (error) |
1377 | goto out; | 1685 | goto out; |
1378 | 1686 | ||
@@ -1572,21 +1880,135 @@ cleanup: | |||
1572 | } | 1880 | } |
1573 | 1881 | ||
1574 | 1882 | ||
1883 | #define EIA_INCR 16 /* must be 2^n */ | ||
1884 | #define EIA_MASK (EIA_INCR - 1) | ||
1885 | /* Add the large xattr @ino into @lea_ino_array for later deletion. | ||
1886 | * If @lea_ino_array is new or full it will be grown and the old | ||
1887 | * contents copied over. | ||
1888 | */ | ||
1889 | static int | ||
1890 | ext4_expand_ino_array(struct ext4_xattr_ino_array **lea_ino_array, __u32 ino) | ||
1891 | { | ||
1892 | if (*lea_ino_array == NULL) { | ||
1893 | /* | ||
1894 | * Start with 15 inodes, so it fits into a power-of-two size. | ||
1895 | * If *lea_ino_array is NULL, this is essentially offsetof() | ||
1896 | */ | ||
1897 | (*lea_ino_array) = | ||
1898 | kmalloc(offsetof(struct ext4_xattr_ino_array, | ||
1899 | xia_inodes[EIA_MASK]), | ||
1900 | GFP_NOFS); | ||
1901 | if (*lea_ino_array == NULL) | ||
1902 | return -ENOMEM; | ||
1903 | (*lea_ino_array)->xia_count = 0; | ||
1904 | } else if (((*lea_ino_array)->xia_count & EIA_MASK) == EIA_MASK) { | ||
1905 | /* expand the array once all 15 + n * 16 slots are full */ | ||
1906 | struct ext4_xattr_ino_array *new_array = NULL; | ||
1907 | int count = (*lea_ino_array)->xia_count; | ||
1908 | |||
1909 | /* if new_array is NULL, this is essentially offsetof() */ | ||
1910 | new_array = kmalloc( | ||
1911 | offsetof(struct ext4_xattr_ino_array, | ||
1912 | xia_inodes[count + EIA_INCR]), | ||
1913 | GFP_NOFS); | ||
1914 | if (new_array == NULL) | ||
1915 | return -ENOMEM; | ||
1916 | memcpy(new_array, *lea_ino_array, | ||
1917 | offsetof(struct ext4_xattr_ino_array, | ||
1918 | xia_inodes[count])); | ||
1919 | kfree(*lea_ino_array); | ||
1920 | *lea_ino_array = new_array; | ||
1921 | } | ||
1922 | (*lea_ino_array)->xia_inodes[(*lea_ino_array)->xia_count++] = ino; | ||
1923 | return 0; | ||
1924 | } | ||
1925 | |||
1926 | /** | ||
1927 | * Add xattr inode to orphan list | ||
1928 | */ | ||
1929 | static int | ||
1930 | ext4_xattr_inode_orphan_add(handle_t *handle, struct inode *inode, | ||
1931 | int credits, struct ext4_xattr_ino_array *lea_ino_array) | ||
1932 | { | ||
1933 | struct inode *ea_inode = NULL; | ||
1934 | int idx = 0, error = 0; | ||
1935 | |||
1936 | if (lea_ino_array == NULL) | ||
1937 | return 0; | ||
1938 | |||
1939 | for (; idx < lea_ino_array->xia_count; ++idx) { | ||
1940 | if (!ext4_handle_has_enough_credits(handle, credits)) { | ||
1941 | error = ext4_journal_extend(handle, credits); | ||
1942 | if (error > 0) | ||
1943 | error = ext4_journal_restart(handle, credits); | ||
1944 | |||
1945 | if (error != 0) { | ||
1946 | ext4_warning(inode->i_sb, | ||
1947 | "couldn't extend journal " | ||
1948 | "(err %d)", error); | ||
1949 | return error; | ||
1950 | } | ||
1951 | } | ||
1952 | ea_inode = ext4_xattr_inode_iget(inode, | ||
1953 | lea_ino_array->xia_inodes[idx], &error); | ||
1954 | if (error) | ||
1955 | continue; | ||
1956 | ext4_orphan_add(handle, ea_inode); | ||
1957 | /* the inode's i_count will be released by caller */ | ||
1958 | } | ||
1959 | |||
1960 | return 0; | ||
1961 | } | ||
1575 | 1962 | ||
1576 | /* | 1963 | /* |
1577 | * ext4_xattr_delete_inode() | 1964 | * ext4_xattr_delete_inode() |
1578 | * | 1965 | * |
1579 | * Free extended attribute resources associated with this inode. This | 1966 | * Free extended attribute resources associated with this inode. Traverse |
1967 | * all entries and unlink any xattr inodes associated with this inode. This | ||
1580 | * is called immediately before an inode is freed. We have exclusive | 1968 | * is called immediately before an inode is freed. We have exclusive |
1581 | * access to the inode. | 1969 | * access to the inode. If an orphan inode is deleted it will also delete any |
1970 | * xattr block and all xattr inodes. They are checked by ext4_xattr_inode_iget() | ||
1971 | * to ensure they belong to the parent inode and were not deleted already. | ||
1582 | */ | 1972 | */ |
1583 | void | 1973 | int |
1584 | ext4_xattr_delete_inode(handle_t *handle, struct inode *inode) | 1974 | ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, |
1975 | struct ext4_xattr_ino_array **lea_ino_array) | ||
1585 | { | 1976 | { |
1586 | struct buffer_head *bh = NULL; | 1977 | struct buffer_head *bh = NULL; |
1978 | struct ext4_xattr_ibody_header *header; | ||
1979 | struct ext4_inode *raw_inode; | ||
1980 | struct ext4_iloc iloc; | ||
1981 | struct ext4_xattr_entry *entry; | ||
1982 | int credits = 3, error = 0; | ||
1587 | 1983 | ||
1588 | if (!EXT4_I(inode)->i_file_acl) | 1984 | if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) |
1985 | goto delete_external_ea; | ||
1986 | |||
1987 | error = ext4_get_inode_loc(inode, &iloc); | ||
1988 | if (error) | ||
1989 | goto cleanup; | ||
1990 | raw_inode = ext4_raw_inode(&iloc); | ||
1991 | header = IHDR(inode, raw_inode); | ||
1992 | for (entry = IFIRST(header); !IS_LAST_ENTRY(entry); | ||
1993 | entry = EXT4_XATTR_NEXT(entry)) { | ||
1994 | if (!entry->e_value_inum) | ||
1995 | continue; | ||
1996 | if (ext4_expand_ino_array(lea_ino_array, | ||
1997 | entry->e_value_inum) != 0) { | ||
1998 | brelse(iloc.bh); | ||
1999 | goto cleanup; | ||
2000 | } | ||
2001 | entry->e_value_inum = 0; | ||
2002 | } | ||
2003 | brelse(iloc.bh); | ||
2004 | |||
2005 | delete_external_ea: | ||
2006 | if (!EXT4_I(inode)->i_file_acl) { | ||
2007 | /* add xattr inode to orphan list */ | ||
2008 | ext4_xattr_inode_orphan_add(handle, inode, credits, | ||
2009 | *lea_ino_array); | ||
1589 | goto cleanup; | 2010 | goto cleanup; |
2011 | } | ||
1590 | bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); | 2012 | bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); |
1591 | if (!bh) { | 2013 | if (!bh) { |
1592 | EXT4_ERROR_INODE(inode, "block %llu read error", | 2014 | EXT4_ERROR_INODE(inode, "block %llu read error", |
@@ -1599,11 +2021,69 @@ ext4_xattr_delete_inode(handle_t *handle, struct inode *inode) | |||
1599 | EXT4_I(inode)->i_file_acl); | 2021 | EXT4_I(inode)->i_file_acl); |
1600 | goto cleanup; | 2022 | goto cleanup; |
1601 | } | 2023 | } |
2024 | |||
2025 | for (entry = BFIRST(bh); !IS_LAST_ENTRY(entry); | ||
2026 | entry = EXT4_XATTR_NEXT(entry)) { | ||
2027 | if (!entry->e_value_inum) | ||
2028 | continue; | ||
2029 | if (ext4_expand_ino_array(lea_ino_array, | ||
2030 | entry->e_value_inum) != 0) | ||
2031 | goto cleanup; | ||
2032 | entry->e_value_inum = 0; | ||
2033 | } | ||
2034 | |||
2035 | /* add xattr inode to orphan list */ | ||
2036 | error = ext4_xattr_inode_orphan_add(handle, inode, credits, | ||
2037 | *lea_ino_array); | ||
2038 | if (error != 0) | ||
2039 | goto cleanup; | ||
2040 | |||
2041 | if (!IS_NOQUOTA(inode)) | ||
2042 | credits += 2 * EXT4_QUOTA_DEL_BLOCKS(inode->i_sb); | ||
2043 | |||
2044 | if (!ext4_handle_has_enough_credits(handle, credits)) { | ||
2045 | error = ext4_journal_extend(handle, credits); | ||
2046 | if (error > 0) | ||
2047 | error = ext4_journal_restart(handle, credits); | ||
2048 | if (error != 0) { | ||
2049 | ext4_warning(inode->i_sb, | ||
2050 | "couldn't extend journal (err %d)", error); | ||
2051 | goto cleanup; | ||
2052 | } | ||
2053 | } | ||
2054 | |||
1602 | ext4_xattr_release_block(handle, inode, bh); | 2055 | ext4_xattr_release_block(handle, inode, bh); |
1603 | EXT4_I(inode)->i_file_acl = 0; | 2056 | EXT4_I(inode)->i_file_acl = 0; |
1604 | 2057 | ||
1605 | cleanup: | 2058 | cleanup: |
1606 | brelse(bh); | 2059 | brelse(bh); |
2060 | |||
2061 | return error; | ||
2062 | } | ||
2063 | |||
2064 | void | ||
2065 | ext4_xattr_inode_array_free(struct inode *inode, | ||
2066 | struct ext4_xattr_ino_array *lea_ino_array) | ||
2067 | { | ||
2068 | struct inode *ea_inode = NULL; | ||
2069 | int idx = 0; | ||
2070 | int err; | ||
2071 | |||
2072 | if (lea_ino_array == NULL) | ||
2073 | return; | ||
2074 | |||
2075 | for (; idx < lea_ino_array->xia_count; ++idx) { | ||
2076 | ea_inode = ext4_xattr_inode_iget(inode, | ||
2077 | lea_ino_array->xia_inodes[idx], &err); | ||
2078 | if (err) | ||
2079 | continue; | ||
2080 | /* for inode's i_count get from ext4_xattr_delete_inode */ | ||
2081 | if (!list_empty(&EXT4_I(ea_inode)->i_orphan)) | ||
2082 | iput(ea_inode); | ||
2083 | clear_nlink(ea_inode); | ||
2084 | iput(ea_inode); | ||
2085 | } | ||
2086 | kfree(lea_ino_array); | ||
1607 | } | 2087 | } |
1608 | 2088 | ||
1609 | /* | 2089 | /* |
@@ -1655,10 +2135,9 @@ ext4_xattr_cmp(struct ext4_xattr_header *header1, | |||
1655 | entry1->e_name_index != entry2->e_name_index || | 2135 | entry1->e_name_index != entry2->e_name_index || |
1656 | entry1->e_name_len != entry2->e_name_len || | 2136 | entry1->e_name_len != entry2->e_name_len || |
1657 | entry1->e_value_size != entry2->e_value_size || | 2137 | entry1->e_value_size != entry2->e_value_size || |
2138 | entry1->e_value_inum != entry2->e_value_inum || | ||
1658 | memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) | 2139 | memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) |
1659 | return 1; | 2140 | return 1; |
1660 | if (entry1->e_value_block != 0 || entry2->e_value_block != 0) | ||
1661 | return -EFSCORRUPTED; | ||
1662 | if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), | 2141 | if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), |
1663 | (char *)header2 + le16_to_cpu(entry2->e_value_offs), | 2142 | (char *)header2 + le16_to_cpu(entry2->e_value_offs), |
1664 | le32_to_cpu(entry1->e_value_size))) | 2143 | le32_to_cpu(entry1->e_value_size))) |
@@ -1730,7 +2209,7 @@ static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header, | |||
1730 | *name++; | 2209 | *name++; |
1731 | } | 2210 | } |
1732 | 2211 | ||
1733 | if (entry->e_value_size != 0) { | 2212 | if (!entry->e_value_inum && entry->e_value_size) { |
1734 | __le32 *value = (__le32 *)((char *)header + | 2213 | __le32 *value = (__le32 *)((char *)header + |
1735 | le16_to_cpu(entry->e_value_offs)); | 2214 | le16_to_cpu(entry->e_value_offs)); |
1736 | for (n = (le32_to_cpu(entry->e_value_size) + | 2215 | for (n = (le32_to_cpu(entry->e_value_size) + |
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h index 099c8b670ef5..6e10ff9393d4 100644 --- a/fs/ext4/xattr.h +++ b/fs/ext4/xattr.h | |||
@@ -44,7 +44,7 @@ struct ext4_xattr_entry { | |||
44 | __u8 e_name_len; /* length of name */ | 44 | __u8 e_name_len; /* length of name */ |
45 | __u8 e_name_index; /* attribute name index */ | 45 | __u8 e_name_index; /* attribute name index */ |
46 | __le16 e_value_offs; /* offset in disk block of value */ | 46 | __le16 e_value_offs; /* offset in disk block of value */ |
47 | __le32 e_value_block; /* disk block attribute is stored on (n/i) */ | 47 | __le32 e_value_inum; /* inode in which the value is stored */ |
48 | __le32 e_value_size; /* size of attribute value */ | 48 | __le32 e_value_size; /* size of attribute value */ |
49 | __le32 e_hash; /* hash value of name and value */ | 49 | __le32 e_hash; /* hash value of name and value */ |
50 | char e_name[0]; /* attribute name */ | 50 | char e_name[0]; /* attribute name */ |
@@ -69,6 +69,26 @@ struct ext4_xattr_entry { | |||
69 | EXT4_I(inode)->i_extra_isize)) | 69 | EXT4_I(inode)->i_extra_isize)) |
70 | #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) | 70 | #define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) |
71 | 71 | ||
72 | /* | ||
73 | * Link EA inode back to parent one using i_mtime field. | ||
74 | * Extra integer type conversion added to ignore higher | ||
75 | * bits in i_mtime.tv_sec which might be set by ext4_get() | ||
76 | */ | ||
77 | #define EXT4_XATTR_INODE_SET_PARENT(inode, inum) \ | ||
78 | do { \ | ||
79 | (inode)->i_mtime.tv_sec = inum; \ | ||
80 | } while(0) | ||
81 | |||
82 | #define EXT4_XATTR_INODE_GET_PARENT(inode) \ | ||
83 | ((__u32)(inode)->i_mtime.tv_sec) | ||
84 | |||
85 | /* | ||
86 | * The minimum size of EA value when you start storing it in an external inode | ||
87 | * size of block - size of header - size of 1 entry - 4 null bytes | ||
88 | */ | ||
89 | #define EXT4_XATTR_MIN_LARGE_EA_SIZE(b) \ | ||
90 | ((b) - EXT4_XATTR_LEN(3) - sizeof(struct ext4_xattr_header) - 4) | ||
91 | |||
72 | #define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data)) | 92 | #define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data)) |
73 | #define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr)) | 93 | #define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr)) |
74 | #define BFIRST(bh) ENTRY(BHDR(bh)+1) | 94 | #define BFIRST(bh) ENTRY(BHDR(bh)+1) |
@@ -77,10 +97,11 @@ struct ext4_xattr_entry { | |||
77 | #define EXT4_ZERO_XATTR_VALUE ((void *)-1) | 97 | #define EXT4_ZERO_XATTR_VALUE ((void *)-1) |
78 | 98 | ||
79 | struct ext4_xattr_info { | 99 | struct ext4_xattr_info { |
80 | int name_index; | ||
81 | const char *name; | 100 | const char *name; |
82 | const void *value; | 101 | const void *value; |
83 | size_t value_len; | 102 | size_t value_len; |
103 | int name_index; | ||
104 | int in_inode; | ||
84 | }; | 105 | }; |
85 | 106 | ||
86 | struct ext4_xattr_search { | 107 | struct ext4_xattr_search { |
@@ -140,7 +161,13 @@ extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t); | |||
140 | extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int); | 161 | extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int); |
141 | extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int); | 162 | extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int); |
142 | 163 | ||
143 | extern void ext4_xattr_delete_inode(handle_t *, struct inode *); | 164 | extern struct inode *ext4_xattr_inode_iget(struct inode *parent, unsigned long ea_ino, |
165 | int *err); | ||
166 | extern int ext4_xattr_inode_unlink(struct inode *inode, unsigned long ea_ino); | ||
167 | extern int ext4_xattr_delete_inode(handle_t *handle, struct inode *inode, | ||
168 | struct ext4_xattr_ino_array **array); | ||
169 | extern void ext4_xattr_inode_array_free(struct inode *inode, | ||
170 | struct ext4_xattr_ino_array *array); | ||
144 | 171 | ||
145 | extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, | 172 | extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, |
146 | struct ext4_inode *raw_inode, handle_t *handle); | 173 | struct ext4_inode *raw_inode, handle_t *handle); |