mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
ext4: update quota information while swapping boot loader inode
While do swap between two inode, they swap i_data without update quota information. Also, swap_inode_boot_loader can do "revert" somtimes, so update the quota while all operations has been finished. Signed-off-by: yangerkun <yangerkun@huawei.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@kernel.org
This commit is contained in:
parent
a46c68a318
commit
aa507b5faf
1 changed files with 43 additions and 13 deletions
|
@ -68,8 +68,6 @@ static void swap_inode_data(struct inode *inode1, struct inode *inode2)
|
|||
ei2 = EXT4_I(inode2);
|
||||
|
||||
swap(inode1->i_version, inode2->i_version);
|
||||
swap(inode1->i_blocks, inode2->i_blocks);
|
||||
swap(inode1->i_bytes, inode2->i_bytes);
|
||||
swap(inode1->i_atime, inode2->i_atime);
|
||||
swap(inode1->i_mtime, inode2->i_mtime);
|
||||
|
||||
|
@ -115,6 +113,9 @@ static long swap_inode_boot_loader(struct super_block *sb,
|
|||
int err;
|
||||
struct inode *inode_bl;
|
||||
struct ext4_inode_info *ei_bl;
|
||||
qsize_t size, size_bl, diff;
|
||||
blkcnt_t blocks;
|
||||
unsigned short bytes;
|
||||
|
||||
inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO, EXT4_IGET_SPECIAL);
|
||||
if (IS_ERR(inode_bl))
|
||||
|
@ -180,6 +181,13 @@ static long swap_inode_boot_loader(struct super_block *sb,
|
|||
memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data));
|
||||
}
|
||||
|
||||
err = dquot_initialize(inode);
|
||||
if (err)
|
||||
goto err_out1;
|
||||
|
||||
size = (qsize_t)(inode->i_blocks) * (1 << 9) + inode->i_bytes;
|
||||
size_bl = (qsize_t)(inode_bl->i_blocks) * (1 << 9) + inode_bl->i_bytes;
|
||||
diff = size - size_bl;
|
||||
swap_inode_data(inode, inode_bl);
|
||||
|
||||
inode->i_ctime = inode_bl->i_ctime = current_time(inode);
|
||||
|
@ -193,24 +201,46 @@ static long swap_inode_boot_loader(struct super_block *sb,
|
|||
|
||||
err = ext4_mark_inode_dirty(handle, inode);
|
||||
if (err < 0) {
|
||||
/* No need to update quota information. */
|
||||
ext4_warning(inode->i_sb,
|
||||
"couldn't mark inode #%lu dirty (err %d)",
|
||||
inode->i_ino, err);
|
||||
/* Revert all changes: */
|
||||
swap_inode_data(inode, inode_bl);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
} else {
|
||||
err = ext4_mark_inode_dirty(handle, inode_bl);
|
||||
if (err < 0) {
|
||||
ext4_warning(inode_bl->i_sb,
|
||||
"couldn't mark inode #%lu dirty (err %d)",
|
||||
inode_bl->i_ino, err);
|
||||
/* Revert all changes: */
|
||||
swap_inode_data(inode, inode_bl);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ext4_mark_inode_dirty(handle, inode_bl);
|
||||
}
|
||||
goto err_out1;
|
||||
}
|
||||
|
||||
blocks = inode_bl->i_blocks;
|
||||
bytes = inode_bl->i_bytes;
|
||||
inode_bl->i_blocks = inode->i_blocks;
|
||||
inode_bl->i_bytes = inode->i_bytes;
|
||||
err = ext4_mark_inode_dirty(handle, inode_bl);
|
||||
if (err < 0) {
|
||||
/* No need to update quota information. */
|
||||
ext4_warning(inode_bl->i_sb,
|
||||
"couldn't mark inode #%lu dirty (err %d)",
|
||||
inode_bl->i_ino, err);
|
||||
goto revert;
|
||||
}
|
||||
|
||||
/* Bootloader inode should not be counted into quota information. */
|
||||
if (diff > 0)
|
||||
dquot_free_space(inode, diff);
|
||||
else
|
||||
err = dquot_alloc_space(inode, -1 * diff);
|
||||
|
||||
if (err < 0) {
|
||||
revert:
|
||||
/* Revert all changes: */
|
||||
inode_bl->i_blocks = blocks;
|
||||
inode_bl->i_bytes = bytes;
|
||||
swap_inode_data(inode, inode_bl);
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
ext4_mark_inode_dirty(handle, inode_bl);
|
||||
}
|
||||
|
||||
err_out1:
|
||||
ext4_journal_stop(handle);
|
||||
ext4_double_up_write_data_sem(inode, inode_bl);
|
||||
|
||||
|
|
Loading…
Reference in a new issue