Skip to content

Commit e50e512

Browse files
Andreas Dilgertytso
authored andcommitted
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>
1 parent e08ac99 commit e50e512

File tree

6 files changed

+604
-56
lines changed

6 files changed

+604
-56
lines changed

fs/ext4/ext4.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1797,6 +1797,7 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT)
17971797
EXT4_FEATURE_INCOMPAT_EXTENTS| \
17981798
EXT4_FEATURE_INCOMPAT_64BIT| \
17991799
EXT4_FEATURE_INCOMPAT_FLEX_BG| \
1800+
EXT4_FEATURE_INCOMPAT_EA_INODE| \
18001801
EXT4_FEATURE_INCOMPAT_MMP | \
18011802
EXT4_FEATURE_INCOMPAT_INLINE_DATA | \
18021803
EXT4_FEATURE_INCOMPAT_ENCRYPT | \
@@ -2230,6 +2231,12 @@ struct mmpd_data {
22302231
*/
22312232
#define EXT4_MMP_MAX_CHECK_INTERVAL 300UL
22322233

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+
22332240
/*
22342241
* Function prototypes
22352242
*/
@@ -2242,6 +2249,10 @@ struct mmpd_data {
22422249
# define ATTRIB_NORET __attribute__((noreturn))
22432250
# define NORET_AND noreturn,
22442251

2252+
struct ext4_xattr_ino_array {
2253+
unsigned int xia_count; /* # of used item in the array */
2254+
unsigned int xia_inodes[0];
2255+
};
22452256
/* bitmap.c */
22462257
extern unsigned int ext4_count_free(char *bitmap, unsigned numchars);
22472258
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);
24892500
extern void ext4_set_inode_flags(struct inode *);
24902501
extern int ext4_alloc_da_blocks(struct inode *inode);
24912502
extern void ext4_set_aops(struct inode *inode);
2503+
extern int ext4_meta_trans_blocks(struct inode *, int nrblocks, int chunk);
24922504
extern int ext4_writepage_trans_blocks(struct inode *);
24932505
extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
24942506
extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,

fs/ext4/ialloc.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,6 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
294294
* as writing the quota to disk may need the lock as well.
295295
*/
296296
dquot_initialize(inode);
297-
ext4_xattr_delete_inode(handle, inode);
298297
dquot_free_inode(inode);
299298
dquot_drop(inode);
300299

fs/ext4/inline.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static int get_max_inline_xattr_value_size(struct inode *inode,
6161

6262
/* Compute min_offs. */
6363
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) {
6565
size_t offs = le16_to_cpu(entry->e_value_offs);
6666
if (offs < min_offs)
6767
min_offs = offs;

fs/ext4/inode.c

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -139,8 +139,6 @@ static void ext4_invalidatepage(struct page *page, unsigned int offset,
139139
unsigned int length);
140140
static int __ext4_journalled_writepage(struct page *page, unsigned int len);
141141
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);
144142

145143
/*
146144
* Test whether an inode is a fast symlink.
@@ -189,6 +187,8 @@ void ext4_evict_inode(struct inode *inode)
189187
{
190188
handle_t *handle;
191189
int err;
190+
int extra_credits = 3;
191+
struct ext4_xattr_ino_array *lea_ino_array = NULL;
192192

193193
trace_ext4_evict_inode(inode);
194194

@@ -238,8 +238,8 @@ void ext4_evict_inode(struct inode *inode)
238238
* protection against it
239239
*/
240240
sb_start_intwrite(inode->i_sb);
241-
handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE,
242-
ext4_blocks_for_truncate(inode)+3);
241+
242+
handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, extra_credits);
243243
if (IS_ERR(handle)) {
244244
ext4_std_error(inode->i_sb, PTR_ERR(handle));
245245
/*
@@ -251,9 +251,36 @@ void ext4_evict_inode(struct inode *inode)
251251
sb_end_intwrite(inode->i_sb);
252252
goto no_delete;
253253
}
254-
255254
if (IS_SYNC(inode))
256255
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+
257284
inode->i_size = 0;
258285
err = ext4_mark_inode_dirty(handle, inode);
259286
if (err) {
@@ -277,10 +304,10 @@ void ext4_evict_inode(struct inode *inode)
277304
* enough credits left in the handle to remove the inode from
278305
* the orphan list and set the dtime field.
279306
*/
280-
if (!ext4_handle_has_enough_credits(handle, 3)) {
281-
err = ext4_journal_extend(handle, 3);
307+
if (!ext4_handle_has_enough_credits(handle, extra_credits)) {
308+
err = ext4_journal_extend(handle, extra_credits);
282309
if (err > 0)
283-
err = ext4_journal_restart(handle, 3);
310+
err = ext4_journal_restart(handle, extra_credits);
284311
if (err != 0) {
285312
ext4_warning(inode->i_sb,
286313
"couldn't extend journal (err %d)", err);
@@ -315,8 +342,12 @@ void ext4_evict_inode(struct inode *inode)
315342
ext4_clear_inode(inode);
316343
else
317344
ext4_free_inode(handle, inode);
345+
318346
ext4_journal_stop(handle);
319347
sb_end_intwrite(inode->i_sb);
348+
349+
if (lea_ino_array != NULL)
350+
ext4_xattr_inode_array_free(inode, lea_ino_array);
320351
return;
321352
no_delete:
322353
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,
55045535
*
55055536
* Also account for superblock, inode, quota and xattr blocks
55065537
*/
5507-
static int ext4_meta_trans_blocks(struct inode *inode, int lblocks,
5538+
int ext4_meta_trans_blocks(struct inode *inode, int lblocks,
55085539
int pextents)
55095540
{
55105541
ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb);

0 commit comments

Comments
 (0)