提交 0ed59406 编写于 作者: A Alexey Dobriyan 提交者: Yang Yingliang

proc: change ->nlink under proc_subdir_lock

stable inclusion
from linux-4.19.167
commit 972013f7351fff34c7b76cfec9e21f5f60548d41

--------------------------------

[ Upstream commit e06689bf ]

Currently gluing PDE into global /proc tree is done under lock, but
changing ->nlink is not.  Additionally struct proc_dir_entry::nlink is
not atomic so updates can be lost.

Link: http://lkml.kernel.org/r/20190925202436.GA17388@avx2Signed-off-by: NAlexey Dobriyan <adobriyan@gmail.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: NSasha Levin <sashal@kernel.org>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
Signed-off-by: NCheng Jian <cj.chengjian@huawei.com>
上级 0a75b5f9
...@@ -137,8 +137,12 @@ static int proc_getattr(const struct path *path, struct kstat *stat, ...@@ -137,8 +137,12 @@ static int proc_getattr(const struct path *path, struct kstat *stat,
{ {
struct inode *inode = d_inode(path->dentry); struct inode *inode = d_inode(path->dentry);
struct proc_dir_entry *de = PDE(inode); struct proc_dir_entry *de = PDE(inode);
if (de && de->nlink) if (de) {
set_nlink(inode, de->nlink); nlink_t nlink = READ_ONCE(de->nlink);
if (nlink > 0) {
set_nlink(inode, nlink);
}
}
generic_fillattr(inode, stat); generic_fillattr(inode, stat);
return 0; return 0;
...@@ -361,6 +365,7 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, ...@@ -361,6 +365,7 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir,
write_unlock(&proc_subdir_lock); write_unlock(&proc_subdir_lock);
goto out_free_inum; goto out_free_inum;
} }
dir->nlink++;
write_unlock(&proc_subdir_lock); write_unlock(&proc_subdir_lock);
return dp; return dp;
...@@ -471,10 +476,7 @@ struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, ...@@ -471,10 +476,7 @@ struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode,
ent->data = data; ent->data = data;
ent->proc_fops = &proc_dir_operations; ent->proc_fops = &proc_dir_operations;
ent->proc_iops = &proc_dir_inode_operations; ent->proc_iops = &proc_dir_inode_operations;
parent->nlink++;
ent = proc_register(parent, ent); ent = proc_register(parent, ent);
if (!ent)
parent->nlink--;
} }
return ent; return ent;
} }
...@@ -504,10 +506,7 @@ struct proc_dir_entry *proc_create_mount_point(const char *name) ...@@ -504,10 +506,7 @@ struct proc_dir_entry *proc_create_mount_point(const char *name)
ent->data = NULL; ent->data = NULL;
ent->proc_fops = NULL; ent->proc_fops = NULL;
ent->proc_iops = NULL; ent->proc_iops = NULL;
parent->nlink++;
ent = proc_register(parent, ent); ent = proc_register(parent, ent);
if (!ent)
parent->nlink--;
} }
return ent; return ent;
} }
...@@ -665,8 +664,12 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) ...@@ -665,8 +664,12 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
len = strlen(fn); len = strlen(fn);
de = pde_subdir_find(parent, fn, len); de = pde_subdir_find(parent, fn, len);
if (de) if (de) {
rb_erase(&de->subdir_node, &parent->subdir); rb_erase(&de->subdir_node, &parent->subdir);
if (S_ISDIR(de->mode)) {
parent->nlink--;
}
}
write_unlock(&proc_subdir_lock); write_unlock(&proc_subdir_lock);
if (!de) { if (!de) {
WARN(1, "name '%s'\n", name); WARN(1, "name '%s'\n", name);
...@@ -675,9 +678,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) ...@@ -675,9 +678,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
proc_entry_rundown(de); proc_entry_rundown(de);
if (S_ISDIR(de->mode))
parent->nlink--;
de->nlink = 0;
WARN(pde_subdir_first(de), WARN(pde_subdir_first(de),
"%s: removing non-empty directory '%s/%s', leaking at least '%s'\n", "%s: removing non-empty directory '%s/%s', leaking at least '%s'\n",
__func__, de->parent->name, de->name, pde_subdir_first(de)->name); __func__, de->parent->name, de->name, pde_subdir_first(de)->name);
...@@ -713,13 +713,12 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) ...@@ -713,13 +713,12 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
de = next; de = next;
continue; continue;
} }
write_unlock(&proc_subdir_lock);
proc_entry_rundown(de);
next = de->parent; next = de->parent;
if (S_ISDIR(de->mode)) if (S_ISDIR(de->mode))
next->nlink--; next->nlink--;
de->nlink = 0; write_unlock(&proc_subdir_lock);
proc_entry_rundown(de);
if (de == root) if (de == root)
break; break;
pde_put(de); pde_put(de);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册