]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ext4: fix leak of quota reservations
authorJan Kara <jack@suse.cz>
Fri, 8 Nov 2019 11:45:11 +0000 (12:45 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 17 Dec 2019 18:56:53 +0000 (19:56 +0100)
commit f4c2d372b89a1e504ebb7b7eb3e29b8306479366 upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ext4/ialloc.c
fs/ext4/super.c

index 764ff4c56233f8d66da4f2eff3ba28c5ea430a49..564e2ceb841718baa9478ec2c03d0decf54c2047 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 73578359d45163d570e3060a3ee0102b4dae9fa4..98d37b8d005011e09d330740d839c2ac90477ee5 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);