unfuck proc_sysctl ->d_compare()
a) struct inode is not going to be freed under ->d_compare(); however, the thing PROC_I(inode)->sysctl points to just might. Fortunately, it's enough to make freeing that sucker delayed, provided that we don't step on its ->unregistering, clear the pointer to it in PROC_I(inode) before dropping the reference and check if it's NULL in ->d_compare(). b) I'm not sure that we *can* walk into NULL inode here (we recheck dentry->seq between verifying that it's still hashed / fetching dentry->d_inode and passing it to ->d_compare() and there's no negative hashed dentries in /proc/sys/*), but if we can walk into that, we really should not have ->d_compare() return 0 on it! Said that, I really suspect that this check can be simply killed. Nick? Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
struct completion;
|
||||
|
||||
@@ -1037,10 +1038,15 @@ struct ctl_table_root {
|
||||
struct ctl_table trees. */
|
||||
struct ctl_table_header
|
||||
{
|
||||
struct ctl_table *ctl_table;
|
||||
struct list_head ctl_entry;
|
||||
int used;
|
||||
int count;
|
||||
union {
|
||||
struct {
|
||||
struct ctl_table *ctl_table;
|
||||
struct list_head ctl_entry;
|
||||
int used;
|
||||
int count;
|
||||
};
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
struct completion *unregistering;
|
||||
struct ctl_table *ctl_table_arg;
|
||||
struct ctl_table_root *root;
|
||||
|
Reference in New Issue
Block a user