kernfs: fix missing kernfs_iattr_rwsem locking

JIRA: https://issues.redhat.com/browse/RHEL-52956
Upstream status: Linus

commit 0559f63057f927d298d68294d6ff77ce09b99255
Author: Ian Kent <raven@themaw.net>
Date:   Sun Aug 6 09:26:49 2023 +0800

    kernfs: fix missing kernfs_iattr_rwsem locking

    When the kernfs_iattr_rwsem was introduced a case was missed.

    The update of the kernfs directory node child count was also protected
    by the kernfs_rwsem and needs to be included in the change so that the
    child count (and so the inode n_link attribute) does not change while
    holding the rwsem for read.

    Fixes: 9caf69614225 ("kernfs: Introduce separate rwsem to protect inode attributes.")
    Cc: stable <stable@kernel.org>
    Signed-off-by: Ian Kent <raven@themaw.net>
    Reviewed-By: Imran Khan <imran.f.khan@oracle.com>
    Acked-by: Miklos Szeredi <mszeredi@redhat.com>
    Cc: Anders Roxell <anders.roxell@linaro.org>
    Cc: Arnd Bergmann <arnd@arndb.de>
    Cc: Minchan Kim <minchan@kernel.org>
    Cc: Eric Sandeen <sandeen@sandeen.net>
    Link: https://lore.kernel.org/r/169128520941.68052.15749253469930138901.stgit@donald.themaw.net
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Signed-off-by: Ian Kent <ikent@redhat.com>
This commit is contained in:
Ian Kent 2024-08-07 10:29:12 +08:00
parent cafaee9ad8
commit e203ef12dc
1 changed files with 4 additions and 0 deletions

View File

@ -374,9 +374,11 @@ static int kernfs_link_sibling(struct kernfs_node *kn)
rb_insert_color(&kn->rb, &kn->parent->dir.children); rb_insert_color(&kn->rb, &kn->parent->dir.children);
/* successfully added, account subdir number */ /* successfully added, account subdir number */
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
if (kernfs_type(kn) == KERNFS_DIR) if (kernfs_type(kn) == KERNFS_DIR)
kn->parent->dir.subdirs++; kn->parent->dir.subdirs++;
kernfs_inc_rev(kn->parent); kernfs_inc_rev(kn->parent);
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
return 0; return 0;
} }
@ -397,9 +399,11 @@ static bool kernfs_unlink_sibling(struct kernfs_node *kn)
if (RB_EMPTY_NODE(&kn->rb)) if (RB_EMPTY_NODE(&kn->rb))
return false; return false;
down_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
if (kernfs_type(kn) == KERNFS_DIR) if (kernfs_type(kn) == KERNFS_DIR)
kn->parent->dir.subdirs--; kn->parent->dir.subdirs--;
kernfs_inc_rev(kn->parent); kernfs_inc_rev(kn->parent);
up_write(&kernfs_root(kn)->kernfs_iattr_rwsem);
rb_erase(&kn->rb, &kn->parent->dir.children); rb_erase(&kn->rb, &kn->parent->dir.children);
RB_CLEAR_NODE(&kn->rb); RB_CLEAR_NODE(&kn->rb);