2006-01-16 19:50:04 +03:00
/*
* Copyright ( C ) Sistina Software , Inc . 1997 - 2003 All rights reserved .
2006-05-18 23:09:15 +04:00
* Copyright ( C ) 2004 - 2006 Red Hat , Inc . All rights reserved .
2006-01-16 19:50:04 +03:00
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2006-09-01 19:05:15 +04:00
* of the GNU General Public License version 2.
2006-01-16 19:50:04 +03:00
*/
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
# include <linux/module.h>
# include <linux/init.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2011-01-19 12:30:01 +03:00
# include <linux/rcupdate.h>
# include <linux/rculist_bl.h>
2011-07-27 03:09:06 +04:00
# include <linux/atomic.h>
2006-01-16 19:50:04 +03:00
# include "gfs2.h"
2006-02-28 01:23:27 +03:00
# include "incore.h"
2008-10-14 19:05:55 +04:00
# include "super.h"
2006-01-16 19:50:04 +03:00
# include "sys.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2006-09-07 22:40:21 +04:00
# include "glock.h"
2009-01-08 01:03:37 +03:00
# include "quota.h"
2010-07-21 00:09:02 +04:00
# include "recovery.h"
2010-09-17 15:30:23 +04:00
# include "dir.h"
2009-01-08 01:03:37 +03:00
2012-01-10 02:18:05 +04:00
struct workqueue_struct * gfs2_control_wq ;
2009-01-08 01:03:37 +03:00
static struct shrinker qd_shrinker = {
. shrink = gfs2_shrink_qd_memory ,
. seeks = DEFAULT_SEEKS ,
} ;
2006-01-16 19:50:04 +03:00
2008-07-26 06:45:34 +04:00
static void gfs2_init_inode_once ( void * foo )
2006-05-19 00:25:27 +04:00
{
struct gfs2_inode * ip = foo ;
2007-05-17 09:10:57 +04:00
inode_init_once ( & ip - > i_inode ) ;
init_rwsem ( & ip - > i_rw_mutex ) ;
2008-11-18 16:38:48 +03:00
INIT_LIST_HEAD ( & ip - > i_trunc_list ) ;
2011-11-21 22:36:17 +04:00
ip - > i_qadata = NULL ;
ip - > i_res = NULL ;
2011-06-15 13:29:37 +04:00
ip - > i_hash_cache = NULL ;
2006-05-19 00:25:27 +04:00
}
2008-07-26 06:45:34 +04:00
static void gfs2_init_glock_once ( void * foo )
2006-08-30 18:36:52 +04:00
{
struct gfs2_glock * gl = foo ;
2007-05-17 09:10:57 +04:00
2011-01-19 12:30:01 +03:00
INIT_HLIST_BL_NODE ( & gl - > gl_list ) ;
2007-05-17 09:10:57 +04:00
spin_lock_init ( & gl - > gl_spin ) ;
INIT_LIST_HEAD ( & gl - > gl_holders ) ;
2008-11-20 16:39:47 +03:00
INIT_LIST_HEAD ( & gl - > gl_lru ) ;
2007-05-17 09:10:57 +04:00
INIT_LIST_HEAD ( & gl - > gl_ail_list ) ;
atomic_set ( & gl - > gl_ail_count , 0 ) ;
2011-04-14 19:50:31 +04:00
atomic_set ( & gl - > gl_revokes , 0 ) ;
2006-08-30 18:36:52 +04:00
}
2009-12-08 15:12:13 +03:00
static void gfs2_init_gl_aspace_once ( void * foo )
{
struct gfs2_glock * gl = foo ;
struct address_space * mapping = ( struct address_space * ) ( gl + 1 ) ;
gfs2_init_glock_once ( gl ) ;
2011-02-23 15:49:47 +03:00
address_space_init_once ( mapping ) ;
2009-12-08 15:12:13 +03:00
}
2006-01-16 19:50:04 +03:00
/**
* init_gfs2_fs - Register GFS2 as a filesystem
*
* Returns : 0 on success , error code on failure
*/
static int __init init_gfs2_fs ( void )
{
int error ;
2010-09-17 15:30:23 +04:00
gfs2_str2qstr ( & gfs2_qdot , " . " ) ;
gfs2_str2qstr ( & gfs2_qdotdot , " .. " ) ;
2006-01-16 19:50:04 +03:00
error = gfs2_sys_init ( ) ;
if ( error )
return error ;
2006-09-07 22:40:21 +04:00
error = gfs2_glock_init ( ) ;
if ( error )
goto fail ;
2006-01-16 19:50:04 +03:00
2006-09-07 22:40:21 +04:00
error = - ENOMEM ;
2006-01-16 19:50:04 +03:00
gfs2_glock_cachep = kmem_cache_create ( " gfs2_glock " ,
sizeof ( struct gfs2_glock ) ,
2006-09-25 17:26:04 +04:00
0 , 0 ,
2007-07-20 05:11:58 +04:00
gfs2_init_glock_once ) ;
2006-01-16 19:50:04 +03:00
if ( ! gfs2_glock_cachep )
goto fail ;
2010-03-12 20:05:31 +03:00
gfs2_glock_aspace_cachep = kmem_cache_create ( " gfs2_glock(aspace) " ,
2009-12-08 15:12:13 +03:00
sizeof ( struct gfs2_glock ) +
sizeof ( struct address_space ) ,
0 , 0 , gfs2_init_gl_aspace_once ) ;
if ( ! gfs2_glock_aspace_cachep )
goto fail ;
2006-01-16 19:50:04 +03:00
gfs2_inode_cachep = kmem_cache_create ( " gfs2_inode " ,
sizeof ( struct gfs2_inode ) ,
2006-10-28 03:03:48 +04:00
0 , SLAB_RECLAIM_ACCOUNT |
SLAB_MEM_SPREAD ,
2007-07-20 05:11:58 +04:00
gfs2_init_inode_once ) ;
2006-01-16 19:50:04 +03:00
if ( ! gfs2_inode_cachep )
goto fail ;
gfs2_bufdata_cachep = kmem_cache_create ( " gfs2_bufdata " ,
sizeof ( struct gfs2_bufdata ) ,
2007-07-20 05:11:58 +04:00
0 , 0 , NULL ) ;
2006-01-16 19:50:04 +03:00
if ( ! gfs2_bufdata_cachep )
goto fail ;
2008-01-29 02:20:26 +03:00
gfs2_rgrpd_cachep = kmem_cache_create ( " gfs2_rgrpd " ,
sizeof ( struct gfs2_rgrpd ) ,
0 , 0 , NULL ) ;
if ( ! gfs2_rgrpd_cachep )
goto fail ;
2008-11-17 17:25:37 +03:00
gfs2_quotad_cachep = kmem_cache_create ( " gfs2_quotad " ,
sizeof ( struct gfs2_quota_data ) ,
0 , 0 , NULL ) ;
if ( ! gfs2_quotad_cachep )
goto fail ;
2009-01-08 01:03:37 +03:00
register_shrinker ( & qd_shrinker ) ;
2006-01-16 19:50:04 +03:00
error = register_filesystem ( & gfs2_fs_type ) ;
if ( error )
goto fail ;
2006-03-03 00:33:41 +03:00
error = register_filesystem ( & gfs2meta_fs_type ) ;
if ( error )
goto fail_unregister ;
2010-07-21 00:09:02 +04:00
error = - ENOMEM ;
gfs_recovery_wq = alloc_workqueue ( " gfs_recovery " ,
2011-02-16 11:25:31 +03:00
WQ_MEM_RECLAIM | WQ_FREEZABLE , 0 ) ;
2010-07-21 00:09:02 +04:00
if ( ! gfs_recovery_wq )
goto fail_wq ;
2009-05-19 13:01:18 +04:00
2012-01-10 02:18:05 +04:00
gfs2_control_wq = alloc_workqueue ( " gfs2_control " ,
WQ_NON_REENTRANT | WQ_UNBOUND | WQ_FREEZABLE , 0 ) ;
if ( ! gfs2_control_wq )
goto fail_control ;
2007-03-16 13:26:37 +03:00
gfs2_register_debugfs ( ) ;
2011-04-01 14:41:20 +04:00
printk ( " GFS2 installed \n " ) ;
2006-01-16 19:50:04 +03:00
return 0 ;
2012-01-10 02:18:05 +04:00
fail_control :
destroy_workqueue ( gfs_recovery_wq ) ;
2010-07-21 00:09:02 +04:00
fail_wq :
2009-05-19 13:01:18 +04:00
unregister_filesystem ( & gfs2meta_fs_type ) ;
2006-03-03 00:33:41 +03:00
fail_unregister :
unregister_filesystem ( & gfs2_fs_type ) ;
fail :
2009-01-08 01:03:37 +03:00
unregister_shrinker ( & qd_shrinker ) ;
2007-08-01 16:57:10 +04:00
gfs2_glock_exit ( ) ;
2008-11-17 17:25:37 +03:00
if ( gfs2_quotad_cachep )
kmem_cache_destroy ( gfs2_quotad_cachep ) ;
2008-01-29 02:20:26 +03:00
if ( gfs2_rgrpd_cachep )
kmem_cache_destroy ( gfs2_rgrpd_cachep ) ;
2006-01-16 19:50:04 +03:00
if ( gfs2_bufdata_cachep )
kmem_cache_destroy ( gfs2_bufdata_cachep ) ;
if ( gfs2_inode_cachep )
kmem_cache_destroy ( gfs2_inode_cachep ) ;
2009-12-08 15:12:13 +03:00
if ( gfs2_glock_aspace_cachep )
kmem_cache_destroy ( gfs2_glock_aspace_cachep ) ;
2006-01-16 19:50:04 +03:00
if ( gfs2_glock_cachep )
kmem_cache_destroy ( gfs2_glock_cachep ) ;
gfs2_sys_uninit ( ) ;
return error ;
}
/**
* exit_gfs2_fs - Unregister the file system
*
*/
static void __exit exit_gfs2_fs ( void )
{
2009-01-08 01:03:37 +03:00
unregister_shrinker ( & qd_shrinker ) ;
2007-08-01 16:57:10 +04:00
gfs2_glock_exit ( ) ;
2007-03-16 13:26:37 +03:00
gfs2_unregister_debugfs ( ) ;
2006-01-16 19:50:04 +03:00
unregister_filesystem ( & gfs2_fs_type ) ;
2006-03-03 00:33:41 +03:00
unregister_filesystem ( & gfs2meta_fs_type ) ;
2010-07-21 00:09:02 +04:00
destroy_workqueue ( gfs_recovery_wq ) ;
2012-01-10 02:18:05 +04:00
destroy_workqueue ( gfs2_control_wq ) ;
2006-01-16 19:50:04 +03:00
2011-01-19 12:30:01 +03:00
rcu_barrier ( ) ;
2008-11-17 17:25:37 +03:00
kmem_cache_destroy ( gfs2_quotad_cachep ) ;
2008-01-29 02:20:26 +03:00
kmem_cache_destroy ( gfs2_rgrpd_cachep ) ;
2006-01-16 19:50:04 +03:00
kmem_cache_destroy ( gfs2_bufdata_cachep ) ;
kmem_cache_destroy ( gfs2_inode_cachep ) ;
2009-12-08 15:12:13 +03:00
kmem_cache_destroy ( gfs2_glock_aspace_cachep ) ;
2006-01-16 19:50:04 +03:00
kmem_cache_destroy ( gfs2_glock_cachep ) ;
gfs2_sys_uninit ( ) ;
}
MODULE_DESCRIPTION ( " Global File System " ) ;
MODULE_AUTHOR ( " Red Hat, Inc. " ) ;
MODULE_LICENSE ( " GPL " ) ;
module_init ( init_gfs2_fs ) ;
module_exit ( exit_gfs2_fs ) ;