2007-02-14 11:34:12 +03:00
/*
* / proc / sys support
*/
# include <linux/sysctl.h>
# include <linux/proc_fs.h>
# include <linux/security.h>
# include "internal.h"
static struct dentry_operations proc_sys_dentry_operations ;
static const struct file_operations proc_sys_file_operations ;
2008-02-08 15:21:19 +03:00
static const struct inode_operations proc_sys_inode_operations ;
2008-07-15 16:54:06 +04:00
static const struct file_operations proc_sys_dir_file_operations ;
static const struct inode_operations proc_sys_dir_operations ;
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
static struct inode * proc_sys_make_inode ( struct super_block * sb ,
struct ctl_table_header * head , struct ctl_table * table )
2007-02-14 11:34:12 +03:00
{
struct inode * inode ;
2008-07-15 16:54:06 +04:00
struct proc_inode * ei ;
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
inode = new_inode ( sb ) ;
2007-02-14 11:34:12 +03:00
if ( ! inode )
goto out ;
2008-07-15 16:54:06 +04:00
sysctl_head_get ( head ) ;
2007-02-14 11:34:12 +03:00
ei = PROC_I ( inode ) ;
2008-07-15 16:54:06 +04:00
ei - > sysctl = head ;
ei - > sysctl_entry = table ;
2007-02-14 11:34:12 +03:00
inode - > i_mtime = inode - > i_atime = inode - > i_ctime = CURRENT_TIME ;
2007-02-14 11:34:16 +03:00
inode - > i_flags | = S_PRIVATE ; /* tell selinux to ignore this inode */
2008-07-15 16:54:06 +04:00
inode - > i_mode = table - > mode ;
if ( ! table - > child ) {
inode - > i_mode | = S_IFREG ;
inode - > i_op = & proc_sys_inode_operations ;
inode - > i_fop = & proc_sys_file_operations ;
} else {
inode - > i_mode | = S_IFDIR ;
inode - > i_nlink = 0 ;
inode - > i_op = & proc_sys_dir_operations ;
inode - > i_fop = & proc_sys_dir_file_operations ;
}
2007-02-14 11:34:12 +03:00
out :
return inode ;
}
2008-07-15 16:54:06 +04:00
static struct ctl_table * find_in_table ( struct ctl_table * p , struct qstr * name )
2007-02-14 11:34:12 +03:00
{
int len ;
2008-07-15 16:54:06 +04:00
for ( ; p - > ctl_name | | p - > procname ; p + + ) {
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
if ( ! p - > procname )
2007-02-14 11:34:12 +03:00
continue ;
2008-07-15 16:54:06 +04:00
len = strlen ( p - > procname ) ;
2007-02-14 11:34:12 +03:00
if ( len ! = name - > len )
continue ;
2008-07-15 16:54:06 +04:00
if ( memcmp ( p - > procname , name - > name , len ) ! = 0 )
2007-02-14 11:34:12 +03:00
continue ;
/* I have a match */
2008-07-15 16:54:06 +04:00
return p ;
2007-02-14 11:34:12 +03:00
}
return NULL ;
}
2008-10-03 00:33:54 +04:00
static struct ctl_table_header * grab_header ( struct inode * inode )
2007-02-14 11:34:12 +03:00
{
2008-07-15 16:54:06 +04:00
if ( PROC_I ( inode ) - > sysctl )
return sysctl_head_grab ( PROC_I ( inode ) - > sysctl ) ;
else
return sysctl_head_next ( NULL ) ;
}
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
static struct dentry * proc_sys_lookup ( struct inode * dir , struct dentry * dentry ,
struct nameidata * nd )
{
struct ctl_table_header * head = grab_header ( dir ) ;
struct ctl_table * table = PROC_I ( dir ) - > sysctl_entry ;
struct ctl_table_header * h = NULL ;
struct qstr * name = & dentry - > d_name ;
struct ctl_table * p ;
struct inode * inode ;
struct dentry * err = ERR_PTR ( - ENOENT ) ;
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
if ( IS_ERR ( head ) )
return ERR_CAST ( head ) ;
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
if ( table & & ! table - > child ) {
WARN_ON ( 1 ) ;
goto out ;
2007-02-14 11:34:12 +03:00
}
2008-07-15 16:54:06 +04:00
table = table ? table - > child : head - > ctl_table ;
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
p = find_in_table ( table , name ) ;
if ( ! p ) {
for ( h = sysctl_head_next ( NULL ) ; h ; h = sysctl_head_next ( h ) ) {
if ( h - > attached_to ! = table )
continue ;
p = find_in_table ( h - > attached_by , name ) ;
if ( p )
break ;
}
2007-02-14 11:34:12 +03:00
}
2008-07-15 16:54:06 +04:00
if ( ! p )
2007-02-14 11:34:12 +03:00
goto out ;
err = ERR_PTR ( - ENOMEM ) ;
2008-07-15 16:54:06 +04:00
inode = proc_sys_make_inode ( dir - > i_sb , h ? h : head , p ) ;
if ( h )
sysctl_head_finish ( h ) ;
2007-02-14 11:34:12 +03:00
if ( ! inode )
goto out ;
err = NULL ;
dentry - > d_op = & proc_sys_dentry_operations ;
d_add ( dentry , inode ) ;
out :
sysctl_head_finish ( head ) ;
return err ;
}
sysctl: merge equal proc_sys_read and proc_sys_write
Many (most of) sysctls do not have a per-container sense. E.g.
kernel.print_fatal_signals, vm.panic_on_oom, net.core.netdev_budget and so on
and so forth. Besides, tuning then from inside a container is not even
secure. On the other hand, hiding them completely from the container's tasks
sometimes causes user-space to stop working.
When developing net sysctl, the common practice was to duplicate a table and
drop the write bits in table->mode, but this approach was not very elegant,
lead to excessive memory consumption and was not suitable in general.
Here's the alternative solution. To facilitate the per-container sysctls
ctl_table_root-s were introduced. Each root contains a list of
ctl_table_header-s that are visible to different namespaces. The idea of this
set is to add the permissions() callback on the ctl_table_root to allow ctl
root limit permissions to the same ctl_table-s.
The main user of this functionality is the net-namespaces code, but later this
will (should) be used by more and more namespaces, containers and control
groups.
Actually, this idea's core is in a single hunk in the third patch. First two
patches are cleanups for sysctl code, while the third one mostly extends the
arguments set of some sysctl functions.
This patch:
These ->read and ->write callbacks act in a very similar way, so merge these
paths to reduce the number of places to patch later and shrink the .text size
(a bit).
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Acked-by: "David S. Miller" <davem@davemloft.net>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Cc: Denis V. Lunev <den@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-04-29 12:02:40 +04:00
static ssize_t proc_sys_call_handler ( struct file * filp , void __user * buf ,
size_t count , loff_t * ppos , int write )
2007-02-14 11:34:12 +03:00
{
2008-07-15 16:54:06 +04:00
struct inode * inode = filp - > f_path . dentry - > d_inode ;
struct ctl_table_header * head = grab_header ( inode ) ;
struct ctl_table * table = PROC_I ( inode ) - > sysctl_entry ;
2007-10-25 18:27:40 +04:00
ssize_t error ;
size_t res ;
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
if ( IS_ERR ( head ) )
return PTR_ERR ( head ) ;
2007-02-14 11:34:12 +03:00
/*
* At this point we know that the sysctl was not unregistered
* and won ' t be until we finish .
*/
error = - EPERM ;
2008-04-29 12:02:44 +04:00
if ( sysctl_perm ( head - > root , table , write ? MAY_WRITE : MAY_READ ) )
2007-02-14 11:34:12 +03:00
goto out ;
2008-07-15 16:54:06 +04:00
/* if that can happen at all, it should be -EINVAL, not -EISDIR */
error = - EINVAL ;
if ( ! table - > proc_handler )
goto out ;
2007-02-14 11:34:12 +03:00
/* careful: calling conventions are nasty here */
res = count ;
sysctl: merge equal proc_sys_read and proc_sys_write
Many (most of) sysctls do not have a per-container sense. E.g.
kernel.print_fatal_signals, vm.panic_on_oom, net.core.netdev_budget and so on
and so forth. Besides, tuning then from inside a container is not even
secure. On the other hand, hiding them completely from the container's tasks
sometimes causes user-space to stop working.
When developing net sysctl, the common practice was to duplicate a table and
drop the write bits in table->mode, but this approach was not very elegant,
lead to excessive memory consumption and was not suitable in general.
Here's the alternative solution. To facilitate the per-container sysctls
ctl_table_root-s were introduced. Each root contains a list of
ctl_table_header-s that are visible to different namespaces. The idea of this
set is to add the permissions() callback on the ctl_table_root to allow ctl
root limit permissions to the same ctl_table-s.
The main user of this functionality is the net-namespaces code, but later this
will (should) be used by more and more namespaces, containers and control
groups.
Actually, this idea's core is in a single hunk in the third patch. First two
patches are cleanups for sysctl code, while the third one mostly extends the
arguments set of some sysctl functions.
This patch:
These ->read and ->write callbacks act in a very similar way, so merge these
paths to reduce the number of places to patch later and shrink the .text size
(a bit).
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Acked-by: "David S. Miller" <davem@davemloft.net>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Cc: Denis V. Lunev <den@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-04-29 12:02:40 +04:00
error = table - > proc_handler ( table , write , filp , buf , & res , ppos ) ;
2007-02-14 11:34:12 +03:00
if ( ! error )
error = res ;
out :
sysctl_head_finish ( head ) ;
return error ;
}
sysctl: merge equal proc_sys_read and proc_sys_write
Many (most of) sysctls do not have a per-container sense. E.g.
kernel.print_fatal_signals, vm.panic_on_oom, net.core.netdev_budget and so on
and so forth. Besides, tuning then from inside a container is not even
secure. On the other hand, hiding them completely from the container's tasks
sometimes causes user-space to stop working.
When developing net sysctl, the common practice was to duplicate a table and
drop the write bits in table->mode, but this approach was not very elegant,
lead to excessive memory consumption and was not suitable in general.
Here's the alternative solution. To facilitate the per-container sysctls
ctl_table_root-s were introduced. Each root contains a list of
ctl_table_header-s that are visible to different namespaces. The idea of this
set is to add the permissions() callback on the ctl_table_root to allow ctl
root limit permissions to the same ctl_table-s.
The main user of this functionality is the net-namespaces code, but later this
will (should) be used by more and more namespaces, containers and control
groups.
Actually, this idea's core is in a single hunk in the third patch. First two
patches are cleanups for sysctl code, while the third one mostly extends the
arguments set of some sysctl functions.
This patch:
These ->read and ->write callbacks act in a very similar way, so merge these
paths to reduce the number of places to patch later and shrink the .text size
(a bit).
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Acked-by: "David S. Miller" <davem@davemloft.net>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Cc: Denis V. Lunev <den@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-04-29 12:02:40 +04:00
static ssize_t proc_sys_read ( struct file * filp , char __user * buf ,
2007-02-14 11:34:12 +03:00
size_t count , loff_t * ppos )
{
sysctl: merge equal proc_sys_read and proc_sys_write
Many (most of) sysctls do not have a per-container sense. E.g.
kernel.print_fatal_signals, vm.panic_on_oom, net.core.netdev_budget and so on
and so forth. Besides, tuning then from inside a container is not even
secure. On the other hand, hiding them completely from the container's tasks
sometimes causes user-space to stop working.
When developing net sysctl, the common practice was to duplicate a table and
drop the write bits in table->mode, but this approach was not very elegant,
lead to excessive memory consumption and was not suitable in general.
Here's the alternative solution. To facilitate the per-container sysctls
ctl_table_root-s were introduced. Each root contains a list of
ctl_table_header-s that are visible to different namespaces. The idea of this
set is to add the permissions() callback on the ctl_table_root to allow ctl
root limit permissions to the same ctl_table-s.
The main user of this functionality is the net-namespaces code, but later this
will (should) be used by more and more namespaces, containers and control
groups.
Actually, this idea's core is in a single hunk in the third patch. First two
patches are cleanups for sysctl code, while the third one mostly extends the
arguments set of some sysctl functions.
This patch:
These ->read and ->write callbacks act in a very similar way, so merge these
paths to reduce the number of places to patch later and shrink the .text size
(a bit).
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Acked-by: "David S. Miller" <davem@davemloft.net>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Cc: Denis V. Lunev <den@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-04-29 12:02:40 +04:00
return proc_sys_call_handler ( filp , ( void __user * ) buf , count , ppos , 0 ) ;
}
2007-02-14 11:34:12 +03:00
sysctl: merge equal proc_sys_read and proc_sys_write
Many (most of) sysctls do not have a per-container sense. E.g.
kernel.print_fatal_signals, vm.panic_on_oom, net.core.netdev_budget and so on
and so forth. Besides, tuning then from inside a container is not even
secure. On the other hand, hiding them completely from the container's tasks
sometimes causes user-space to stop working.
When developing net sysctl, the common practice was to duplicate a table and
drop the write bits in table->mode, but this approach was not very elegant,
lead to excessive memory consumption and was not suitable in general.
Here's the alternative solution. To facilitate the per-container sysctls
ctl_table_root-s were introduced. Each root contains a list of
ctl_table_header-s that are visible to different namespaces. The idea of this
set is to add the permissions() callback on the ctl_table_root to allow ctl
root limit permissions to the same ctl_table-s.
The main user of this functionality is the net-namespaces code, but later this
will (should) be used by more and more namespaces, containers and control
groups.
Actually, this idea's core is in a single hunk in the third patch. First two
patches are cleanups for sysctl code, while the third one mostly extends the
arguments set of some sysctl functions.
This patch:
These ->read and ->write callbacks act in a very similar way, so merge these
paths to reduce the number of places to patch later and shrink the .text size
(a bit).
Signed-off-by: Pavel Emelyanov <xemul@openvz.org>
Acked-by: "David S. Miller" <davem@davemloft.net>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Cc: Denis V. Lunev <den@openvz.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-04-29 12:02:40 +04:00
static ssize_t proc_sys_write ( struct file * filp , const char __user * buf ,
size_t count , loff_t * ppos )
{
return proc_sys_call_handler ( filp , ( void __user * ) buf , count , ppos , 1 ) ;
2007-02-14 11:34:12 +03:00
}
static int proc_sys_fill_cache ( struct file * filp , void * dirent ,
2008-07-15 16:54:06 +04:00
filldir_t filldir ,
struct ctl_table_header * head ,
struct ctl_table * table )
2007-02-14 11:34:12 +03:00
{
struct dentry * child , * dir = filp - > f_path . dentry ;
struct inode * inode ;
struct qstr qname ;
ino_t ino = 0 ;
unsigned type = DT_UNKNOWN ;
qname . name = table - > procname ;
qname . len = strlen ( table - > procname ) ;
qname . hash = full_name_hash ( qname . name , qname . len ) ;
child = d_lookup ( dir , & qname ) ;
if ( ! child ) {
2008-07-15 16:54:06 +04:00
child = d_alloc ( dir , & qname ) ;
if ( child ) {
inode = proc_sys_make_inode ( dir - > d_sb , head , table ) ;
if ( ! inode ) {
dput ( child ) ;
return - ENOMEM ;
} else {
child - > d_op = & proc_sys_dentry_operations ;
d_add ( child , inode ) ;
2007-02-14 11:34:12 +03:00
}
2008-07-15 16:54:06 +04:00
} else {
return - ENOMEM ;
2007-02-14 11:34:12 +03:00
}
}
inode = child - > d_inode ;
2008-07-15 16:54:06 +04:00
ino = inode - > i_ino ;
type = inode - > i_mode > > 12 ;
2007-02-14 11:34:12 +03:00
dput ( child ) ;
2008-07-15 16:54:06 +04:00
return ! ! filldir ( dirent , qname . name , qname . len , filp - > f_pos , ino , type ) ;
}
static int scan ( struct ctl_table_header * head , ctl_table * table ,
unsigned long * pos , struct file * file ,
void * dirent , filldir_t filldir )
{
for ( ; table - > ctl_name | | table - > procname ; table + + , ( * pos ) + + ) {
int res ;
/* Can't do anything without a proc name */
if ( ! table - > procname )
continue ;
if ( * pos < file - > f_pos )
continue ;
res = proc_sys_fill_cache ( file , dirent , filldir , head , table ) ;
if ( res )
return res ;
file - > f_pos = * pos + 1 ;
}
return 0 ;
2007-02-14 11:34:12 +03:00
}
static int proc_sys_readdir ( struct file * filp , void * dirent , filldir_t filldir )
{
2008-07-15 16:54:06 +04:00
struct dentry * dentry = filp - > f_path . dentry ;
2007-02-14 11:34:12 +03:00
struct inode * inode = dentry - > d_inode ;
2008-07-15 16:54:06 +04:00
struct ctl_table_header * head = grab_header ( inode ) ;
struct ctl_table * table = PROC_I ( inode ) - > sysctl_entry ;
struct ctl_table_header * h = NULL ;
2007-02-14 11:34:12 +03:00
unsigned long pos ;
2008-07-15 16:54:06 +04:00
int ret = - EINVAL ;
if ( IS_ERR ( head ) )
return PTR_ERR ( head ) ;
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
if ( table & & ! table - > child ) {
WARN_ON ( 1 ) ;
2007-02-14 11:34:12 +03:00
goto out ;
2008-07-15 16:54:06 +04:00
}
table = table ? table - > child : head - > ctl_table ;
2007-02-14 11:34:12 +03:00
ret = 0 ;
/* Avoid a switch here: arm builds fail with missing __cmpdi2 */
if ( filp - > f_pos = = 0 ) {
if ( filldir ( dirent , " . " , 1 , filp - > f_pos ,
inode - > i_ino , DT_DIR ) < 0 )
goto out ;
filp - > f_pos + + ;
}
if ( filp - > f_pos = = 1 ) {
if ( filldir ( dirent , " .. " , 2 , filp - > f_pos ,
parent_ino ( dentry ) , DT_DIR ) < 0 )
goto out ;
filp - > f_pos + + ;
}
pos = 2 ;
2008-07-15 16:54:06 +04:00
ret = scan ( head , table , & pos , filp , dirent , filldir ) ;
if ( ret )
goto out ;
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
for ( h = sysctl_head_next ( NULL ) ; h ; h = sysctl_head_next ( h ) ) {
if ( h - > attached_to ! = table )
2007-02-14 11:34:12 +03:00
continue ;
2008-07-15 16:54:06 +04:00
ret = scan ( h , h - > attached_by , & pos , filp , dirent , filldir ) ;
if ( ret ) {
sysctl_head_finish ( h ) ;
break ;
2007-02-14 11:34:12 +03:00
}
}
ret = 1 ;
out :
sysctl_head_finish ( head ) ;
return ret ;
}
2008-07-16 05:03:57 +04:00
static int proc_sys_permission ( struct inode * inode , int mask )
2007-02-14 11:34:12 +03:00
{
/*
* sysctl entries that are not writeable ,
* are _NOT_ writeable , capabilities or not .
*/
2008-07-15 16:54:06 +04:00
struct ctl_table_header * head = grab_header ( inode ) ;
struct ctl_table * table = PROC_I ( inode ) - > sysctl_entry ;
2007-02-14 11:34:12 +03:00
int error ;
2008-07-15 16:54:06 +04:00
if ( IS_ERR ( head ) )
return PTR_ERR ( head ) ;
2007-02-14 11:34:12 +03:00
2008-07-15 16:54:06 +04:00
if ( ! table ) /* global root - r-xr-xr-x */
error = mask & MAY_WRITE ? - EACCES : 0 ;
else /* Use the permissions on the sysctl table entry */
error = sysctl_perm ( head - > root , table , mask ) ;
2007-02-14 11:34:12 +03:00
sysctl_head_finish ( head ) ;
return error ;
}
static int proc_sys_setattr ( struct dentry * dentry , struct iattr * attr )
{
struct inode * inode = dentry - > d_inode ;
int error ;
if ( attr - > ia_valid & ( ATTR_MODE | ATTR_UID | ATTR_GID ) )
return - EPERM ;
error = inode_change_ok ( inode , attr ) ;
2007-05-08 11:29:44 +04:00
if ( ! error )
error = inode_setattr ( inode , attr ) ;
2007-02-14 11:34:12 +03:00
return error ;
}
2008-07-15 16:54:06 +04:00
static int proc_sys_getattr ( struct vfsmount * mnt , struct dentry * dentry , struct kstat * stat )
{
struct inode * inode = dentry - > d_inode ;
struct ctl_table_header * head = grab_header ( inode ) ;
struct ctl_table * table = PROC_I ( inode ) - > sysctl_entry ;
if ( IS_ERR ( head ) )
return PTR_ERR ( head ) ;
generic_fillattr ( inode , stat ) ;
if ( table )
stat - > mode = ( stat - > mode & S_IFMT ) | table - > mode ;
sysctl_head_finish ( head ) ;
return 0 ;
}
2007-02-14 11:34:12 +03:00
static const struct file_operations proc_sys_file_operations = {
. read = proc_sys_read ,
. write = proc_sys_write ,
2008-07-15 16:54:06 +04:00
} ;
static const struct file_operations proc_sys_dir_file_operations = {
2007-02-14 11:34:12 +03:00
. readdir = proc_sys_readdir ,
2008-09-03 23:53:01 +04:00
. llseek = generic_file_llseek ,
2007-02-14 11:34:12 +03:00
} ;
2008-02-08 15:21:19 +03:00
static const struct inode_operations proc_sys_inode_operations = {
2008-07-15 16:54:06 +04:00
. permission = proc_sys_permission ,
. setattr = proc_sys_setattr ,
. getattr = proc_sys_getattr ,
} ;
static const struct inode_operations proc_sys_dir_operations = {
2007-02-14 11:34:12 +03:00
. lookup = proc_sys_lookup ,
. permission = proc_sys_permission ,
. setattr = proc_sys_setattr ,
2008-07-15 16:54:06 +04:00
. getattr = proc_sys_getattr ,
2007-02-14 11:34:12 +03:00
} ;
static int proc_sys_revalidate ( struct dentry * dentry , struct nameidata * nd )
{
2008-07-15 16:54:06 +04:00
return ! PROC_I ( dentry - > d_inode ) - > sysctl - > unregistering ;
}
static int proc_sys_delete ( struct dentry * dentry )
{
return ! ! PROC_I ( dentry - > d_inode ) - > sysctl - > unregistering ;
}
static int proc_sys_compare ( struct dentry * dir , struct qstr * qstr ,
struct qstr * name )
{
struct dentry * dentry = container_of ( qstr , struct dentry , d_name ) ;
if ( qstr - > len ! = name - > len )
return 1 ;
if ( memcmp ( qstr - > name , name - > name , name - > len ) )
return 1 ;
return ! sysctl_is_seen ( PROC_I ( dentry - > d_inode ) - > sysctl ) ;
2007-02-14 11:34:12 +03:00
}
static struct dentry_operations proc_sys_dentry_operations = {
. d_revalidate = proc_sys_revalidate ,
2008-07-15 16:54:06 +04:00
. d_delete = proc_sys_delete ,
. d_compare = proc_sys_compare ,
2007-02-14 11:34:12 +03:00
} ;
int proc_sys_init ( void )
{
2008-10-03 00:23:32 +04:00
struct proc_dir_entry * proc_sys_root ;
2007-02-14 11:34:12 +03:00
proc_sys_root = proc_mkdir ( " sys " , NULL ) ;
2008-07-15 16:54:06 +04:00
proc_sys_root - > proc_iops = & proc_sys_dir_operations ;
proc_sys_root - > proc_fops = & proc_sys_dir_file_operations ;
2007-02-14 11:34:12 +03:00
proc_sys_root - > nlink = 0 ;
return 0 ;
}