2005-04-17 02:20:36 +04:00
/*
2007-09-20 12:31:38 +04:00
* fs / sysfs / inode . c - basic sysfs inode and dentry operations
2005-04-17 02:20:36 +04:00
*
2007-09-20 12:31:38 +04:00
* Copyright ( c ) 2001 - 3 Patrick Mochel
* Copyright ( c ) 2007 SUSE Linux Products GmbH
* Copyright ( c ) 2007 Tejun Heo < teheo @ suse . de >
*
* This file is released under the GPLv2 .
2005-04-17 02:20:36 +04:00
*
* Please see Documentation / filesystems / sysfs . txt for more information .
*/
# undef DEBUG
# include <linux/pagemap.h>
# include <linux/namei.h>
# include <linux/backing-dev.h>
2006-01-11 23:17:46 +03:00
# include <linux/capability.h>
2006-07-11 10:05:25 +04:00
# include <linux/errno.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/sched.h>
2009-09-09 22:25:37 +04:00
# include <linux/xattr.h>
# include <linux/security.h>
2005-04-17 02:20:36 +04:00
# include "sysfs.h"
extern struct super_block * sysfs_sb ;
2006-06-28 15:26:44 +04:00
static const struct address_space_operations sysfs_aops = {
2005-04-17 02:20:36 +04:00
. readpage = simple_readpage ,
2007-10-16 12:25:03 +04:00
. write_begin = simple_write_begin ,
. write_end = simple_write_end ,
2005-04-17 02:20:36 +04:00
} ;
static struct backing_dev_info sysfs_backing_dev_info = {
2009-06-12 16:45:52 +04:00
. name = " sysfs " ,
2005-04-17 02:20:36 +04:00
. ra_pages = 0 , /* No readahead */
2008-04-30 11:54:37 +04:00
. capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK ,
2005-04-17 02:20:36 +04:00
} ;
2007-02-12 11:55:40 +03:00
static const struct inode_operations sysfs_inode_operations = {
2009-11-21 03:08:53 +03:00
. permission = sysfs_permission ,
2005-05-31 09:09:14 +04:00
. setattr = sysfs_setattr ,
2009-11-21 03:08:53 +03:00
. getattr = sysfs_getattr ,
2009-09-09 22:25:37 +04:00
. setxattr = sysfs_setxattr ,
2005-05-31 09:09:14 +04:00
} ;
2007-10-17 10:25:46 +04:00
int __init sysfs_inode_init ( void )
{
return bdi_init ( & sysfs_backing_dev_info ) ;
}
2009-10-14 22:47:32 +04:00
static struct sysfs_inode_attrs * sysfs_init_inode_attrs ( struct sysfs_dirent * sd )
2009-09-09 22:25:37 +04:00
{
struct sysfs_inode_attrs * attrs ;
struct iattr * iattrs ;
attrs = kzalloc ( sizeof ( struct sysfs_inode_attrs ) , GFP_KERNEL ) ;
if ( ! attrs )
return NULL ;
iattrs = & attrs - > ia_iattr ;
/* assign default attributes */
iattrs - > ia_mode = sd - > s_mode ;
iattrs - > ia_uid = 0 ;
iattrs - > ia_gid = 0 ;
iattrs - > ia_atime = iattrs - > ia_mtime = iattrs - > ia_ctime = CURRENT_TIME ;
return attrs ;
}
2009-10-14 22:47:32 +04:00
2009-11-21 03:08:50 +03:00
int sysfs_sd_setattr ( struct sysfs_dirent * sd , struct iattr * iattr )
2005-05-31 09:09:14 +04:00
{
2009-09-09 22:25:37 +04:00
struct sysfs_inode_attrs * sd_attrs ;
struct iattr * iattrs ;
2005-05-31 09:09:14 +04:00
unsigned int ia_valid = iattr - > ia_valid ;
2009-09-09 22:25:37 +04:00
sd_attrs = sd - > s_iattr ;
2005-05-31 09:09:14 +04:00
2009-09-09 22:25:37 +04:00
if ( ! sd_attrs ) {
2005-05-31 09:09:14 +04:00
/* setting attributes for the first time, allocate now */
2009-09-09 22:25:37 +04:00
sd_attrs = sysfs_init_inode_attrs ( sd ) ;
if ( ! sd_attrs )
2005-05-31 09:09:14 +04:00
return - ENOMEM ;
2009-09-09 22:25:37 +04:00
sd - > s_iattr = sd_attrs ;
2010-02-04 10:13:24 +03:00
}
/* attributes were changed at least once in past */
iattrs = & sd_attrs - > ia_iattr ;
if ( ia_valid & ATTR_UID )
iattrs - > ia_uid = iattr - > ia_uid ;
if ( ia_valid & ATTR_GID )
iattrs - > ia_gid = iattr - > ia_gid ;
if ( ia_valid & ATTR_ATIME )
iattrs - > ia_atime = iattr - > ia_atime ;
if ( ia_valid & ATTR_MTIME )
iattrs - > ia_mtime = iattr - > ia_mtime ;
if ( ia_valid & ATTR_CTIME )
iattrs - > ia_ctime = iattr - > ia_ctime ;
if ( ia_valid & ATTR_MODE ) {
umode_t mode = iattr - > ia_mode ;
iattrs - > ia_mode = sd - > s_mode = mode ;
2005-05-31 09:09:14 +04:00
}
2009-11-21 03:08:50 +03:00
return 0 ;
}
int sysfs_setattr ( struct dentry * dentry , struct iattr * iattr )
{
struct inode * inode = dentry - > d_inode ;
struct sysfs_dirent * sd = dentry - > d_fsdata ;
int error ;
if ( ! sd )
return - EINVAL ;
error = inode_change_ok ( inode , iattr ) ;
if ( error )
return error ;
iattr - > ia_valid & = ~ ATTR_SIZE ; /* ignore size changes */
error = inode_setattr ( inode , iattr ) ;
if ( error )
return error ;
mutex_lock ( & sysfs_mutex ) ;
error = sysfs_sd_setattr ( sd , iattr ) ;
mutex_unlock ( & sysfs_mutex ) ;
2009-09-09 22:25:37 +04:00
return error ;
}
2005-05-31 09:09:14 +04:00
2009-11-08 10:26:59 +03:00
static int sysfs_sd_setsecdata ( struct sysfs_dirent * sd , void * * secdata , u32 * secdata_len )
{
struct sysfs_inode_attrs * iattrs ;
void * old_secdata ;
size_t old_secdata_len ;
iattrs = sd - > s_iattr ;
if ( ! iattrs )
iattrs = sysfs_init_inode_attrs ( sd ) ;
if ( ! iattrs )
return - ENOMEM ;
old_secdata = iattrs - > ia_secdata ;
old_secdata_len = iattrs - > ia_secdata_len ;
iattrs - > ia_secdata = * secdata ;
iattrs - > ia_secdata_len = * secdata_len ;
* secdata = old_secdata ;
* secdata_len = old_secdata_len ;
return 0 ;
}
2009-09-09 22:25:37 +04:00
int sysfs_setxattr ( struct dentry * dentry , const char * name , const void * value ,
size_t size , int flags )
{
struct sysfs_dirent * sd = dentry - > d_fsdata ;
void * secdata ;
int error ;
u32 secdata_len = 0 ;
if ( ! sd )
return - EINVAL ;
if ( ! strncmp ( name , XATTR_SECURITY_PREFIX , XATTR_SECURITY_PREFIX_LEN ) ) {
const char * suffix = name + XATTR_SECURITY_PREFIX_LEN ;
error = security_inode_setsecurity ( dentry - > d_inode , suffix ,
value , size , flags ) ;
if ( error )
goto out ;
error = security_inode_getsecctx ( dentry - > d_inode ,
& secdata , & secdata_len ) ;
if ( error )
goto out ;
2005-05-31 09:09:14 +04:00
2009-11-08 10:26:59 +03:00
mutex_lock ( & sysfs_mutex ) ;
error = sysfs_sd_setsecdata ( sd , & secdata , & secdata_len ) ;
mutex_unlock ( & sysfs_mutex ) ;
if ( secdata )
security_release_secctx ( secdata , secdata_len ) ;
2009-09-09 22:25:37 +04:00
} else
return - EINVAL ;
out :
2005-05-31 09:09:14 +04:00
return error ;
}
2005-05-31 09:09:52 +04:00
static inline void set_default_inode_attr ( struct inode * inode , mode_t mode )
{
inode - > i_mode = mode ;
inode - > i_atime = inode - > i_mtime = inode - > i_ctime = CURRENT_TIME ;
}
static inline void set_inode_attr ( struct inode * inode , struct iattr * iattr )
{
inode - > i_uid = iattr - > ia_uid ;
inode - > i_gid = iattr - > ia_gid ;
inode - > i_atime = iattr - > ia_atime ;
inode - > i_mtime = iattr - > ia_mtime ;
inode - > i_ctime = iattr - > ia_ctime ;
}
2007-08-20 16:36:29 +04:00
static int sysfs_count_nlink ( struct sysfs_dirent * sd )
{
struct sysfs_dirent * child ;
int nr = 0 ;
2007-09-20 11:05:12 +04:00
for ( child = sd - > s_dir . children ; child ; child = child - > s_sibling )
2007-08-20 16:36:29 +04:00
if ( sysfs_type ( child ) = = SYSFS_DIR )
nr + + ;
return nr + 2 ;
}
2009-11-21 03:08:53 +03:00
static void sysfs_refresh_inode ( struct sysfs_dirent * sd , struct inode * inode )
{
struct sysfs_inode_attrs * iattrs = sd - > s_iattr ;
inode - > i_mode = sd - > s_mode ;
if ( iattrs ) {
/* sysfs_dirent has non-default attributes
* get them from persistent copy in sysfs_dirent
*/
set_inode_attr ( inode , & iattrs - > ia_iattr ) ;
security_inode_notifysecctx ( inode ,
iattrs - > ia_secdata ,
iattrs - > ia_secdata_len ) ;
}
if ( sysfs_type ( sd ) = = SYSFS_DIR )
inode - > i_nlink = sysfs_count_nlink ( sd ) ;
}
int sysfs_getattr ( struct vfsmount * mnt , struct dentry * dentry , struct kstat * stat )
{
struct sysfs_dirent * sd = dentry - > d_fsdata ;
struct inode * inode = dentry - > d_inode ;
mutex_lock ( & sysfs_mutex ) ;
sysfs_refresh_inode ( sd , inode ) ;
mutex_unlock ( & sysfs_mutex ) ;
generic_fillattr ( inode , stat ) ;
return 0 ;
}
2007-07-18 09:30:28 +04:00
static void sysfs_init_inode ( struct sysfs_dirent * sd , struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2007-08-20 16:36:29 +04:00
struct bin_attribute * bin_attr ;
2009-02-12 00:20:23 +03:00
inode - > i_private = sysfs_get ( sd ) ;
2007-06-13 22:45:17 +04:00
inode - > i_mapping - > a_ops = & sysfs_aops ;
inode - > i_mapping - > backing_dev_info = & sysfs_backing_dev_info ;
inode - > i_op = & sysfs_inode_operations ;
2009-11-21 03:08:53 +03:00
set_default_inode_attr ( inode , sd - > s_mode ) ;
sysfs_refresh_inode ( sd , inode ) ;
2007-08-20 16:36:29 +04:00
/* initialize inode according to type */
switch ( sysfs_type ( sd ) ) {
case SYSFS_DIR :
inode - > i_op = & sysfs_dir_inode_operations ;
inode - > i_fop = & sysfs_dir_operations ;
break ;
case SYSFS_KOBJ_ATTR :
inode - > i_size = PAGE_SIZE ;
inode - > i_fop = & sysfs_file_operations ;
break ;
case SYSFS_KOBJ_BIN_ATTR :
2007-09-20 11:05:11 +04:00
bin_attr = sd - > s_bin_attr . bin_attr ;
2007-08-20 16:36:29 +04:00
inode - > i_size = bin_attr - > size ;
inode - > i_fop = & bin_fops ;
break ;
case SYSFS_KOBJ_LINK :
inode - > i_op = & sysfs_symlink_inode_operations ;
break ;
default :
BUG ( ) ;
}
unlock_new_inode ( inode ) ;
2007-06-13 22:45:17 +04:00
}
/**
2007-06-13 22:45:17 +04:00
* sysfs_get_inode - get inode for sysfs_dirent
2007-06-13 22:45:17 +04:00
* @ sd : sysfs_dirent to allocate inode for
*
2007-06-13 22:45:17 +04:00
* Get inode for @ sd . If such inode doesn ' t exist , a new inode
* is allocated and basics are initialized . New inode is
* returned locked .
2007-06-13 22:45:17 +04:00
*
* LOCKING :
* Kernel thread context ( may sleep ) .
*
* RETURNS :
* Pointer to allocated inode on success , NULL on failure .
*/
2007-06-13 22:45:17 +04:00
struct inode * sysfs_get_inode ( struct sysfs_dirent * sd )
2007-06-13 22:45:17 +04:00
{
struct inode * inode ;
2007-06-13 22:45:17 +04:00
inode = iget_locked ( sysfs_sb , sd - > s_ino ) ;
if ( inode & & ( inode - > i_state & I_NEW ) )
2007-06-13 22:45:17 +04:00
sysfs_init_inode ( sd , inode ) ;
2005-04-17 02:20:36 +04:00
return inode ;
}
2009-02-12 00:20:23 +03:00
/*
* The sysfs_dirent serves as both an inode and a directory entry for sysfs .
* To prevent the sysfs inode numbers from being freed prematurely we take a
* reference to sysfs_dirent from the sysfs inode . A
* super_operations . delete_inode ( ) implementation is needed to drop that
* reference upon inode destruction .
*/
void sysfs_delete_inode ( struct inode * inode )
{
struct sysfs_dirent * sd = inode - > i_private ;
truncate_inode_pages ( & inode - > i_data , 0 ) ;
clear_inode ( inode ) ;
sysfs_put ( sd ) ;
}
2007-06-13 23:27:22 +04:00
int sysfs_hash_and_remove ( struct sysfs_dirent * dir_sd , const char * name )
2005-04-17 02:20:36 +04:00
{
2007-06-13 23:27:24 +04:00
struct sysfs_addrm_cxt acxt ;
2007-08-02 16:38:03 +04:00
struct sysfs_dirent * sd ;
2006-03-17 02:44:26 +03:00
2007-06-13 23:27:22 +04:00
if ( ! dir_sd )
2006-07-11 10:05:25 +04:00
return - ENOENT ;
2005-04-17 02:20:36 +04:00
2007-06-13 23:27:24 +04:00
sysfs_addrm_start ( & acxt , dir_sd ) ;
2007-06-13 23:27:22 +04:00
2007-08-02 16:38:03 +04:00
sd = sysfs_find_dirent ( dir_sd , name ) ;
if ( sd )
sysfs_remove_one ( & acxt , sd ) ;
2007-06-13 23:27:23 +04:00
2007-08-02 16:38:03 +04:00
sysfs_addrm_finish ( & acxt ) ;
if ( sd )
2007-06-13 23:27:24 +04:00
return 0 ;
2007-08-02 16:38:03 +04:00
else
return - ENOENT ;
2005-04-17 02:20:36 +04:00
}
2009-11-21 03:08:53 +03:00
int sysfs_permission ( struct inode * inode , int mask )
{
struct sysfs_dirent * sd = inode - > i_private ;
mutex_lock ( & sysfs_mutex ) ;
sysfs_refresh_inode ( sd , inode ) ;
mutex_unlock ( & sysfs_mutex ) ;
return generic_permission ( inode , mask , NULL ) ;
}