>From a4c94461ae18b2d6cc2e8a9cfb042d0b6cc46e86 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 9 Aug 2014 17:25:53 +0200 Subject: [PATCH 1/3] proc: introduce proc_sys_evict_inode() Preparation. Shift the sysctl_head_put() code from proc_evict_inode() into the new trivial helper, make sysctl_head_put() static. --- fs/proc/inode.c | 8 ++------ fs/proc/internal.h | 4 ++-- fs/proc/proc_sysctl.c | 13 ++++++++++++- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 0adbc02..9f6715a 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -31,7 +31,6 @@ static void proc_evict_inode(struct inode *inode) { struct proc_dir_entry *de; - struct ctl_table_header *head; const struct proc_ns_operations *ns_ops; void *ns; @@ -45,11 +44,8 @@ static void proc_evict_inode(struct inode *inode) de = PROC_I(inode)->pde; if (de) pde_put(de); - head = PROC_I(inode)->sysctl; - if (head) { - RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL); - sysctl_head_put(head); - } + + proc_sys_evict_inode(inode); /* Release any associated namespace */ ns_ops = PROC_I(inode)->ns.ns_ops; ns = PROC_I(inode)->ns.ns; diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 78784cd..7ce3262 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -238,10 +238,10 @@ extern int proc_setup_self(struct super_block *); */ #ifdef CONFIG_PROC_SYSCTL extern int proc_sys_init(void); -extern void sysctl_head_put(struct ctl_table_header *); +extern void proc_sys_evict_inode(struct inode *inode); #else static inline void proc_sys_init(void) { } -static inline void sysctl_head_put(struct ctl_table_header *head) { } +static inline void proc_sys_evict_inode(struct inode *inode) { } #endif /* diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 7129046..2fa67e7 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -256,7 +256,7 @@ static void sysctl_head_get(struct ctl_table_header *head) spin_unlock(&sysctl_lock); } -void sysctl_head_put(struct ctl_table_header *head) +static void sysctl_head_put(struct ctl_table_header *head) { spin_lock(&sysctl_lock); if (!--head->count) @@ -264,6 +264,17 @@ void sysctl_head_put(struct ctl_table_header *head) spin_unlock(&sysctl_lock); } +void proc_sys_evict_inode(struct inode *inode) +{ + struct ctl_table_header *head; + + head = PROC_I(inode)->sysctl; + if (head) { + RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL); + sysctl_head_put(head); + } +} + static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) { BUG_ON(!head); -- 1.5.5.1 >From e0b42f4770cd76069e4e70e48e4e7bfa84fab4bf Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sat, 9 Aug 2014 17:37:31 +0200 Subject: [PATCH 2/3] proc: change proc_sys_evict_inode() to check inode->i_op Change proc_sys_evict_inode() to verify that this inode is really a /proc/sys inode before using ->sysctl. --- fs/proc/proc_sysctl.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 2fa67e7..863aaee 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c @@ -268,6 +268,10 @@ void proc_sys_evict_inode(struct inode *inode) { struct ctl_table_header *head; + if (inode->i_op != &proc_sys_inode_operations && + inode->i_op != &proc_sys_dir_operations) + return; + head = PROC_I(inode)->sysctl; if (head) { RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL); -- 1.5.5.1 >From 9c8e98fc45f091d5d2a4bfc6dcd86b67275160a1 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Sun, 10 Aug 2014 17:37:25 +0200 Subject: [PATCH 3/3] proc: place proc_inode->sysctl* and proc_inode->fd into a union ->sysctl* and ->fd members can share the memory, add a union. Note: unfortunately proc_alloc_inode() still has to initialize ->sysctl* members. And the only (afaics) reason is that proc_mkdir("sys") relies on ->sysctl == NULL which means sysctl_table_root in grab_header(). It would be nice to initialize these members after proc_get_inode("sys") somehow and remove the special "NULL means global root" case in proc_sys paths somehow, but I do not see how. --- fs/proc/internal.h | 12 ++++++++---- 1 files changed, 8 insertions(+), 4 deletions(-) diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 7ce3262..8d35ac0 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -60,11 +60,15 @@ union proc_op { struct proc_inode { struct pid *pid; - int fd; - union proc_op op; struct proc_dir_entry *pde; - struct ctl_table_header *sysctl; - struct ctl_table *sysctl_entry; + union proc_op op; + union { + struct { + struct ctl_table_header *sysctl; + struct ctl_table *sysctl_entry; + }; + int fd; + }; struct proc_ns ns; struct inode vfs_inode; }; -- 1.5.5.1