mirror of
https://github.com/hardkernel/linux.git
synced 2026-03-25 20:10:23 +09:00
UPSTREAM: kernfs: switch global kernfs_rwsem lock to per-fs lock
The kernfs implementation has big lock granularity(kernfs_rwsem) so
every kernfs-based(e.g., sysfs, cgroup) fs are able to compete the
lock. It makes trouble for some cases to wait the global lock
for a long time even though they are totally independent contexts
each other.
A general example is process A goes under direct reclaim with holding
the lock when it accessed the file in sysfs and process B is waiting
the lock with exclusive mode and then process C is waiting the lock
until process B could finish the job after it gets the lock from
process A.
This patch switches the global kernfs_rwsem to per-fs lock, which
put the rwsem into kernfs_root.
Suggested-by: Tejun Heo <tj@kernel.org>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Minchan Kim <minchan@kernel.org>
Link: https://lore.kernel.org/r/20211118230008.2679780-1-minchan@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 393c371408)
Bug: 320903885
Bug: 219424218
Bug: 206126556
Change-Id: I5f942f7a4a18b3c2198496fea789b381ba955d19
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
This commit is contained in:
committed by
Suren Baghdasaryan
parent
73ba66a3c5
commit
d8dbc91f9a
110
fs/kernfs/dir.c
110
fs/kernfs/dir.c
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "kernfs-internal.h"
|
||||
|
||||
DECLARE_RWSEM(kernfs_rwsem);
|
||||
static DEFINE_SPINLOCK(kernfs_rename_lock); /* kn->parent and ->name */
|
||||
/*
|
||||
* Don't use rename_lock to piggy back on pr_cont_buf. We don't want to
|
||||
@@ -34,7 +33,7 @@ static DEFINE_SPINLOCK(kernfs_idr_lock); /* root->ino_idr */
|
||||
|
||||
static bool kernfs_active(struct kernfs_node *kn)
|
||||
{
|
||||
lockdep_assert_held(&kernfs_rwsem);
|
||||
lockdep_assert_held(&kernfs_root(kn)->kernfs_rwsem);
|
||||
return atomic_read(&kn->active) >= 0;
|
||||
}
|
||||
|
||||
@@ -465,14 +464,15 @@ void kernfs_put_active(struct kernfs_node *kn)
|
||||
* return after draining is complete.
|
||||
*/
|
||||
static void kernfs_drain(struct kernfs_node *kn)
|
||||
__releases(&kernfs_rwsem) __acquires(&kernfs_rwsem)
|
||||
__releases(&kernfs_root(kn)->kernfs_rwsem)
|
||||
__acquires(&kernfs_root(kn)->kernfs_rwsem)
|
||||
{
|
||||
struct kernfs_root *root = kernfs_root(kn);
|
||||
|
||||
lockdep_assert_held_write(&kernfs_rwsem);
|
||||
lockdep_assert_held_write(&root->kernfs_rwsem);
|
||||
WARN_ON_ONCE(kernfs_active(kn));
|
||||
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
|
||||
if (kernfs_lockdep(kn)) {
|
||||
rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
|
||||
@@ -491,7 +491,7 @@ static void kernfs_drain(struct kernfs_node *kn)
|
||||
|
||||
kernfs_drain_open_files(kn);
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -728,11 +728,12 @@ err_unlock:
|
||||
int kernfs_add_one(struct kernfs_node *kn)
|
||||
{
|
||||
struct kernfs_node *parent = kn->parent;
|
||||
struct kernfs_root *root = kernfs_root(parent);
|
||||
struct kernfs_iattrs *ps_iattr;
|
||||
bool has_ns;
|
||||
int ret;
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
|
||||
ret = -EINVAL;
|
||||
has_ns = kernfs_ns_enabled(parent);
|
||||
@@ -763,7 +764,7 @@ int kernfs_add_one(struct kernfs_node *kn)
|
||||
ps_iattr->ia_mtime = ps_iattr->ia_ctime;
|
||||
}
|
||||
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
|
||||
/*
|
||||
* Activate the new node unless CREATE_DEACTIVATED is requested.
|
||||
@@ -777,7 +778,7 @@ int kernfs_add_one(struct kernfs_node *kn)
|
||||
return 0;
|
||||
|
||||
out_unlock:
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -798,7 +799,7 @@ static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent,
|
||||
bool has_ns = kernfs_ns_enabled(parent);
|
||||
unsigned int hash;
|
||||
|
||||
lockdep_assert_held(&kernfs_rwsem);
|
||||
lockdep_assert_held(&kernfs_root(parent)->kernfs_rwsem);
|
||||
|
||||
if (has_ns != (bool)ns) {
|
||||
WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
|
||||
@@ -830,7 +831,7 @@ static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent,
|
||||
size_t len;
|
||||
char *p, *name;
|
||||
|
||||
lockdep_assert_held_read(&kernfs_rwsem);
|
||||
lockdep_assert_held_read(&kernfs_root(parent)->kernfs_rwsem);
|
||||
|
||||
spin_lock_irq(&kernfs_pr_cont_lock);
|
||||
|
||||
@@ -868,11 +869,12 @@ struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent,
|
||||
const char *name, const void *ns)
|
||||
{
|
||||
struct kernfs_node *kn;
|
||||
struct kernfs_root *root = kernfs_root(parent);
|
||||
|
||||
down_read(&kernfs_rwsem);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
kn = kernfs_find_ns(parent, name, ns);
|
||||
kernfs_get(kn);
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
|
||||
return kn;
|
||||
}
|
||||
@@ -892,11 +894,12 @@ struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent,
|
||||
const char *path, const void *ns)
|
||||
{
|
||||
struct kernfs_node *kn;
|
||||
struct kernfs_root *root = kernfs_root(parent);
|
||||
|
||||
down_read(&kernfs_rwsem);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
kn = kernfs_walk_ns(parent, path, ns);
|
||||
kernfs_get(kn);
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
|
||||
return kn;
|
||||
}
|
||||
@@ -921,6 +924,7 @@ struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
idr_init(&root->ino_idr);
|
||||
init_rwsem(&root->kernfs_rwsem);
|
||||
INIT_LIST_HEAD(&root->supers);
|
||||
|
||||
/*
|
||||
@@ -1044,6 +1048,7 @@ struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent,
|
||||
static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct kernfs_node *kn;
|
||||
struct kernfs_root *root;
|
||||
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
@@ -1055,18 +1060,19 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
/* If the kernfs parent node has changed discard and
|
||||
* proceed to ->lookup.
|
||||
*/
|
||||
down_read(&kernfs_rwsem);
|
||||
spin_lock(&dentry->d_lock);
|
||||
parent = kernfs_dentry_node(dentry->d_parent);
|
||||
if (parent) {
|
||||
spin_unlock(&dentry->d_lock);
|
||||
root = kernfs_root(parent);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
if (kernfs_dir_changed(parent, dentry)) {
|
||||
spin_unlock(&dentry->d_lock);
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
spin_unlock(&dentry->d_lock);
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
} else
|
||||
spin_unlock(&dentry->d_lock);
|
||||
|
||||
/* The kernfs parent node hasn't changed, leave the
|
||||
* dentry negative and return success.
|
||||
@@ -1075,7 +1081,8 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
}
|
||||
|
||||
kn = kernfs_dentry_node(dentry);
|
||||
down_read(&kernfs_rwsem);
|
||||
root = kernfs_root(kn);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
|
||||
/* The kernfs node has been deactivated */
|
||||
if (!kernfs_active(kn))
|
||||
@@ -1094,10 +1101,10 @@ static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
kernfs_info(dentry->d_sb)->ns != kn->ns)
|
||||
goto out_bad;
|
||||
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
return 1;
|
||||
out_bad:
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1111,10 +1118,12 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
|
||||
{
|
||||
struct kernfs_node *parent = dir->i_private;
|
||||
struct kernfs_node *kn;
|
||||
struct kernfs_root *root;
|
||||
struct inode *inode = NULL;
|
||||
const void *ns = NULL;
|
||||
|
||||
down_read(&kernfs_rwsem);
|
||||
root = kernfs_root(parent);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
if (kernfs_ns_enabled(parent))
|
||||
ns = kernfs_info(dir->i_sb)->ns;
|
||||
|
||||
@@ -1125,7 +1134,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
|
||||
* create a negative.
|
||||
*/
|
||||
if (!kernfs_active(kn)) {
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
return NULL;
|
||||
}
|
||||
inode = kernfs_get_inode(dir->i_sb, kn);
|
||||
@@ -1140,7 +1149,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
|
||||
*/
|
||||
if (!IS_ERR(inode))
|
||||
kernfs_set_rev(parent, dentry);
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
|
||||
/* instantiate and hash (possibly negative) dentry */
|
||||
return d_splice_alias(inode, dentry);
|
||||
@@ -1263,7 +1272,7 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
|
||||
{
|
||||
struct rb_node *rbn;
|
||||
|
||||
lockdep_assert_held_write(&kernfs_rwsem);
|
||||
lockdep_assert_held_write(&kernfs_root(root)->kernfs_rwsem);
|
||||
|
||||
/* if first iteration, visit leftmost descendant which may be root */
|
||||
if (!pos)
|
||||
@@ -1298,8 +1307,9 @@ static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
|
||||
void kernfs_activate(struct kernfs_node *kn)
|
||||
{
|
||||
struct kernfs_node *pos;
|
||||
struct kernfs_root *root = kernfs_root(kn);
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
|
||||
pos = NULL;
|
||||
while ((pos = kernfs_next_descendant_post(pos, kn))) {
|
||||
@@ -1313,14 +1323,14 @@ void kernfs_activate(struct kernfs_node *kn)
|
||||
pos->flags |= KERNFS_ACTIVATED;
|
||||
}
|
||||
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
}
|
||||
|
||||
static void __kernfs_remove(struct kernfs_node *kn)
|
||||
{
|
||||
struct kernfs_node *pos;
|
||||
|
||||
lockdep_assert_held_write(&kernfs_rwsem);
|
||||
lockdep_assert_held_write(&kernfs_root(kn)->kernfs_rwsem);
|
||||
|
||||
/*
|
||||
* Short-circuit if non-root @kn has already finished removal.
|
||||
@@ -1390,9 +1400,11 @@ static void __kernfs_remove(struct kernfs_node *kn)
|
||||
*/
|
||||
void kernfs_remove(struct kernfs_node *kn)
|
||||
{
|
||||
down_write(&kernfs_rwsem);
|
||||
struct kernfs_root *root = kernfs_root(kn);
|
||||
|
||||
down_write(&root->kernfs_rwsem);
|
||||
__kernfs_remove(kn);
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1478,8 +1490,9 @@ void kernfs_unbreak_active_protection(struct kernfs_node *kn)
|
||||
bool kernfs_remove_self(struct kernfs_node *kn)
|
||||
{
|
||||
bool ret;
|
||||
struct kernfs_root *root = kernfs_root(kn);
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
kernfs_break_active_protection(kn);
|
||||
|
||||
/*
|
||||
@@ -1507,9 +1520,9 @@ bool kernfs_remove_self(struct kernfs_node *kn)
|
||||
atomic_read(&kn->active) == KN_DEACTIVATED_BIAS)
|
||||
break;
|
||||
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
schedule();
|
||||
down_write(&kernfs_rwsem);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
}
|
||||
finish_wait(waitq, &wait);
|
||||
WARN_ON_ONCE(!RB_EMPTY_NODE(&kn->rb));
|
||||
@@ -1522,7 +1535,7 @@ bool kernfs_remove_self(struct kernfs_node *kn)
|
||||
*/
|
||||
kernfs_unbreak_active_protection(kn);
|
||||
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1539,6 +1552,7 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
|
||||
const void *ns)
|
||||
{
|
||||
struct kernfs_node *kn;
|
||||
struct kernfs_root *root;
|
||||
|
||||
if (!parent) {
|
||||
WARN(1, KERN_WARNING "kernfs: can not remove '%s', no directory\n",
|
||||
@@ -1546,7 +1560,8 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
root = kernfs_root(parent);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
|
||||
kn = kernfs_find_ns(parent, name, ns);
|
||||
if (kn) {
|
||||
@@ -1555,7 +1570,7 @@ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
|
||||
kernfs_put(kn);
|
||||
}
|
||||
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
|
||||
if (kn)
|
||||
return 0;
|
||||
@@ -1574,6 +1589,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
|
||||
const char *new_name, const void *new_ns)
|
||||
{
|
||||
struct kernfs_node *old_parent;
|
||||
struct kernfs_root *root;
|
||||
const char *old_name = NULL;
|
||||
int error;
|
||||
|
||||
@@ -1581,7 +1597,8 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
|
||||
if (!kn->parent)
|
||||
return -EINVAL;
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
root = kernfs_root(kn);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
|
||||
error = -ENOENT;
|
||||
if (!kernfs_active(kn) || !kernfs_active(new_parent) ||
|
||||
@@ -1635,7 +1652,7 @@ int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
|
||||
|
||||
error = 0;
|
||||
out:
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -1706,11 +1723,14 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct kernfs_node *parent = kernfs_dentry_node(dentry);
|
||||
struct kernfs_node *pos = file->private_data;
|
||||
struct kernfs_root *root;
|
||||
const void *ns = NULL;
|
||||
|
||||
if (!dir_emit_dots(file, ctx))
|
||||
return 0;
|
||||
down_read(&kernfs_rwsem);
|
||||
|
||||
root = kernfs_root(parent);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
|
||||
if (kernfs_ns_enabled(parent))
|
||||
ns = kernfs_info(dentry->d_sb)->ns;
|
||||
@@ -1727,12 +1747,12 @@ static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
|
||||
file->private_data = pos;
|
||||
kernfs_get(pos);
|
||||
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
if (!dir_emit(ctx, name, len, ino, type))
|
||||
return 0;
|
||||
down_read(&kernfs_rwsem);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
}
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
file->private_data = NULL;
|
||||
ctx->pos = INT_MAX;
|
||||
return 0;
|
||||
|
||||
@@ -847,6 +847,7 @@ static void kernfs_notify_workfn(struct work_struct *work)
|
||||
{
|
||||
struct kernfs_node *kn;
|
||||
struct kernfs_super_info *info;
|
||||
struct kernfs_root *root;
|
||||
repeat:
|
||||
/* pop one off the notify_list */
|
||||
spin_lock_irq(&kernfs_notify_lock);
|
||||
@@ -859,8 +860,9 @@ repeat:
|
||||
kn->attr.notify_next = NULL;
|
||||
spin_unlock_irq(&kernfs_notify_lock);
|
||||
|
||||
root = kernfs_root(kn);
|
||||
/* kick fsnotify */
|
||||
down_write(&kernfs_rwsem);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
|
||||
list_for_each_entry(info, &kernfs_root(kn)->supers, node) {
|
||||
struct kernfs_node *parent;
|
||||
@@ -898,7 +900,7 @@ repeat:
|
||||
iput(inode);
|
||||
}
|
||||
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
kernfs_put(kn);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
@@ -99,10 +99,11 @@ int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
|
||||
int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr)
|
||||
{
|
||||
int ret;
|
||||
struct kernfs_root *root = kernfs_root(kn);
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
ret = __kernfs_setattr(kn, iattr);
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -111,12 +112,14 @@ int kernfs_iop_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct kernfs_node *kn = inode->i_private;
|
||||
struct kernfs_root *root;
|
||||
int error;
|
||||
|
||||
if (!kn)
|
||||
return -EINVAL;
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
root = kernfs_root(kn);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
error = setattr_prepare(&init_user_ns, dentry, iattr);
|
||||
if (error)
|
||||
goto out;
|
||||
@@ -129,7 +132,7 @@ int kernfs_iop_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
|
||||
setattr_copy(&init_user_ns, inode, iattr);
|
||||
|
||||
out:
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -184,13 +187,14 @@ int kernfs_iop_getattr(struct user_namespace *mnt_userns,
|
||||
{
|
||||
struct inode *inode = d_inode(path->dentry);
|
||||
struct kernfs_node *kn = inode->i_private;
|
||||
struct kernfs_root *root = kernfs_root(kn);
|
||||
|
||||
down_read(&kernfs_rwsem);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
spin_lock(&inode->i_lock);
|
||||
kernfs_refresh_inode(kn, inode);
|
||||
generic_fillattr(&init_user_ns, inode, stat);
|
||||
spin_unlock(&inode->i_lock);
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -274,19 +278,21 @@ int kernfs_iop_permission(struct user_namespace *mnt_userns,
|
||||
struct inode *inode, int mask)
|
||||
{
|
||||
struct kernfs_node *kn;
|
||||
struct kernfs_root *root;
|
||||
int ret;
|
||||
|
||||
if (mask & MAY_NOT_BLOCK)
|
||||
return -ECHILD;
|
||||
|
||||
kn = inode->i_private;
|
||||
root = kernfs_root(kn);
|
||||
|
||||
down_read(&kernfs_rwsem);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
spin_lock(&inode->i_lock);
|
||||
kernfs_refresh_inode(kn, inode);
|
||||
ret = generic_permission(&init_user_ns, inode, mask);
|
||||
spin_unlock(&inode->i_lock);
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -236,6 +236,7 @@ struct dentry *kernfs_node_dentry(struct kernfs_node *kn,
|
||||
static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *kfc)
|
||||
{
|
||||
struct kernfs_super_info *info = kernfs_info(sb);
|
||||
struct kernfs_root *kf_root = kfc->root;
|
||||
struct inode *inode;
|
||||
struct dentry *root;
|
||||
|
||||
@@ -255,9 +256,9 @@ static int kernfs_fill_super(struct super_block *sb, struct kernfs_fs_context *k
|
||||
sb->s_shrink.seeks = 0;
|
||||
|
||||
/* get root inode, initialize and unlock it */
|
||||
down_read(&kernfs_rwsem);
|
||||
down_read(&kf_root->kernfs_rwsem);
|
||||
inode = kernfs_get_inode(sb, info->root->kn);
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&kf_root->kernfs_rwsem);
|
||||
if (!inode) {
|
||||
pr_debug("kernfs: could not get root inode\n");
|
||||
return -ENOMEM;
|
||||
@@ -334,6 +335,7 @@ int kernfs_get_tree(struct fs_context *fc)
|
||||
|
||||
if (!sb->s_root) {
|
||||
struct kernfs_super_info *info = kernfs_info(sb);
|
||||
struct kernfs_root *root = kfc->root;
|
||||
|
||||
kfc->new_sb_created = true;
|
||||
|
||||
@@ -344,9 +346,9 @@ int kernfs_get_tree(struct fs_context *fc)
|
||||
}
|
||||
sb->s_flags |= SB_ACTIVE;
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
list_add(&info->node, &info->root->supers);
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
}
|
||||
|
||||
fc->root = dget(sb->s_root);
|
||||
@@ -371,10 +373,11 @@ void kernfs_free_fs_context(struct fs_context *fc)
|
||||
void kernfs_kill_sb(struct super_block *sb)
|
||||
{
|
||||
struct kernfs_super_info *info = kernfs_info(sb);
|
||||
struct kernfs_root *root = info->root;
|
||||
|
||||
down_write(&kernfs_rwsem);
|
||||
down_write(&root->kernfs_rwsem);
|
||||
list_del(&info->node);
|
||||
up_write(&kernfs_rwsem);
|
||||
up_write(&root->kernfs_rwsem);
|
||||
|
||||
/*
|
||||
* Remove the superblock from fs_supers/s_instances
|
||||
|
||||
@@ -114,11 +114,12 @@ static int kernfs_getlink(struct inode *inode, char *path)
|
||||
struct kernfs_node *kn = inode->i_private;
|
||||
struct kernfs_node *parent = kn->parent;
|
||||
struct kernfs_node *target = kn->symlink.target_kn;
|
||||
struct kernfs_root *root = kernfs_root(parent);
|
||||
int error;
|
||||
|
||||
down_read(&kernfs_rwsem);
|
||||
down_read(&root->kernfs_rwsem);
|
||||
error = kernfs_get_target_path(parent, target, path);
|
||||
up_read(&kernfs_rwsem);
|
||||
up_read(&root->kernfs_rwsem);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/uidgid.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/android_kabi.h>
|
||||
|
||||
struct file;
|
||||
@@ -205,6 +206,7 @@ struct kernfs_root {
|
||||
struct list_head supers;
|
||||
|
||||
wait_queue_head_t deactivate_waitq;
|
||||
struct rw_semaphore kernfs_rwsem;
|
||||
|
||||
ANDROID_KABI_RESERVE(1);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user