[ Sasha's backport helper bot ]
Hi,
✅ All tests passed successfully. No issues detected. No action required from the submitter.
The upstream commit SHA1 provided is correct: 7ba0273b2f34a55efe967d3c7381fb1da2ca195f
WARNING: Author mismatch between patch and upstream commit: Backport author: Qingfang Dengdqfext@gmail.com Commit author: Ian Kentraven@themaw.net
Status in newer kernel trees: 6.14.y | Present (exact SHA1) 6.12.y | Present (exact SHA1) 6.6.y | Present (exact SHA1) 6.1.y | Present (exact SHA1) 5.15.y | Present (exact SHA1)
Note: The patch differs from the upstream commit: --- 1: 7ba0273b2f34a ! 1: a0418b6d194c8 kernfs: switch kernfs to use an rwsem @@ Metadata ## Commit message ## kernfs: switch kernfs to use an rwsem
+ Commit 7ba0273b2f34a55efe967d3c7381fb1da2ca195f upstream. + The kernfs global lock restricts the ability to perform kernfs node lookup operations in parallel during path walks.
@@ fs/kernfs/dir.c -DEFINE_MUTEX(kernfs_mutex); +DECLARE_RWSEM(kernfs_rwsem); static DEFINE_SPINLOCK(kernfs_rename_lock); /* kn->parent and ->name */ - static char kernfs_pr_cont_buf[PATH_MAX]; /* protected by rename_lock */ - static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */ + /* + * Don't use rename_lock to piggy back on pr_cont_buf. We don't want to @@ fs/kernfs/dir.c: static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */
static bool kernfs_active(struct kernfs_node *kn) @@ fs/kernfs/dir.c: static void kernfs_drain(struct kernfs_node *kn) }
/** +@@ fs/kernfs/dir.c: static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) + /* If the kernfs parent node has changed discard and + * proceed to ->lookup. + */ +- mutex_lock(&kernfs_mutex); ++ down_read(&kernfs_rwsem); + spin_lock(&dentry->d_lock); + parent = kernfs_dentry_node(dentry->d_parent); + if (parent) { + if (kernfs_dir_changed(parent, dentry)) { + spin_unlock(&dentry->d_lock); +- mutex_unlock(&kernfs_mutex); ++ up_read(&kernfs_rwsem); + return 0; + } + } + spin_unlock(&dentry->d_lock); +- mutex_unlock(&kernfs_mutex); ++ up_read(&kernfs_rwsem); + + /* The kernfs parent node hasn't changed, leave the + * dentry negative and return success. +@@ fs/kernfs/dir.c: static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) + } + + kn = kernfs_dentry_node(dentry); +- mutex_lock(&kernfs_mutex); ++ down_read(&kernfs_rwsem); + + /* The kernfs node has been deactivated */ + if (!kernfs_active(kn)) +@@ fs/kernfs/dir.c: static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) + kernfs_info(dentry->d_sb)->ns != kn->ns) + goto out_bad; + +- mutex_unlock(&kernfs_mutex); ++ up_read(&kernfs_rwsem); + return 1; + out_bad: +- mutex_unlock(&kernfs_mutex); ++ up_read(&kernfs_rwsem); + return 0; + } + @@ fs/kernfs/dir.c: int kernfs_add_one(struct kernfs_node *kn) bool has_ns; int ret; @@ fs/kernfs/dir.c: static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *p - lockdep_assert_held(&kernfs_mutex); + lockdep_assert_held_read(&kernfs_rwsem);
- /* grab kernfs_rename_lock to piggy back on kernfs_pr_cont_buf */ - spin_lock_irq(&kernfs_rename_lock); + spin_lock_irq(&kernfs_pr_cont_lock); + @@ fs/kernfs/dir.c: struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, { struct kernfs_node *kn; @@ fs/kernfs/dir.c: struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *
return kn; } -@@ fs/kernfs/dir.c: static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) - /* If the kernfs parent node has changed discard and - * proceed to ->lookup. - */ -- mutex_lock(&kernfs_mutex); -+ down_read(&kernfs_rwsem); - spin_lock(&dentry->d_lock); - parent = kernfs_dentry_node(dentry->d_parent); - if (parent) { - if (kernfs_dir_changed(parent, dentry)) { - spin_unlock(&dentry->d_lock); -- mutex_unlock(&kernfs_mutex); -+ up_read(&kernfs_rwsem); - return 0; - } - } - spin_unlock(&dentry->d_lock); -- mutex_unlock(&kernfs_mutex); -+ up_read(&kernfs_rwsem); - - /* The kernfs parent node hasn't changed, leave the - * dentry negative and return success. -@@ fs/kernfs/dir.c: static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) - } - - kn = kernfs_dentry_node(dentry); -- mutex_lock(&kernfs_mutex); -+ down_read(&kernfs_rwsem); - - /* The kernfs node has been deactivated */ - if (!kernfs_active(kn)) -@@ fs/kernfs/dir.c: static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) - kernfs_info(dentry->d_sb)->ns != kn->ns) - goto out_bad; - -- mutex_unlock(&kernfs_mutex); -+ up_read(&kernfs_rwsem); - return 1; - out_bad: -- mutex_unlock(&kernfs_mutex); -+ up_read(&kernfs_rwsem); - return 0; - } - @@ fs/kernfs/dir.c: static struct dentry *kernfs_iop_lookup(struct inode *dir, struct inode *inode = NULL; const void *ns = NULL; @@ fs/kernfs/dir.c: int kernfs_remove_by_name_ns(struct kernfs_node *parent, const + down_write(&kernfs_rwsem);
kn = kernfs_find_ns(parent, name, ns); - if (kn) - __kernfs_remove(kn); + if (kn) { +@@ fs/kernfs/dir.c: int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, + kernfs_put(kn); + }
- mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem); @@ fs/kernfs/inode.c: int kernfs_setattr(struct kernfs_node *kn, const struct iattr return ret; }
-@@ fs/kernfs/inode.c: int kernfs_iop_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, +@@ fs/kernfs/inode.c: int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr) if (!kn) return -EINVAL;
- mutex_lock(&kernfs_mutex); + down_write(&kernfs_rwsem); - error = setattr_prepare(&init_user_ns, dentry, iattr); + error = setattr_prepare(dentry, iattr); if (error) goto out; -@@ fs/kernfs/inode.c: int kernfs_iop_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, - setattr_copy(&init_user_ns, inode, iattr); +@@ fs/kernfs/inode.c: int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr) + setattr_copy(inode, iattr);
out: - mutex_unlock(&kernfs_mutex); @@ fs/kernfs/inode.c: int kernfs_iop_setattr(struct user_namespace *mnt_userns, str return error; }
-@@ fs/kernfs/inode.c: int kernfs_iop_getattr(struct user_namespace *mnt_userns, +@@ fs/kernfs/inode.c: int kernfs_iop_getattr(const struct path *path, struct kstat *stat, struct inode *inode = d_inode(path->dentry); struct kernfs_node *kn = inode->i_private;
@@ fs/kernfs/inode.c: int kernfs_iop_getattr(struct user_namespace *mnt_userns, - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem);
- generic_fillattr(&init_user_ns, inode, stat); + generic_fillattr(inode, stat); return 0; -@@ fs/kernfs/inode.c: int kernfs_iop_permission(struct user_namespace *mnt_userns, +@@ fs/kernfs/inode.c: int kernfs_iop_permission(struct inode *inode, int mask)
kn = inode->i_private;
@@ fs/kernfs/inode.c: int kernfs_iop_permission(struct user_namespace *mnt_userns, - mutex_unlock(&kernfs_mutex); + up_write(&kernfs_rwsem);
- return generic_permission(&init_user_ns, inode, mask); + return generic_permission(inode, mask); }
## fs/kernfs/kernfs-internal.h ## ---
Results of testing on various branches:
| Branch | Patch Apply | Build Test | |---------------------------|-------------|------------| | stable/linux-5.15.y | Success | Success |