diff options
author | Ian Kent <[email protected]> | 2023-08-06 09:26:49 +0800 |
---|---|---|
committer | Greg Kroah-Hartman <[email protected]> | 2023-08-12 13:05:47 +0200 |
commit | 0559f63057f927d298d68294d6ff77ce09b99255 (patch) | |
tree | c979d4f746f7d9e8d308b52cb8c57dd199193ad9 | |
parent | bbaee49cce7c815d1bd6d95b6020b5fe33ba561a (diff) |
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 <[email protected]>
Signed-off-by: Ian Kent <[email protected]>
Reviewed-By: Imran Khan <[email protected]>
Acked-by: Miklos Szeredi <[email protected]>
Cc: Anders Roxell <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Minchan Kim <[email protected]>
Cc: Eric Sandeen <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Greg Kroah-Hartman <[email protected]>
-rw-r--r-- | fs/kernfs/dir.c | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c index 5a1a4af9d3d2..bf243015834e 100644 --- a/fs/kernfs/dir.c +++ b/fs/kernfs/dir.c @@ -383,9 +383,11 @@ static int kernfs_link_sibling(struct kernfs_node *kn) rb_insert_color(&kn->rb, &kn->parent->dir.children); /* successfully added, account subdir number */ + down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); if (kernfs_type(kn) == KERNFS_DIR) kn->parent->dir.subdirs++; kernfs_inc_rev(kn->parent); + up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); return 0; } @@ -408,9 +410,11 @@ static bool kernfs_unlink_sibling(struct kernfs_node *kn) if (RB_EMPTY_NODE(&kn->rb)) return false; + down_write(&kernfs_root(kn)->kernfs_iattr_rwsem); if (kernfs_type(kn) == KERNFS_DIR) kn->parent->dir.subdirs--; kernfs_inc_rev(kn->parent); + up_write(&kernfs_root(kn)->kernfs_iattr_rwsem); rb_erase(&kn->rb, &kn->parent->dir.children); RB_CLEAR_NODE(&kn->rb); |