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/sched.h>
# include <linux/slab.h>
# include <linux/spinlock.h>
# include <linux/completion.h>
# include <linux/buffer_head.h>
2006-03-28 23:14:04 +04:00
# include <linux/crc32.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2006-07-27 21:53:53 +04:00
# include <linux/bio.h>
2006-09-19 09:56:29 +04:00
# include <linux/lm_interface.h>
2006-01-16 19:50:04 +03:00
# include "gfs2.h"
2006-02-28 01:23:27 +03:00
# include "incore.h"
2006-01-16 19:50:04 +03:00
# include "bmap.h"
# include "dir.h"
# include "glock.h"
# include "glops.h"
# include "inode.h"
# include "log.h"
# include "meta_io.h"
# include "quota.h"
# include "recovery.h"
# include "rgrp.h"
# include "super.h"
# include "trans.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2006-01-16 19:50:04 +03:00
2006-09-04 20:49:07 +04:00
static const u32 gfs2_old_fs_formats [ ] = {
2006-09-04 19:41:31 +04:00
0
} ;
2006-09-04 20:49:07 +04:00
static const u32 gfs2_old_multihost_formats [ ] = {
2006-09-04 19:41:31 +04:00
0
} ;
2006-01-16 19:50:04 +03:00
/**
* gfs2_tune_init - Fill a gfs2_tune structure with default values
* @ gt : tune
*
*/
void gfs2_tune_init ( struct gfs2_tune * gt )
{
spin_lock_init ( & gt - > gt_spin ) ;
gt - > gt_ilimit = 100 ;
gt - > gt_ilimit_tries = 3 ;
gt - > gt_ilimit_min = 1 ;
gt - > gt_demote_secs = 300 ;
gt - > gt_incore_log_blocks = 1024 ;
gt - > gt_log_flush_secs = 60 ;
gt - > gt_jindex_refresh_secs = 60 ;
gt - > gt_scand_secs = 15 ;
gt - > gt_recoverd_secs = 60 ;
gt - > gt_logd_secs = 1 ;
gt - > gt_quotad_secs = 5 ;
gt - > gt_quota_simul_sync = 64 ;
gt - > gt_quota_warn_period = 10 ;
gt - > gt_quota_scale_num = 1 ;
gt - > gt_quota_scale_den = 1 ;
gt - > gt_quota_cache_secs = 300 ;
gt - > gt_quota_quantum = 60 ;
gt - > gt_atime_quantum = 3600 ;
gt - > gt_new_files_jdata = 0 ;
gt - > gt_new_files_directio = 0 ;
gt - > gt_max_readahead = 1 < < 18 ;
gt - > gt_lockdump_size = 131072 ;
gt - > gt_stall_secs = 600 ;
gt - > gt_complain_secs = 10 ;
gt - > gt_reclaim_limit = 5000 ;
gt - > gt_statfs_quantum = 30 ;
gt - > gt_statfs_slow = 0 ;
}
/**
* gfs2_check_sb - Check superblock
* @ sdp : the filesystem
* @ sb : The superblock
* @ silent : Don ' t print a message if the check fails
*
* Checks the version code of the FS is one that we understand how to
* read and that the sizes of the various on - disk structures have not
* changed .
*/
2006-10-14 04:45:02 +04:00
int gfs2_check_sb ( struct gfs2_sbd * sdp , struct gfs2_sb_host * sb , int silent )
2006-01-16 19:50:04 +03:00
{
unsigned int x ;
if ( sb - > sb_header . mh_magic ! = GFS2_MAGIC | |
sb - > sb_header . mh_type ! = GFS2_METATYPE_SB ) {
if ( ! silent )
2006-02-27 18:57:14 +03:00
printk ( KERN_WARNING " GFS2: not a GFS2 filesystem \n " ) ;
2006-01-16 19:50:04 +03:00
return - EINVAL ;
}
/* If format numbers match exactly, we're done. */
if ( sb - > sb_fs_format = = GFS2_FORMAT_FS & &
sb - > sb_multihost_format = = GFS2_FORMAT_MULTI )
return 0 ;
if ( sb - > sb_fs_format ! = GFS2_FORMAT_FS ) {
for ( x = 0 ; gfs2_old_fs_formats [ x ] ; x + + )
if ( gfs2_old_fs_formats [ x ] = = sb - > sb_fs_format )
break ;
if ( ! gfs2_old_fs_formats [ x ] ) {
2006-02-27 20:00:42 +03:00
printk ( KERN_WARNING
" GFS2: code version (%u, %u) is incompatible "
2006-01-16 19:50:04 +03:00
" with ondisk format (%u, %u) \n " ,
GFS2_FORMAT_FS , GFS2_FORMAT_MULTI ,
sb - > sb_fs_format , sb - > sb_multihost_format ) ;
2006-02-27 20:00:42 +03:00
printk ( KERN_WARNING
" GFS2: I don't know how to upgrade this FS \n " ) ;
2006-01-16 19:50:04 +03:00
return - EINVAL ;
}
}
if ( sb - > sb_multihost_format ! = GFS2_FORMAT_MULTI ) {
for ( x = 0 ; gfs2_old_multihost_formats [ x ] ; x + + )
2006-02-27 20:00:42 +03:00
if ( gfs2_old_multihost_formats [ x ] = =
sb - > sb_multihost_format )
2006-01-16 19:50:04 +03:00
break ;
if ( ! gfs2_old_multihost_formats [ x ] ) {
2006-02-27 20:00:42 +03:00
printk ( KERN_WARNING
" GFS2: code version (%u, %u) is incompatible "
2006-01-16 19:50:04 +03:00
" with ondisk format (%u, %u) \n " ,
GFS2_FORMAT_FS , GFS2_FORMAT_MULTI ,
sb - > sb_fs_format , sb - > sb_multihost_format ) ;
2006-02-27 20:00:42 +03:00
printk ( KERN_WARNING
" GFS2: I don't know how to upgrade this FS \n " ) ;
2006-01-16 19:50:04 +03:00
return - EINVAL ;
}
}
if ( ! sdp - > sd_args . ar_upgrade ) {
2006-02-27 20:00:42 +03:00
printk ( KERN_WARNING
" GFS2: code version (%u, %u) is incompatible "
2006-01-16 19:50:04 +03:00
" with ondisk format (%u, %u) \n " ,
GFS2_FORMAT_FS , GFS2_FORMAT_MULTI ,
sb - > sb_fs_format , sb - > sb_multihost_format ) ;
2006-02-27 20:00:42 +03:00
printk ( KERN_INFO
" GFS2: Use the \" upgrade \" mount option to upgrade "
2006-01-16 19:50:04 +03:00
" the FS \n " ) ;
2006-02-27 18:57:14 +03:00
printk ( KERN_INFO " GFS2: See the manual for more details \n " ) ;
2006-01-16 19:50:04 +03:00
return - EINVAL ;
}
return 0 ;
}
2006-07-27 21:53:53 +04:00
static int end_bio_io_page ( struct bio * bio , unsigned int bytes_done , int error )
{
struct page * page = bio - > bi_private ;
if ( bio - > bi_size )
return 1 ;
if ( ! error )
SetPageUptodate ( page ) ;
2006-07-28 00:37:48 +04:00
else
printk ( KERN_WARNING " gfs2: error %d reading superblock \n " , error ) ;
2006-07-27 21:53:53 +04:00
unlock_page ( page ) ;
return 0 ;
}
2006-11-30 18:02:19 +03:00
/**
* gfs2_read_super - Read the gfs2 super block from disk
* @ sb : The VFS super block
* @ sector : The location of the super block
*
* This uses the bio functions to read the super block from disk
* because we want to be 100 % sure that we never read cached data .
* A super block is read twice only during each GFS2 mount and is
* never written to by the filesystem . The first time its read no
* locks are held , and the only details which are looked at are those
* relating to the locking protocol . Once locking is up and working ,
* the sb is read again under the lock to establish the location of
* the master directory ( contains pointers to journals etc ) and the
* root directory .
*
* Returns : A page containing the sb or NULL
*/
2006-10-02 19:49:41 +04:00
struct page * gfs2_read_super ( struct super_block * sb , sector_t sector )
2006-07-27 21:53:53 +04:00
{
struct page * page ;
struct bio * bio ;
page = alloc_page ( GFP_KERNEL ) ;
if ( unlikely ( ! page ) )
return NULL ;
ClearPageUptodate ( page ) ;
ClearPageDirty ( page ) ;
lock_page ( page ) ;
bio = bio_alloc ( GFP_KERNEL , 1 ) ;
if ( unlikely ( ! bio ) ) {
__free_page ( page ) ;
return NULL ;
}
2006-11-30 12:34:55 +03:00
bio - > bi_sector = sector * ( sb - > s_blocksize > > 9 ) ;
2006-07-27 21:53:53 +04:00
bio - > bi_bdev = sb - > s_bdev ;
bio_add_page ( bio , page , PAGE_SIZE , 0 ) ;
bio - > bi_end_io = end_bio_io_page ;
bio - > bi_private = page ;
2006-10-02 19:49:41 +04:00
submit_bio ( READ_SYNC | ( 1 < < BIO_RW_META ) , bio ) ;
2006-07-27 21:53:53 +04:00
wait_on_page_locked ( page ) ;
bio_put ( bio ) ;
if ( ! PageUptodate ( page ) ) {
__free_page ( page ) ;
return NULL ;
}
return page ;
}
2006-01-16 19:50:04 +03:00
/**
* gfs2_read_sb - Read super block
* @ sdp : The GFS2 superblock
* @ gl : the glock for the superblock ( assumed to be held )
* @ silent : Don ' t print message if mount fails
*
*/
int gfs2_read_sb ( struct gfs2_sbd * sdp , struct gfs2_glock * gl , int silent )
{
2006-09-04 20:49:07 +04:00
u32 hash_blocks , ind_blocks , leaf_blocks ;
u32 tmp_blocks ;
2006-01-16 19:50:04 +03:00
unsigned int x ;
int error ;
2006-07-27 21:53:53 +04:00
struct page * page ;
char * sb ;
2006-01-16 19:50:04 +03:00
2006-07-27 21:53:53 +04:00
page = gfs2_read_super ( sdp - > sd_vfs , GFS2_SB_ADDR > > sdp - > sd_fsb2bb_shift ) ;
if ( ! page ) {
2006-01-16 19:50:04 +03:00
if ( ! silent )
fs_err ( sdp , " can't read superblock \n " ) ;
2006-07-27 21:53:53 +04:00
return - EIO ;
2006-01-16 19:50:04 +03:00
}
2006-07-27 21:53:53 +04:00
sb = kmap ( page ) ;
gfs2_sb_in ( & sdp - > sd_sb , sb ) ;
kunmap ( page ) ;
__free_page ( page ) ;
2006-01-16 19:50:04 +03:00
error = gfs2_check_sb ( sdp , & sdp - > sd_sb , silent ) ;
if ( error )
return error ;
sdp - > sd_fsb2bb_shift = sdp - > sd_sb . sb_bsize_shift -
GFS2_BASIC_BLOCK_SHIFT ;
sdp - > sd_fsb2bb = 1 < < sdp - > sd_fsb2bb_shift ;
sdp - > sd_diptrs = ( sdp - > sd_sb . sb_bsize -
2006-09-04 20:49:07 +04:00
sizeof ( struct gfs2_dinode ) ) / sizeof ( u64 ) ;
2006-01-16 19:50:04 +03:00
sdp - > sd_inptrs = ( sdp - > sd_sb . sb_bsize -
2006-09-04 20:49:07 +04:00
sizeof ( struct gfs2_meta_header ) ) / sizeof ( u64 ) ;
2006-01-16 19:50:04 +03:00
sdp - > sd_jbsize = sdp - > sd_sb . sb_bsize - sizeof ( struct gfs2_meta_header ) ;
sdp - > sd_hash_bsize = sdp - > sd_sb . sb_bsize / 2 ;
sdp - > sd_hash_bsize_shift = sdp - > sd_sb . sb_bsize_shift - 1 ;
2006-09-04 20:49:07 +04:00
sdp - > sd_hash_ptrs = sdp - > sd_hash_bsize / sizeof ( u64 ) ;
2006-01-16 19:50:04 +03:00
sdp - > sd_qc_per_block = ( sdp - > sd_sb . sb_bsize -
sizeof ( struct gfs2_meta_header ) ) /
2006-07-27 21:53:53 +04:00
sizeof ( struct gfs2_quota_change ) ;
2006-01-16 19:50:04 +03:00
/* Compute maximum reservation required to add a entry to a directory */
2006-09-04 20:49:07 +04:00
hash_blocks = DIV_ROUND_UP ( sizeof ( u64 ) * ( 1 < < GFS2_DIR_MAX_DEPTH ) ,
2006-01-16 19:50:04 +03:00
sdp - > sd_jbsize ) ;
ind_blocks = 0 ;
for ( tmp_blocks = hash_blocks ; tmp_blocks > sdp - > sd_diptrs ; ) {
2006-02-28 01:23:27 +03:00
tmp_blocks = DIV_ROUND_UP ( tmp_blocks , sdp - > sd_inptrs ) ;
2006-01-16 19:50:04 +03:00
ind_blocks + = tmp_blocks ;
}
leaf_blocks = 2 + GFS2_DIR_MAX_DEPTH ;
sdp - > sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks ;
sdp - > sd_heightsize [ 0 ] = sdp - > sd_sb . sb_bsize -
sizeof ( struct gfs2_dinode ) ;
sdp - > sd_heightsize [ 1 ] = sdp - > sd_sb . sb_bsize * sdp - > sd_diptrs ;
for ( x = 2 ; ; x + + ) {
2006-09-04 20:49:07 +04:00
u64 space , d ;
u32 m ;
2006-01-16 19:50:04 +03:00
space = sdp - > sd_heightsize [ x - 1 ] * sdp - > sd_inptrs ;
d = space ;
m = do_div ( d , sdp - > sd_inptrs ) ;
if ( d ! = sdp - > sd_heightsize [ x - 1 ] | | m )
break ;
sdp - > sd_heightsize [ x ] = space ;
}
sdp - > sd_max_height = x ;
gfs2_assert ( sdp , sdp - > sd_max_height < = GFS2_MAX_META_HEIGHT ) ;
sdp - > sd_jheightsize [ 0 ] = sdp - > sd_sb . sb_bsize -
sizeof ( struct gfs2_dinode ) ;
sdp - > sd_jheightsize [ 1 ] = sdp - > sd_jbsize * sdp - > sd_diptrs ;
for ( x = 2 ; ; x + + ) {
2006-09-04 20:49:07 +04:00
u64 space , d ;
u32 m ;
2006-01-16 19:50:04 +03:00
space = sdp - > sd_jheightsize [ x - 1 ] * sdp - > sd_inptrs ;
d = space ;
m = do_div ( d , sdp - > sd_inptrs ) ;
if ( d ! = sdp - > sd_jheightsize [ x - 1 ] | | m )
break ;
sdp - > sd_jheightsize [ x ] = space ;
}
sdp - > sd_max_jheight = x ;
gfs2_assert ( sdp , sdp - > sd_max_jheight < = GFS2_MAX_META_HEIGHT ) ;
return 0 ;
}
/**
* gfs2_jindex_hold - Grab a lock on the jindex
* @ sdp : The GFS2 superblock
* @ ji_gh : the holder for the jindex glock
*
* This is very similar to the gfs2_rindex_hold ( ) function , except that
* in general we hold the jindex lock for longer periods of time and
* we grab it far less frequently ( in general ) then the rgrp lock .
*
* Returns : errno
*/
int gfs2_jindex_hold ( struct gfs2_sbd * sdp , struct gfs2_holder * ji_gh )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * dip = GFS2_I ( sdp - > sd_jindex ) ;
2006-01-16 19:50:04 +03:00
struct qstr name ;
char buf [ 20 ] ;
struct gfs2_jdesc * jd ;
int error ;
name . name = buf ;
2006-02-21 15:51:39 +03:00
mutex_lock ( & sdp - > sd_jindex_mutex ) ;
2006-01-16 19:50:04 +03:00
for ( ; ; ) {
2007-01-22 20:10:39 +03:00
error = gfs2_glock_nq_init ( dip - > i_gl , LM_ST_SHARED , 0 , ji_gh ) ;
2006-01-16 19:50:04 +03:00
if ( error )
break ;
name . len = sprintf ( buf , " journal%u " , sdp - > sd_journals ) ;
2006-03-20 20:30:04 +03:00
name . hash = gfs2_disk_hash ( name . name , name . len ) ;
2006-01-16 19:50:04 +03:00
2006-06-14 23:32:57 +04:00
error = gfs2_dir_search ( sdp - > sd_jindex , & name , NULL , NULL ) ;
2006-01-16 19:50:04 +03:00
if ( error = = - ENOENT ) {
error = 0 ;
break ;
}
gfs2_glock_dq_uninit ( ji_gh ) ;
if ( error )
break ;
error = - ENOMEM ;
jd = kzalloc ( sizeof ( struct gfs2_jdesc ) , GFP_KERNEL ) ;
if ( ! jd )
break ;
2006-03-20 20:30:04 +03:00
jd - > jd_inode = gfs2_lookupi ( sdp - > sd_jindex , & name , 1 , NULL ) ;
if ( ! jd - > jd_inode | | IS_ERR ( jd - > jd_inode ) ) {
if ( ! jd - > jd_inode )
error = - ENOENT ;
else
error = PTR_ERR ( jd - > jd_inode ) ;
2006-01-16 19:50:04 +03:00
kfree ( jd ) ;
break ;
}
spin_lock ( & sdp - > sd_jindex_spin ) ;
jd - > jd_jid = sdp - > sd_journals + + ;
list_add_tail ( & jd - > jd_list , & sdp - > sd_jindex_list ) ;
spin_unlock ( & sdp - > sd_jindex_spin ) ;
}
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_jindex_mutex ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
/**
* gfs2_jindex_free - Clear all the journal index information
* @ sdp : The GFS2 superblock
*
*/
void gfs2_jindex_free ( struct gfs2_sbd * sdp )
{
struct list_head list ;
struct gfs2_jdesc * jd ;
spin_lock ( & sdp - > sd_jindex_spin ) ;
list_add ( & list , & sdp - > sd_jindex_list ) ;
list_del_init ( & sdp - > sd_jindex_list ) ;
sdp - > sd_journals = 0 ;
spin_unlock ( & sdp - > sd_jindex_spin ) ;
while ( ! list_empty ( & list ) ) {
jd = list_entry ( list . next , struct gfs2_jdesc , jd_list ) ;
list_del ( & jd - > jd_list ) ;
2006-02-13 15:27:43 +03:00
iput ( jd - > jd_inode ) ;
2006-01-16 19:50:04 +03:00
kfree ( jd ) ;
}
}
static struct gfs2_jdesc * jdesc_find_i ( struct list_head * head , unsigned int jid )
{
struct gfs2_jdesc * jd ;
int found = 0 ;
list_for_each_entry ( jd , head , jd_list ) {
if ( jd - > jd_jid = = jid ) {
found = 1 ;
break ;
}
}
if ( ! found )
jd = NULL ;
return jd ;
}
struct gfs2_jdesc * gfs2_jdesc_find ( struct gfs2_sbd * sdp , unsigned int jid )
{
struct gfs2_jdesc * jd ;
spin_lock ( & sdp - > sd_jindex_spin ) ;
jd = jdesc_find_i ( & sdp - > sd_jindex_list , jid ) ;
spin_unlock ( & sdp - > sd_jindex_spin ) ;
return jd ;
}
void gfs2_jdesc_make_dirty ( struct gfs2_sbd * sdp , unsigned int jid )
{
struct gfs2_jdesc * jd ;
spin_lock ( & sdp - > sd_jindex_spin ) ;
jd = jdesc_find_i ( & sdp - > sd_jindex_list , jid ) ;
if ( jd )
jd - > jd_dirty = 1 ;
spin_unlock ( & sdp - > sd_jindex_spin ) ;
}
struct gfs2_jdesc * gfs2_jdesc_find_dirty ( struct gfs2_sbd * sdp )
{
struct gfs2_jdesc * jd ;
int found = 0 ;
spin_lock ( & sdp - > sd_jindex_spin ) ;
list_for_each_entry ( jd , & sdp - > sd_jindex_list , jd_list ) {
if ( jd - > jd_dirty ) {
jd - > jd_dirty = 0 ;
found = 1 ;
break ;
}
}
spin_unlock ( & sdp - > sd_jindex_spin ) ;
if ( ! found )
jd = NULL ;
return jd ;
}
int gfs2_jdesc_check ( struct gfs2_jdesc * jd )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( jd - > jd_inode ) ;
struct gfs2_sbd * sdp = GFS2_SB ( jd - > jd_inode ) ;
2006-01-16 19:50:04 +03:00
int ar ;
int error ;
2006-06-14 23:32:57 +04:00
if ( ip - > i_di . di_size < ( 8 < < 20 ) | | ip - > i_di . di_size > ( 1 < < 30 ) | |
2006-01-16 19:50:04 +03:00
( ip - > i_di . di_size & ( sdp - > sd_sb . sb_bsize - 1 ) ) ) {
gfs2_consist_inode ( ip ) ;
return - EIO ;
}
jd - > jd_blocks = ip - > i_di . di_size > > sdp - > sd_sb . sb_bsize_shift ;
2006-06-14 23:32:57 +04:00
error = gfs2_write_alloc_required ( ip , 0 , ip - > i_di . di_size , & ar ) ;
2006-01-16 19:50:04 +03:00
if ( ! error & & ar ) {
gfs2_consist_inode ( ip ) ;
error = - EIO ;
}
return error ;
}
/**
* gfs2_make_fs_rw - Turn a Read - Only FS into a Read - Write one
* @ sdp : the filesystem
*
* Returns : errno
*/
int gfs2_make_fs_rw ( struct gfs2_sbd * sdp )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( sdp - > sd_jdesc - > jd_inode ) ;
2006-02-28 01:23:27 +03:00
struct gfs2_glock * j_gl = ip - > i_gl ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder t_gh ;
2006-10-14 05:47:13 +04:00
struct gfs2_log_header_host head ;
2006-01-16 19:50:04 +03:00
int error ;
2007-01-22 20:10:39 +03:00
error = gfs2_glock_nq_init ( sdp - > sd_trans_gl , LM_ST_SHARED , 0 , & t_gh ) ;
2006-01-16 19:50:04 +03:00
if ( error )
return error ;
2006-02-28 01:23:27 +03:00
gfs2_meta_cache_flush ( ip ) ;
2006-11-20 18:37:45 +03:00
j_gl - > gl_ops - > go_inval ( j_gl , DIO_METADATA ) ;
2006-01-16 19:50:04 +03:00
error = gfs2_find_jhead ( sdp - > sd_jdesc , & head ) ;
if ( error )
goto fail ;
if ( ! ( head . lh_flags & GFS2_LOG_HEAD_UNMOUNT ) ) {
gfs2_consist ( sdp ) ;
error = - EIO ;
goto fail ;
}
/* Initialize some head of the log stuff */
sdp - > sd_log_sequence = head . lh_sequence + 1 ;
gfs2_log_pointers_init ( sdp , head . lh_blkno ) ;
error = gfs2_quota_init ( sdp ) ;
if ( error )
2006-09-04 20:04:26 +04:00
goto fail ;
2006-01-16 19:50:04 +03:00
set_bit ( SDF_JOURNAL_LIVE , & sdp - > sd_flags ) ;
gfs2_glock_dq_uninit ( & t_gh ) ;
return 0 ;
2006-09-04 20:04:26 +04:00
fail :
2006-01-16 19:50:04 +03:00
t_gh . gh_flags | = GL_NOCACHE ;
gfs2_glock_dq_uninit ( & t_gh ) ;
return error ;
}
/**
* gfs2_make_fs_ro - Turn a Read - Write FS into a Read - Only one
* @ sdp : the filesystem
*
* Returns : errno
*/
int gfs2_make_fs_ro ( struct gfs2_sbd * sdp )
{
struct gfs2_holder t_gh ;
int error ;
gfs2_quota_sync ( sdp ) ;
gfs2_statfs_sync ( sdp ) ;
2007-01-22 20:10:39 +03:00
error = gfs2_glock_nq_init ( sdp - > sd_trans_gl , LM_ST_SHARED , GL_NOCACHE ,
& t_gh ) ;
2006-01-16 19:50:04 +03:00
if ( error & & ! test_bit ( SDF_SHUTDOWN , & sdp - > sd_flags ) )
return error ;
gfs2_meta_syncfs ( sdp ) ;
gfs2_log_shutdown ( sdp ) ;
clear_bit ( SDF_JOURNAL_LIVE , & sdp - > sd_flags ) ;
if ( t_gh . gh_gl )
gfs2_glock_dq_uninit ( & t_gh ) ;
gfs2_quota_cleanup ( sdp ) ;
return error ;
}
int gfs2_statfs_init ( struct gfs2_sbd * sdp )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * m_ip = GFS2_I ( sdp - > sd_statfs_inode ) ;
2006-10-14 07:43:19 +04:00
struct gfs2_statfs_change_host * m_sc = & sdp - > sd_statfs_master ;
2006-06-14 23:32:57 +04:00
struct gfs2_inode * l_ip = GFS2_I ( sdp - > sd_sc_inode ) ;
2006-10-14 07:43:19 +04:00
struct gfs2_statfs_change_host * l_sc = & sdp - > sd_statfs_local ;
2006-01-16 19:50:04 +03:00
struct buffer_head * m_bh , * l_bh ;
struct gfs2_holder gh ;
int error ;
error = gfs2_glock_nq_init ( m_ip - > i_gl , LM_ST_EXCLUSIVE , GL_NOCACHE ,
& gh ) ;
if ( error )
return error ;
error = gfs2_meta_inode_buffer ( m_ip , & m_bh ) ;
if ( error )
goto out ;
if ( sdp - > sd_args . ar_spectator ) {
spin_lock ( & sdp - > sd_statfs_spin ) ;
gfs2_statfs_change_in ( m_sc , m_bh - > b_data +
sizeof ( struct gfs2_dinode ) ) ;
spin_unlock ( & sdp - > sd_statfs_spin ) ;
} else {
error = gfs2_meta_inode_buffer ( l_ip , & l_bh ) ;
if ( error )
goto out_m_bh ;
spin_lock ( & sdp - > sd_statfs_spin ) ;
gfs2_statfs_change_in ( m_sc , m_bh - > b_data +
sizeof ( struct gfs2_dinode ) ) ;
gfs2_statfs_change_in ( l_sc , l_bh - > b_data +
sizeof ( struct gfs2_dinode ) ) ;
spin_unlock ( & sdp - > sd_statfs_spin ) ;
brelse ( l_bh ) ;
}
2006-09-04 20:04:26 +04:00
out_m_bh :
2006-01-16 19:50:04 +03:00
brelse ( m_bh ) ;
2006-09-04 20:04:26 +04:00
out :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & gh ) ;
return 0 ;
}
2006-09-04 20:49:07 +04:00
void gfs2_statfs_change ( struct gfs2_sbd * sdp , s64 total , s64 free ,
s64 dinodes )
2006-01-16 19:50:04 +03:00
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * l_ip = GFS2_I ( sdp - > sd_sc_inode ) ;
2006-10-14 07:43:19 +04:00
struct gfs2_statfs_change_host * l_sc = & sdp - > sd_statfs_local ;
2006-01-16 19:50:04 +03:00
struct buffer_head * l_bh ;
int error ;
error = gfs2_meta_inode_buffer ( l_ip , & l_bh ) ;
if ( error )
return ;
2006-02-21 15:51:39 +03:00
mutex_lock ( & sdp - > sd_statfs_mutex ) ;
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( l_ip - > i_gl , l_bh , 1 ) ;
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_statfs_mutex ) ;
2006-01-16 19:50:04 +03:00
spin_lock ( & sdp - > sd_statfs_spin ) ;
l_sc - > sc_total + = total ;
l_sc - > sc_free + = free ;
l_sc - > sc_dinodes + = dinodes ;
2006-09-25 17:26:04 +04:00
gfs2_statfs_change_out ( l_sc , l_bh - > b_data + sizeof ( struct gfs2_dinode ) ) ;
2006-01-16 19:50:04 +03:00
spin_unlock ( & sdp - > sd_statfs_spin ) ;
brelse ( l_bh ) ;
}
int gfs2_statfs_sync ( struct gfs2_sbd * sdp )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * m_ip = GFS2_I ( sdp - > sd_statfs_inode ) ;
struct gfs2_inode * l_ip = GFS2_I ( sdp - > sd_sc_inode ) ;
2006-10-14 07:43:19 +04:00
struct gfs2_statfs_change_host * m_sc = & sdp - > sd_statfs_master ;
struct gfs2_statfs_change_host * l_sc = & sdp - > sd_statfs_local ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder gh ;
struct buffer_head * m_bh , * l_bh ;
int error ;
error = gfs2_glock_nq_init ( m_ip - > i_gl , LM_ST_EXCLUSIVE , GL_NOCACHE ,
& gh ) ;
if ( error )
return error ;
error = gfs2_meta_inode_buffer ( m_ip , & m_bh ) ;
if ( error )
goto out ;
spin_lock ( & sdp - > sd_statfs_spin ) ;
gfs2_statfs_change_in ( m_sc , m_bh - > b_data +
2006-09-25 17:26:04 +04:00
sizeof ( struct gfs2_dinode ) ) ;
2006-01-16 19:50:04 +03:00
if ( ! l_sc - > sc_total & & ! l_sc - > sc_free & & ! l_sc - > sc_dinodes ) {
spin_unlock ( & sdp - > sd_statfs_spin ) ;
goto out_bh ;
}
spin_unlock ( & sdp - > sd_statfs_spin ) ;
error = gfs2_meta_inode_buffer ( l_ip , & l_bh ) ;
if ( error )
goto out_bh ;
error = gfs2_trans_begin ( sdp , 2 * RES_DINODE , 0 ) ;
if ( error )
goto out_bh2 ;
2006-02-21 15:51:39 +03:00
mutex_lock ( & sdp - > sd_statfs_mutex ) ;
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( l_ip - > i_gl , l_bh , 1 ) ;
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_statfs_mutex ) ;
2006-01-16 19:50:04 +03:00
spin_lock ( & sdp - > sd_statfs_spin ) ;
m_sc - > sc_total + = l_sc - > sc_total ;
m_sc - > sc_free + = l_sc - > sc_free ;
m_sc - > sc_dinodes + = l_sc - > sc_dinodes ;
memset ( l_sc , 0 , sizeof ( struct gfs2_statfs_change ) ) ;
memset ( l_bh - > b_data + sizeof ( struct gfs2_dinode ) ,
0 , sizeof ( struct gfs2_statfs_change ) ) ;
spin_unlock ( & sdp - > sd_statfs_spin ) ;
2006-01-18 14:19:28 +03:00
gfs2_trans_add_bh ( m_ip - > i_gl , m_bh , 1 ) ;
2006-01-16 19:50:04 +03:00
gfs2_statfs_change_out ( m_sc , m_bh - > b_data + sizeof ( struct gfs2_dinode ) ) ;
gfs2_trans_end ( sdp ) ;
2006-09-04 20:04:26 +04:00
out_bh2 :
2006-01-16 19:50:04 +03:00
brelse ( l_bh ) ;
2006-09-04 20:04:26 +04:00
out_bh :
2006-01-16 19:50:04 +03:00
brelse ( m_bh ) ;
2006-09-04 20:04:26 +04:00
out :
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( & gh ) ;
return error ;
}
/**
* gfs2_statfs_i - Do a statfs
* @ sdp : the filesystem
* @ sg : the sg structure
*
* Returns : errno
*/
2006-10-14 07:43:19 +04:00
int gfs2_statfs_i ( struct gfs2_sbd * sdp , struct gfs2_statfs_change_host * sc )
2006-01-16 19:50:04 +03:00
{
2006-10-14 07:43:19 +04:00
struct gfs2_statfs_change_host * m_sc = & sdp - > sd_statfs_master ;
struct gfs2_statfs_change_host * l_sc = & sdp - > sd_statfs_local ;
2006-01-16 19:50:04 +03:00
spin_lock ( & sdp - > sd_statfs_spin ) ;
* sc = * m_sc ;
sc - > sc_total + = l_sc - > sc_total ;
sc - > sc_free + = l_sc - > sc_free ;
sc - > sc_dinodes + = l_sc - > sc_dinodes ;
spin_unlock ( & sdp - > sd_statfs_spin ) ;
if ( sc - > sc_free < 0 )
sc - > sc_free = 0 ;
if ( sc - > sc_free > sc - > sc_total )
sc - > sc_free = sc - > sc_total ;
if ( sc - > sc_dinodes < 0 )
sc - > sc_dinodes = 0 ;
return 0 ;
}
/**
* statfs_fill - fill in the sg for a given RG
* @ rgd : the RG
* @ sc : the sc structure
*
* Returns : 0 on success , - ESTALE if the LVB is invalid
*/
static int statfs_slow_fill ( struct gfs2_rgrpd * rgd ,
2006-10-14 07:43:19 +04:00
struct gfs2_statfs_change_host * sc )
2006-01-16 19:50:04 +03:00
{
gfs2_rgrp_verify ( rgd ) ;
sc - > sc_total + = rgd - > rd_ri . ri_data ;
sc - > sc_free + = rgd - > rd_rg . rg_free ;
sc - > sc_dinodes + = rgd - > rd_rg . rg_dinodes ;
return 0 ;
}
/**
* gfs2_statfs_slow - Stat a filesystem using asynchronous locking
* @ sdp : the filesystem
* @ sc : the sc info that will be returned
*
* Any error ( other than a signal ) will cause this routine to fall back
* to the synchronous version .
*
* FIXME : This really shouldn ' t busy wait like this .
*
* Returns : errno
*/
2006-10-14 07:43:19 +04:00
int gfs2_statfs_slow ( struct gfs2_sbd * sdp , struct gfs2_statfs_change_host * sc )
2006-01-16 19:50:04 +03:00
{
struct gfs2_holder ri_gh ;
struct gfs2_rgrpd * rgd_next ;
struct gfs2_holder * gha , * gh ;
unsigned int slots = 64 ;
unsigned int x ;
int done ;
int error = 0 , err ;
2006-10-14 07:43:19 +04:00
memset ( sc , 0 , sizeof ( struct gfs2_statfs_change_host ) ) ;
2006-01-16 19:50:04 +03:00
gha = kcalloc ( slots , sizeof ( struct gfs2_holder ) , GFP_KERNEL ) ;
if ( ! gha )
return - ENOMEM ;
error = gfs2_rindex_hold ( sdp , & ri_gh ) ;
if ( error )
goto out ;
rgd_next = gfs2_rgrpd_get_first ( sdp ) ;
for ( ; ; ) {
done = 1 ;
for ( x = 0 ; x < slots ; x + + ) {
gh = gha + x ;
if ( gh - > gh_gl & & gfs2_glock_poll ( gh ) ) {
err = gfs2_glock_wait ( gh ) ;
if ( err ) {
gfs2_holder_uninit ( gh ) ;
error = err ;
} else {
if ( ! error )
2006-02-28 01:23:27 +03:00
error = statfs_slow_fill (
gh - > gh_gl - > gl_object , sc ) ;
2006-01-16 19:50:04 +03:00
gfs2_glock_dq_uninit ( gh ) ;
}
}
if ( gh - > gh_gl )
done = 0 ;
else if ( rgd_next & & ! error ) {
error = gfs2_glock_nq_init ( rgd_next - > rd_gl ,
LM_ST_SHARED ,
GL_ASYNC ,
gh ) ;
rgd_next = gfs2_rgrpd_get_next ( rgd_next ) ;
done = 0 ;
}
if ( signal_pending ( current ) )
error = - ERESTARTSYS ;
}
if ( done )
break ;
yield ( ) ;
}
gfs2_glock_dq_uninit ( & ri_gh ) ;
2006-09-04 20:04:26 +04:00
out :
2006-01-16 19:50:04 +03:00
kfree ( gha ) ;
return error ;
}
struct lfcc {
struct list_head list ;
struct gfs2_holder gh ;
} ;
/**
* gfs2_lock_fs_check_clean - Stop all writes to the FS and check that all
* journals are clean
* @ sdp : the file system
* @ state : the state to put the transaction lock into
* @ t_gh : the hold on the transaction lock
*
* Returns : errno
*/
2006-04-28 18:59:12 +04:00
static int gfs2_lock_fs_check_clean ( struct gfs2_sbd * sdp ,
struct gfs2_holder * t_gh )
2006-01-16 19:50:04 +03:00
{
2006-02-28 01:23:27 +03:00
struct gfs2_inode * ip ;
2006-01-16 19:50:04 +03:00
struct gfs2_holder ji_gh ;
struct gfs2_jdesc * jd ;
struct lfcc * lfcc ;
LIST_HEAD ( list ) ;
2006-10-14 05:47:13 +04:00
struct gfs2_log_header_host lh ;
2006-01-16 19:50:04 +03:00
int error ;
error = gfs2_jindex_hold ( sdp , & ji_gh ) ;
if ( error )
return error ;
list_for_each_entry ( jd , & sdp - > sd_jindex_list , jd_list ) {
lfcc = kmalloc ( sizeof ( struct lfcc ) , GFP_KERNEL ) ;
if ( ! lfcc ) {
error = - ENOMEM ;
goto out ;
}
2006-06-14 23:32:57 +04:00
ip = GFS2_I ( jd - > jd_inode ) ;
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_SHARED , 0 , & lfcc - > gh ) ;
2006-01-16 19:50:04 +03:00
if ( error ) {
kfree ( lfcc ) ;
goto out ;
}
list_add ( & lfcc - > list , & list ) ;
}
error = gfs2_glock_nq_init ( sdp - > sd_trans_gl , LM_ST_DEFERRED ,
2006-04-26 22:58:26 +04:00
LM_FLAG_PRIORITY | GL_NOCACHE ,
2006-01-16 19:50:04 +03:00
t_gh ) ;
list_for_each_entry ( jd , & sdp - > sd_jindex_list , jd_list ) {
error = gfs2_jdesc_check ( jd ) ;
if ( error )
break ;
error = gfs2_find_jhead ( jd , & lh ) ;
if ( error )
break ;
if ( ! ( lh . lh_flags & GFS2_LOG_HEAD_UNMOUNT ) ) {
error = - EBUSY ;
break ;
}
}
if ( error )
gfs2_glock_dq_uninit ( t_gh ) ;
2006-09-04 20:04:26 +04:00
out :
2006-01-16 19:50:04 +03:00
while ( ! list_empty ( & list ) ) {
lfcc = list_entry ( list . next , struct lfcc , list ) ;
list_del ( & lfcc - > list ) ;
gfs2_glock_dq_uninit ( & lfcc - > gh ) ;
kfree ( lfcc ) ;
}
gfs2_glock_dq_uninit ( & ji_gh ) ;
return error ;
}
/**
* gfs2_freeze_fs - freezes the file system
* @ sdp : the file system
*
* This function flushes data and meta data for all machines by
* aquiring the transaction log exclusively . All journals are
* ensured to be in a clean state as well .
*
* Returns : errno
*/
int gfs2_freeze_fs ( struct gfs2_sbd * sdp )
{
int error = 0 ;
2006-02-21 15:51:39 +03:00
mutex_lock ( & sdp - > sd_freeze_lock ) ;
2006-01-16 19:50:04 +03:00
if ( ! sdp - > sd_freeze_count + + ) {
error = gfs2_lock_fs_check_clean ( sdp , & sdp - > sd_freeze_gh ) ;
if ( error )
sdp - > sd_freeze_count - - ;
}
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_freeze_lock ) ;
2006-01-16 19:50:04 +03:00
return error ;
}
/**
* gfs2_unfreeze_fs - unfreezes the file system
* @ sdp : the file system
*
* This function allows the file system to proceed by unlocking
* the exclusively held transaction lock . Other GFS2 nodes are
* now free to acquire the lock shared and go on with their lives .
*
*/
void gfs2_unfreeze_fs ( struct gfs2_sbd * sdp )
{
2006-02-21 15:51:39 +03:00
mutex_lock ( & sdp - > sd_freeze_lock ) ;
2006-01-16 19:50:04 +03:00
if ( sdp - > sd_freeze_count & & ! - - sdp - > sd_freeze_count )
gfs2_glock_dq_uninit ( & sdp - > sd_freeze_gh ) ;
2006-02-21 15:51:39 +03:00
mutex_unlock ( & sdp - > sd_freeze_lock ) ;
2006-01-16 19:50:04 +03:00
}