Skip to content

Commit c03b45b

Browse files
miaoxietytso
authored andcommitted
ext4, project: expand inode extra size if possible
When upgrading from old format, try to set project id to old file first time, it will return EOVERFLOW, but if that file is dirtied(touch etc), changing project id will be allowed, this might be confusing for users, we could try to expand @i_extra_isize here too. Reported-by: Zhang Yi <yi.zhang@huawei.com> Signed-off-by: Miao Xie <miaoxie@huawei.com> Signed-off-by: Wang Shilong <wshilong@ddn.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent b640b2c commit c03b45b

File tree

3 files changed

+85
-24
lines changed

3 files changed

+85
-24
lines changed

fs/ext4/ext4_jbd2.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ int ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
227227

228228
int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
229229

230+
int ext4_expand_extra_isize(struct inode *inode,
231+
unsigned int new_extra_isize,
232+
struct ext4_iloc *iloc);
230233
/*
231234
* Wrapper functions with which ext4 calls into JBD.
232235
*/

fs/ext4/inode.c

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5702,6 +5702,42 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
57025702
return err;
57035703
}
57045704

5705+
static int __ext4_expand_extra_isize(struct inode *inode,
5706+
unsigned int new_extra_isize,
5707+
struct ext4_iloc *iloc,
5708+
handle_t *handle, int *no_expand)
5709+
{
5710+
struct ext4_inode *raw_inode;
5711+
struct ext4_xattr_ibody_header *header;
5712+
int error;
5713+
5714+
raw_inode = ext4_raw_inode(iloc);
5715+
5716+
header = IHDR(inode, raw_inode);
5717+
5718+
/* No extended attributes present */
5719+
if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
5720+
header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
5721+
memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
5722+
EXT4_I(inode)->i_extra_isize, 0,
5723+
new_extra_isize - EXT4_I(inode)->i_extra_isize);
5724+
EXT4_I(inode)->i_extra_isize = new_extra_isize;
5725+
return 0;
5726+
}
5727+
5728+
/* try to expand with EAs present */
5729+
error = ext4_expand_extra_isize_ea(inode, new_extra_isize,
5730+
raw_inode, handle);
5731+
if (error) {
5732+
/*
5733+
* Inode size expansion failed; don't try again
5734+
*/
5735+
*no_expand = 1;
5736+
}
5737+
5738+
return error;
5739+
}
5740+
57055741
/*
57065742
* Expand an inode by new_extra_isize bytes.
57075743
* Returns 0 on success or negative error number on failure.
@@ -5711,8 +5747,6 @@ static int ext4_try_to_expand_extra_isize(struct inode *inode,
57115747
struct ext4_iloc iloc,
57125748
handle_t *handle)
57135749
{
5714-
struct ext4_inode *raw_inode;
5715-
struct ext4_xattr_ibody_header *header;
57165750
int no_expand;
57175751
int error;
57185752

@@ -5736,32 +5770,53 @@ static int ext4_try_to_expand_extra_isize(struct inode *inode,
57365770
if (ext4_write_trylock_xattr(inode, &no_expand) == 0)
57375771
return -EBUSY;
57385772

5739-
raw_inode = ext4_raw_inode(&iloc);
5773+
error = __ext4_expand_extra_isize(inode, new_extra_isize, &iloc,
5774+
handle, &no_expand);
5775+
ext4_write_unlock_xattr(inode, &no_expand);
57405776

5741-
header = IHDR(inode, raw_inode);
5777+
return error;
5778+
}
57425779

5743-
/* No extended attributes present */
5744-
if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) ||
5745-
header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) {
5746-
memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE +
5747-
EXT4_I(inode)->i_extra_isize, 0,
5748-
new_extra_isize - EXT4_I(inode)->i_extra_isize);
5749-
EXT4_I(inode)->i_extra_isize = new_extra_isize;
5750-
ext4_write_unlock_xattr(inode, &no_expand);
5751-
return 0;
5780+
int ext4_expand_extra_isize(struct inode *inode,
5781+
unsigned int new_extra_isize,
5782+
struct ext4_iloc *iloc)
5783+
{
5784+
handle_t *handle;
5785+
int no_expand;
5786+
int error, rc;
5787+
5788+
if (ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) {
5789+
brelse(iloc->bh);
5790+
return -EOVERFLOW;
57525791
}
57535792

5754-
/* try to expand with EAs present */
5755-
error = ext4_expand_extra_isize_ea(inode, new_extra_isize,
5756-
raw_inode, handle);
5793+
handle = ext4_journal_start(inode, EXT4_HT_INODE,
5794+
EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
5795+
if (IS_ERR(handle)) {
5796+
error = PTR_ERR(handle);
5797+
brelse(iloc->bh);
5798+
return error;
5799+
}
5800+
5801+
ext4_write_lock_xattr(inode, &no_expand);
5802+
5803+
BUFFER_TRACE(iloc.bh, "get_write_access");
5804+
error = ext4_journal_get_write_access(handle, iloc->bh);
57575805
if (error) {
5758-
/*
5759-
* Inode size expansion failed; don't try again
5760-
*/
5761-
no_expand = 1;
5806+
brelse(iloc->bh);
5807+
goto out_stop;
57625808
}
5763-
ext4_write_unlock_xattr(inode, &no_expand);
57645809

5810+
error = __ext4_expand_extra_isize(inode, new_extra_isize, iloc,
5811+
handle, &no_expand);
5812+
5813+
rc = ext4_mark_iloc_dirty(handle, inode, iloc);
5814+
if (!error)
5815+
error = rc;
5816+
5817+
ext4_write_unlock_xattr(inode, &no_expand);
5818+
out_stop:
5819+
ext4_journal_stop(handle);
57655820
return error;
57665821
}
57675822

fs/ext4/ioctl.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,14 @@ static int ext4_ioctl_setproject(struct file *filp, __u32 projid)
349349

350350
raw_inode = ext4_raw_inode(&iloc);
351351
if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) {
352-
err = -EOVERFLOW;
352+
err = ext4_expand_extra_isize(inode,
353+
EXT4_SB(sb)->s_want_extra_isize,
354+
&iloc);
355+
if (err)
356+
goto out_unlock;
357+
} else {
353358
brelse(iloc.bh);
354-
goto out_unlock;
355359
}
356-
brelse(iloc.bh);
357360

358361
dquot_initialize(inode);
359362

0 commit comments

Comments
 (0)