ext4: fix leak of quota reservations
authorJan Kara <jack@suse.cz>
Fri, 8 Nov 2019 11:45:11 +0000 (12:45 +0100)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 15 Nov 2019 00:25:47 +0000 (19:25 -0500)
Commit 8fcc3a580651 ("ext4: rework reserved cluster accounting when
invalidating pages") moved freeing of delayed allocation reservations
from dirty page invalidation time to time when we evict corresponding
status extent from extent status tree. For inodes which don't have any
blocks allocated this may actually happen only in ext4_clear_blocks()
which is after we've dropped references to quota structures from the
inode. Thus reservation of quota leaked. Fix the problem by clearing
quota information from the inode only after evicting extent status tree
in ext4_clear_inode().

Link: https://lore.kernel.org/r/20191108115420.GI20863@quack2.suse.cz
Reported-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
Fixes: 8fcc3a580651 ("ext4: rework reserved cluster accounting when invalidating pages")
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/ialloc.c
fs/ext4/super.c

index fa8c3c485e4bc79f712295dfa622e86a927f67b4..dc333e8e51e89a4951f02b0fbc2a91cf32434a59 100644 (file)
@@ -265,13 +265,8 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
        ext4_debug("freeing inode %lu\n", ino);
        trace_ext4_free_inode(inode);
 
-       /*
-        * Note: we must free any quota before locking the superblock,
-        * as writing the quota to disk may need the lock as well.
-        */
        dquot_initialize(inode);
        dquot_free_inode(inode);
-       dquot_drop(inode);
 
        is_directory = S_ISDIR(inode->i_mode);
 
index 19f0ea9d6b5df8e5027c5e380557bd0ff01c5b82..4e80bdee5b0f791bce7378475fa7affece1d14b2 100644 (file)
@@ -1172,9 +1172,9 @@ void ext4_clear_inode(struct inode *inode)
 {
        invalidate_inode_buffers(inode);
        clear_inode(inode);
-       dquot_drop(inode);
        ext4_discard_preallocations(inode);
        ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
+       dquot_drop(inode);
        if (EXT4_I(inode)->jinode) {
                jbd2_journal_release_jbd_inode(EXT4_JOURNAL(inode),
                                               EXT4_I(inode)->jinode);