2005-04-17 02:20:36 +04:00
/*
* super . c
*
* Copyright ( c ) 1999 Al Smith
*
* Portions derived from work ( c ) 1995 , 1996 Christian Vogelgsang .
*/
# include <linux/init.h>
# include <linux/module.h>
2007-07-17 15:04:28 +04:00
# include <linux/exportfs.h>
2005-04-17 02:20:36 +04:00
# include <linux/slab.h>
# include <linux/buffer_head.h>
# include <linux/vfs.h>
2008-02-24 02:23:51 +03:00
# include "efs.h"
# include <linux/efs_vh.h>
# include <linux/efs_fs_sb.h>
2006-06-23 13:02:58 +04:00
static int efs_statfs ( struct dentry * dentry , struct kstatfs * buf ) ;
2005-04-17 02:20:36 +04:00
static int efs_fill_super ( struct super_block * s , void * d , int silent ) ;
2010-07-25 00:46:55 +04:00
static struct dentry * efs_mount ( struct file_system_type * fs_type ,
int flags , const char * dev_name , void * data )
2005-04-17 02:20:36 +04:00
{
2010-07-25 00:46:55 +04:00
return mount_bdev ( fs_type , flags , dev_name , data , efs_fill_super ) ;
2005-04-17 02:20:36 +04:00
}
2013-12-11 02:05:05 +04:00
static void efs_kill_sb ( struct super_block * s )
{
struct efs_sb_info * sbi = SUPER_INFO ( s ) ;
kill_block_super ( s ) ;
kfree ( sbi ) ;
}
2005-04-17 02:20:36 +04:00
static struct file_system_type efs_fs_type = {
. owner = THIS_MODULE ,
. name = " efs " ,
2010-07-25 00:46:55 +04:00
. mount = efs_mount ,
2013-12-11 02:05:05 +04:00
. kill_sb = efs_kill_sb ,
2005-04-17 02:20:36 +04:00
. fs_flags = FS_REQUIRES_DEV ,
} ;
2013-03-03 07:39:14 +04:00
MODULE_ALIAS_FS ( " efs " ) ;
2005-04-17 02:20:36 +04:00
static struct pt_types sgi_pt_types [ ] = {
{ 0x00 , " SGI vh " } ,
{ 0x01 , " SGI trkrepl " } ,
{ 0x02 , " SGI secrepl " } ,
{ 0x03 , " SGI raw " } ,
{ 0x04 , " SGI bsd " } ,
{ SGI_SYSV , " SGI sysv " } ,
{ 0x06 , " SGI vol " } ,
{ SGI_EFS , " SGI efs " } ,
{ 0x08 , " SGI lv " } ,
{ 0x09 , " SGI rlv " } ,
{ 0x0A , " SGI xfs " } ,
{ 0x0B , " SGI xfslog " } ,
{ 0x0C , " SGI xlv " } ,
{ 0x82 , " Linux swap " } ,
{ 0x83 , " Linux native " } ,
{ 0 , NULL }
} ;
2006-12-07 07:33:20 +03:00
static struct kmem_cache * efs_inode_cachep ;
2005-04-17 02:20:36 +04:00
static struct inode * efs_alloc_inode ( struct super_block * sb )
{
struct efs_inode_info * ei ;
2015-06-26 01:03:32 +03:00
ei = kmem_cache_alloc ( efs_inode_cachep , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! ei )
return NULL ;
return & ei - > vfs_inode ;
}
2011-01-07 09:49:49 +03:00
static void efs_i_callback ( struct rcu_head * head )
2005-04-17 02:20:36 +04:00
{
2011-01-07 09:49:49 +03:00
struct inode * inode = container_of ( head , struct inode , i_rcu ) ;
2005-04-17 02:20:36 +04:00
kmem_cache_free ( efs_inode_cachep , INODE_INFO ( inode ) ) ;
}
2011-01-07 09:49:49 +03:00
static void efs_destroy_inode ( struct inode * inode )
{
call_rcu ( & inode - > i_rcu , efs_i_callback ) ;
}
2008-07-26 06:45:34 +04:00
static void init_once ( void * foo )
2005-04-17 02:20:36 +04:00
{
struct efs_inode_info * ei = ( struct efs_inode_info * ) foo ;
2007-05-17 09:10:57 +04:00
inode_init_once ( & ei - > vfs_inode ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-20 05:11:58 +04:00
2014-04-04 01:49:33 +04:00
static int __init init_inodecache ( void )
2005-04-17 02:20:36 +04:00
{
efs_inode_cachep = kmem_cache_create ( " efs_inode_cache " ,
2016-01-15 02:18:21 +03:00
sizeof ( struct efs_inode_info ) , 0 ,
SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD |
SLAB_ACCOUNT , init_once ) ;
2005-04-17 02:20:36 +04:00
if ( efs_inode_cachep = = NULL )
return - ENOMEM ;
return 0 ;
}
static void destroy_inodecache ( void )
{
2012-09-26 05:33:07 +04:00
/*
* Make sure all delayed rcu free inodes are flushed before we
* destroy cache .
*/
rcu_barrier ( ) ;
2006-09-27 12:49:40 +04:00
kmem_cache_destroy ( efs_inode_cachep ) ;
2005-04-17 02:20:36 +04:00
}
static int efs_remount ( struct super_block * sb , int * flags , char * data )
{
2014-03-13 18:14:33 +04:00
sync_filesystem ( sb ) ;
2005-04-17 02:20:36 +04:00
* flags | = MS_RDONLY ;
return 0 ;
}
2007-02-12 11:55:41 +03:00
static const struct super_operations efs_superblock_operations = {
2005-04-17 02:20:36 +04:00
. alloc_inode = efs_alloc_inode ,
. destroy_inode = efs_destroy_inode ,
. statfs = efs_statfs ,
. remount_fs = efs_remount ,
} ;
2007-10-22 03:42:17 +04:00
static const struct export_operations efs_export_ops = {
2007-10-22 03:42:09 +04:00
. fh_to_dentry = efs_fh_to_dentry ,
. fh_to_parent = efs_fh_to_parent ,
2005-04-17 02:20:36 +04:00
. get_parent = efs_get_parent ,
} ;
static int __init init_efs_fs ( void ) {
int err ;
2014-06-05 03:12:12 +04:00
pr_info ( EFS_VERSION " - http://aeschi.ch.eu.org/efs/ \n " ) ;
2005-04-17 02:20:36 +04:00
err = init_inodecache ( ) ;
if ( err )
goto out1 ;
err = register_filesystem ( & efs_fs_type ) ;
if ( err )
goto out ;
return 0 ;
out :
destroy_inodecache ( ) ;
out1 :
return err ;
}
static void __exit exit_efs_fs ( void ) {
unregister_filesystem ( & efs_fs_type ) ;
destroy_inodecache ( ) ;
}
module_init ( init_efs_fs )
module_exit ( exit_efs_fs )
static efs_block_t efs_validate_vh ( struct volume_header * vh ) {
int i ;
__be32 cs , * ui ;
int csum ;
efs_block_t sblock = 0 ; /* shuts up gcc */
struct pt_types * pt_entry ;
int pt_type , slice = - 1 ;
if ( be32_to_cpu ( vh - > vh_magic ) ! = VHMAGIC ) {
/*
* assume that we ' re dealing with a partition and allow
* read_super ( ) to try and detect a valid superblock
* on the next block .
*/
return 0 ;
}
ui = ( ( __be32 * ) ( vh + 1 ) ) - 1 ;
for ( csum = 0 ; ui > = ( ( __be32 * ) vh ) ; ) {
cs = * ui - - ;
csum + = be32_to_cpu ( cs ) ;
}
if ( csum ) {
2014-06-05 03:12:12 +04:00
pr_warn ( " SGI disklabel: checksum bad, label corrupted \n " ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
# ifdef DEBUG
2014-06-05 03:12:13 +04:00
pr_debug ( " bf: \" %16s \" \n " , vh - > vh_bootfile ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < NVDIR ; i + + ) {
int j ;
char name [ VDNAMESIZE + 1 ] ;
for ( j = 0 ; j < VDNAMESIZE ; j + + ) {
name [ j ] = vh - > vh_vd [ i ] . vd_name [ j ] ;
}
name [ j ] = ( char ) 0 ;
if ( name [ 0 ] ) {
2014-06-05 03:12:13 +04:00
pr_debug ( " vh: %8s block: 0x%08x size: 0x%08x \n " ,
name , ( int ) be32_to_cpu ( vh - > vh_vd [ i ] . vd_lbn ) ,
2005-04-17 02:20:36 +04:00
( int ) be32_to_cpu ( vh - > vh_vd [ i ] . vd_nbytes ) ) ;
}
}
# endif
for ( i = 0 ; i < NPARTAB ; i + + ) {
pt_type = ( int ) be32_to_cpu ( vh - > vh_pt [ i ] . pt_type ) ;
for ( pt_entry = sgi_pt_types ; pt_entry - > pt_name ; pt_entry + + ) {
if ( pt_type = = pt_entry - > pt_type ) break ;
}
# ifdef DEBUG
if ( be32_to_cpu ( vh - > vh_pt [ i ] . pt_nblks ) ) {
2014-06-05 03:12:13 +04:00
pr_debug ( " pt %2d: start: %08d size: %08d type: 0x%02x (%s) \n " ,
i , ( int ) be32_to_cpu ( vh - > vh_pt [ i ] . pt_firstlbn ) ,
( int ) be32_to_cpu ( vh - > vh_pt [ i ] . pt_nblks ) ,
pt_type , ( pt_entry - > pt_name ) ?
pt_entry - > pt_name : " unknown " ) ;
2005-04-17 02:20:36 +04:00
}
# endif
if ( IS_EFS ( pt_type ) ) {
sblock = be32_to_cpu ( vh - > vh_pt [ i ] . pt_firstlbn ) ;
slice = i ;
}
}
if ( slice = = - 1 ) {
2014-06-05 03:12:12 +04:00
pr_notice ( " partition table contained no EFS partitions \n " ) ;
2005-04-17 02:20:36 +04:00
# ifdef DEBUG
} else {
2014-06-05 03:12:12 +04:00
pr_info ( " using slice %d (type %s, offset 0x%x) \n " , slice ,
2005-04-17 02:20:36 +04:00
( pt_entry - > pt_name ) ? pt_entry - > pt_name : " unknown " ,
sblock ) ;
# endif
}
2006-01-15 04:37:08 +03:00
return sblock ;
2005-04-17 02:20:36 +04:00
}
static int efs_validate_super ( struct efs_sb_info * sb , struct efs_super * super ) {
2006-01-15 04:37:08 +03:00
if ( ! IS_EFS_MAGIC ( be32_to_cpu ( super - > fs_magic ) ) )
return - 1 ;
2005-04-17 02:20:36 +04:00
sb - > fs_magic = be32_to_cpu ( super - > fs_magic ) ;
sb - > total_blocks = be32_to_cpu ( super - > fs_size ) ;
sb - > first_block = be32_to_cpu ( super - > fs_firstcg ) ;
sb - > group_size = be32_to_cpu ( super - > fs_cgfsize ) ;
sb - > data_free = be32_to_cpu ( super - > fs_tfree ) ;
sb - > inode_free = be32_to_cpu ( super - > fs_tinode ) ;
sb - > inode_blocks = be16_to_cpu ( super - > fs_cgisize ) ;
sb - > total_groups = be16_to_cpu ( super - > fs_ncg ) ;
return 0 ;
}
static int efs_fill_super ( struct super_block * s , void * d , int silent )
{
struct efs_sb_info * sb ;
struct buffer_head * bh ;
struct inode * root ;
2006-09-27 12:49:37 +04:00
sb = kzalloc ( sizeof ( struct efs_sb_info ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! sb )
return - ENOMEM ;
s - > s_fs_info = sb ;
s - > s_magic = EFS_SUPER_MAGIC ;
if ( ! sb_set_blocksize ( s , EFS_BLOCKSIZE ) ) {
2014-06-05 03:12:12 +04:00
pr_err ( " device does not support %d byte blocks \n " ,
2005-04-17 02:20:36 +04:00
EFS_BLOCKSIZE ) ;
2013-12-11 02:05:05 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
/* read the vh (volume header) block */
bh = sb_bread ( s , 0 ) ;
if ( ! bh ) {
2014-06-05 03:12:12 +04:00
pr_err ( " cannot read volume header \n " ) ;
2016-05-21 03:04:25 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
/*
* if this returns zero then we didn ' t find any partition table .
* this isn ' t ( yet ) an error - just assume for the moment that
* the device is valid and go on to search for a superblock .
*/
sb - > fs_start = efs_validate_vh ( ( struct volume_header * ) bh - > b_data ) ;
brelse ( bh ) ;
if ( sb - > fs_start = = - 1 ) {
2013-12-11 02:05:05 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
bh = sb_bread ( s , sb - > fs_start + EFS_SUPER ) ;
if ( ! bh ) {
2014-06-05 03:12:12 +04:00
pr_err ( " cannot read superblock \n " ) ;
2016-05-21 03:04:25 +03:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
if ( efs_validate_super ( sb , ( struct efs_super * ) bh - > b_data ) ) {
# ifdef DEBUG
2014-06-05 03:12:12 +04:00
pr_warn ( " invalid superblock at block %u \n " ,
sb - > fs_start + EFS_SUPER ) ;
2005-04-17 02:20:36 +04:00
# endif
brelse ( bh ) ;
2013-12-11 02:05:05 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
brelse ( bh ) ;
if ( ! ( s - > s_flags & MS_RDONLY ) ) {
# ifdef DEBUG
2014-06-05 03:12:12 +04:00
pr_info ( " forcing read-only mode \n " ) ;
2005-04-17 02:20:36 +04:00
# endif
s - > s_flags | = MS_RDONLY ;
}
s - > s_op = & efs_superblock_operations ;
s - > s_export_op = & efs_export_ops ;
2008-02-07 11:15:34 +03:00
root = efs_iget ( s , EFS_ROOTINODE ) ;
if ( IS_ERR ( root ) ) {
2014-06-05 03:12:12 +04:00
pr_err ( " get root inode failed \n " ) ;
2013-12-11 02:05:05 +04:00
return PTR_ERR ( root ) ;
2008-02-07 11:15:34 +03:00
}
2012-01-09 07:15:13 +04:00
s - > s_root = d_make_root ( root ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( s - > s_root ) ) {
2014-06-05 03:12:12 +04:00
pr_err ( " get root dentry failed \n " ) ;
2013-12-11 02:05:05 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
2006-06-23 13:02:58 +04:00
static int efs_statfs ( struct dentry * dentry , struct kstatfs * buf ) {
2009-04-03 03:59:34 +04:00
struct super_block * sb = dentry - > d_sb ;
struct efs_sb_info * sbi = SUPER_INFO ( sb ) ;
u64 id = huge_encode_dev ( sb - > s_bdev - > bd_dev ) ;
2005-04-17 02:20:36 +04:00
buf - > f_type = EFS_SUPER_MAGIC ; /* efs magic number */
buf - > f_bsize = EFS_BLOCKSIZE ; /* blocksize */
2009-04-03 03:59:34 +04:00
buf - > f_blocks = sbi - > total_groups * /* total data blocks */
( sbi - > group_size - sbi - > inode_blocks ) ;
buf - > f_bfree = sbi - > data_free ; /* free data blocks */
buf - > f_bavail = sbi - > data_free ; /* free blocks for non-root */
buf - > f_files = sbi - > total_groups * /* total inodes */
sbi - > inode_blocks *
2005-04-17 02:20:36 +04:00
( EFS_BLOCKSIZE / sizeof ( struct efs_dinode ) ) ;
2009-04-03 03:59:34 +04:00
buf - > f_ffree = sbi - > inode_free ; /* free inodes */
buf - > f_fsid . val [ 0 ] = ( u32 ) id ;
buf - > f_fsid . val [ 1 ] = ( u32 ) ( id > > 32 ) ;
2005-04-17 02:20:36 +04:00
buf - > f_namelen = EFS_MAXNAMELEN ; /* max filename length */
return 0 ;
}