2013-11-24 09:54:58 -05:00
/*
* fs / kernfs / mount . c - kernfs mount implementation
*
* Copyright ( c ) 2001 - 3 Patrick Mochel
* Copyright ( c ) 2007 SUSE Linux Products GmbH
* Copyright ( c ) 2007 , 2013 Tejun Heo < tj @ kernel . org >
*
* This file is released under the GPLv2 .
*/
2013-11-28 14:54:44 -05:00
# include <linux/fs.h>
# include <linux/mount.h>
# include <linux/init.h>
# include <linux/magic.h>
# include <linux/slab.h>
# include <linux/pagemap.h>
# include "kernfs-internal.h"
2013-12-11 14:11:57 -05:00
struct kmem_cache * kernfs_node_cache ;
2013-11-28 14:54:44 -05:00
2014-02-03 14:09:10 -05:00
static int kernfs_sop_remount_fs ( struct super_block * sb , int * flags , char * data )
{
struct kernfs_root * root = kernfs_info ( sb ) - > root ;
struct kernfs_syscall_ops * scops = root - > syscall_ops ;
if ( scops & & scops - > remount_fs )
return scops - > remount_fs ( root , flags , data ) ;
return 0 ;
}
static int kernfs_sop_show_options ( struct seq_file * sf , struct dentry * dentry )
{
struct kernfs_root * root = kernfs_root ( dentry - > d_fsdata ) ;
struct kernfs_syscall_ops * scops = root - > syscall_ops ;
if ( scops & & scops - > show_options )
return scops - > show_options ( sf , root ) ;
return 0 ;
}
2014-02-14 16:57:27 +08:00
const struct super_operations kernfs_sops = {
2013-11-28 14:54:44 -05:00
. statfs = simple_statfs ,
. drop_inode = generic_delete_inode ,
2013-12-11 14:11:58 -05:00
. evict_inode = kernfs_evict_inode ,
2014-02-03 14:09:10 -05:00
. remount_fs = kernfs_sop_remount_fs ,
. show_options = kernfs_sop_show_options ,
2013-11-28 14:54:44 -05:00
} ;
2014-02-03 14:09:15 -05:00
/**
* kernfs_root_from_sb - determine kernfs_root associated with a super_block
* @ sb : the super_block in question
*
* Return the kernfs_root associated with @ sb . If @ sb is not a kernfs one ,
* % NULL is returned .
*/
struct kernfs_root * kernfs_root_from_sb ( struct super_block * sb )
{
if ( sb - > s_op = = & kernfs_sops )
return kernfs_info ( sb ) - > root ;
return NULL ;
}
2013-12-11 14:11:58 -05:00
static int kernfs_fill_super ( struct super_block * sb )
2013-11-28 14:54:44 -05:00
{
2013-12-11 14:11:55 -05:00
struct kernfs_super_info * info = kernfs_info ( sb ) ;
2013-11-28 14:54:44 -05:00
struct inode * inode ;
struct dentry * root ;
2014-04-09 11:07:30 -04:00
info - > sb = sb ;
2013-11-28 14:54:44 -05:00
sb - > s_blocksize = PAGE_CACHE_SIZE ;
sb - > s_blocksize_bits = PAGE_CACHE_SHIFT ;
sb - > s_magic = SYSFS_MAGIC ;
2013-12-11 14:11:57 -05:00
sb - > s_op = & kernfs_sops ;
2013-11-28 14:54:44 -05:00
sb - > s_time_gran = 1 ;
/* get root inode, initialize and unlock it */
2013-12-11 14:11:57 -05:00
mutex_lock ( & kernfs_mutex ) ;
2013-12-11 14:11:58 -05:00
inode = kernfs_get_inode ( sb , info - > root - > kn ) ;
2013-12-11 14:11:57 -05:00
mutex_unlock ( & kernfs_mutex ) ;
2013-11-28 14:54:44 -05:00
if ( ! inode ) {
2013-12-11 14:11:58 -05:00
pr_debug ( " kernfs: could not get root inode \n " ) ;
2013-11-28 14:54:44 -05:00
return - ENOMEM ;
}
/* instantiate and link root dentry */
root = d_make_root ( inode ) ;
if ( ! root ) {
pr_debug ( " %s: could not get root dentry! \n " , __func__ ) ;
return - ENOMEM ;
}
2013-12-11 14:11:53 -05:00
kernfs_get ( info - > root - > kn ) ;
root - > d_fsdata = info - > root - > kn ;
2013-11-28 14:54:44 -05:00
sb - > s_root = root ;
2013-12-11 14:11:57 -05:00
sb - > s_d_op = & kernfs_dops ;
2013-11-28 14:54:44 -05:00
return 0 ;
}
2013-12-11 14:11:58 -05:00
static int kernfs_test_super ( struct super_block * sb , void * data )
2013-11-28 14:54:44 -05:00
{
2013-12-11 14:11:55 -05:00
struct kernfs_super_info * sb_info = kernfs_info ( sb ) ;
struct kernfs_super_info * info = data ;
2013-11-28 14:54:44 -05:00
return sb_info - > root = = info - > root & & sb_info - > ns = = info - > ns ;
}
2013-12-11 14:11:58 -05:00
static int kernfs_set_super ( struct super_block * sb , void * data )
2013-11-28 14:54:44 -05:00
{
int error ;
error = set_anon_super ( sb , data ) ;
if ( ! error )
sb - > s_fs_info = data ;
return error ;
}
/**
* kernfs_super_ns - determine the namespace tag of a kernfs super_block
* @ sb : super_block of interest
*
* Return the namespace tag associated with kernfs super_block @ sb .
*/
const void * kernfs_super_ns ( struct super_block * sb )
{
2013-12-11 14:11:55 -05:00
struct kernfs_super_info * info = kernfs_info ( sb ) ;
2013-11-28 14:54:44 -05:00
return info - > ns ;
}
/**
* kernfs_mount_ns - kernfs mount helper
* @ fs_type : file_system_type of the fs being mounted
* @ flags : mount flags specified for the mount
* @ root : kernfs_root of the hierarchy being mounted
2014-02-25 19:28:44 +08:00
* @ new_sb_created : tell the caller if we allocated a new superblock
2013-11-28 14:54:44 -05:00
* @ ns : optional namespace tag of the mount
*
* This is to be called from each kernfs user ' s file_system_type - > mount ( )
* implementation , which should pass through the specified @ fs_type and
* @ flags , and specify the hierarchy and namespace tag to mount via @ root
* and @ ns , respectively .
*
* The return value can be passed to the vfs layer verbatim .
*/
struct dentry * kernfs_mount_ns ( struct file_system_type * fs_type , int flags ,
2014-02-25 19:28:44 +08:00
struct kernfs_root * root , bool * new_sb_created ,
const void * ns )
2013-11-28 14:54:44 -05:00
{
struct super_block * sb ;
2013-12-11 14:11:55 -05:00
struct kernfs_super_info * info ;
2013-11-28 14:54:44 -05:00
int error ;
info = kzalloc ( sizeof ( * info ) , GFP_KERNEL ) ;
if ( ! info )
return ERR_PTR ( - ENOMEM ) ;
info - > root = root ;
info - > ns = ns ;
2013-12-11 14:11:58 -05:00
sb = sget ( fs_type , kernfs_test_super , kernfs_set_super , flags , info ) ;
2013-11-28 14:54:44 -05:00
if ( IS_ERR ( sb ) | | sb - > s_fs_info ! = info )
kfree ( info ) ;
if ( IS_ERR ( sb ) )
return ERR_CAST ( sb ) ;
2014-02-25 19:28:44 +08:00
if ( new_sb_created )
* new_sb_created = ! sb - > s_root ;
2013-11-28 14:54:44 -05:00
if ( ! sb - > s_root ) {
2014-04-09 11:07:30 -04:00
struct kernfs_super_info * info = kernfs_info ( sb ) ;
2013-12-11 14:11:58 -05:00
error = kernfs_fill_super ( sb ) ;
2013-11-28 14:54:44 -05:00
if ( error ) {
deactivate_locked_super ( sb ) ;
return ERR_PTR ( error ) ;
}
sb - > s_flags | = MS_ACTIVE ;
2014-04-09 11:07:30 -04:00
mutex_lock ( & kernfs_mutex ) ;
list_add ( & info - > node , & root - > supers ) ;
mutex_unlock ( & kernfs_mutex ) ;
2013-11-28 14:54:44 -05:00
}
return dget ( sb - > s_root ) ;
}
/**
* kernfs_kill_sb - kill_sb for kernfs
* @ sb : super_block being killed
*
* This can be used directly for file_system_type - > kill_sb ( ) . If a kernfs
* user needs extra cleanup , it can implement its own kill_sb ( ) and call
* this function at the end .
*/
void kernfs_kill_sb ( struct super_block * sb )
{
2013-12-11 14:11:55 -05:00
struct kernfs_super_info * info = kernfs_info ( sb ) ;
2013-12-11 14:11:53 -05:00
struct kernfs_node * root_kn = sb - > s_root - > d_fsdata ;
2013-11-28 14:54:44 -05:00
2014-04-09 11:07:30 -04:00
mutex_lock ( & kernfs_mutex ) ;
list_del ( & info - > node ) ;
mutex_unlock ( & kernfs_mutex ) ;
2013-11-28 14:54:44 -05:00
/*
* Remove the superblock from fs_supers / s_instances
2013-12-11 14:11:55 -05:00
* so we can ' t find it , before freeing kernfs_super_info .
2013-11-28 14:54:44 -05:00
*/
kill_anon_super ( sb ) ;
kfree ( info ) ;
2013-12-11 14:11:53 -05:00
kernfs_put ( root_kn ) ;
2013-11-28 14:54:44 -05:00
}
void __init kernfs_init ( void )
{
2013-12-11 14:11:57 -05:00
kernfs_node_cache = kmem_cache_create ( " kernfs_node_cache " ,
2013-12-11 14:11:53 -05:00
sizeof ( struct kernfs_node ) ,
2013-11-28 14:54:44 -05:00
0 , SLAB_PANIC , NULL ) ;
2013-12-11 14:11:58 -05:00
kernfs_inode_init ( ) ;
2013-11-28 14:54:44 -05:00
}