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>
# include <linux/statfs.h>
# include <linux/seq_file.h>
# include <linux/mount.h>
# include <linux/kthread.h>
# include <linux/delay.h>
2006-02-28 01:23:27 +03:00
# include <linux/gfs2_ondisk.h>
2006-06-14 23:32:57 +04:00
# include <linux/crc32.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 "glock.h"
# include "inode.h"
# include "lm.h"
# include "log.h"
# include "mount.h"
# include "ops_super.h"
# include "quota.h"
# include "recovery.h"
# include "rgrp.h"
# include "super.h"
# include "sys.h"
2006-02-28 01:23:27 +03:00
# include "util.h"
2006-06-14 23:32:57 +04:00
# include "trans.h"
# include "dir.h"
# include "eattr.h"
# include "bmap.h"
2006-01-16 19:50:04 +03:00
/**
* gfs2_write_inode - Make sure the inode is stable on the disk
* @ inode : The inode
* @ sync : synchronous write flag
*
* Returns : errno
*/
static int gfs2_write_inode ( struct inode * inode , int sync )
{
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
/* Check this is a "normal" inode */
2006-09-27 12:50:31 +04:00
if ( inode - > i_private ) {
2006-06-14 23:32:57 +04:00
if ( current - > flags & PF_MEMALLOC )
return 0 ;
if ( sync )
2006-06-19 17:10:39 +04:00
gfs2_log_flush ( GFS2_SB ( inode ) , ip - > i_gl ) ;
2006-06-14 23:32:57 +04:00
}
2006-01-16 19:50:04 +03:00
return 0 ;
}
/**
* gfs2_put_super - Unmount the filesystem
* @ sb : The VFS superblock
*
*/
static void gfs2_put_super ( struct super_block * sb )
{
2006-02-28 01:23:27 +03:00
struct gfs2_sbd * sdp = sb - > s_fs_info ;
2006-01-16 19:50:04 +03:00
int error ;
if ( ! sdp )
return ;
2006-08-25 20:13:37 +04:00
if ( ! strncmp ( sb - > s_type - > name , " gfs2meta " , 8 ) )
2006-09-05 00:16:45 +04:00
return ; /* Nothing to do */
2006-08-25 20:13:37 +04:00
2006-01-16 19:50:04 +03:00
/* Unfreeze the filesystem, if we need to */
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 )
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
kthread_stop ( sdp - > sd_quotad_process ) ;
kthread_stop ( sdp - > sd_logd_process ) ;
kthread_stop ( sdp - > sd_recoverd_process ) ;
while ( sdp - > sd_glockd_num - - )
kthread_stop ( sdp - > sd_glockd_process [ sdp - > sd_glockd_num ] ) ;
kthread_stop ( sdp - > sd_scand_process ) ;
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
error = gfs2_make_fs_ro ( sdp ) ;
if ( error )
gfs2_io_error ( sdp ) ;
}
/* At this point, we're through modifying the disk */
/* Release stuff */
2006-01-30 21:34:10 +03:00
iput ( sdp - > sd_master_dir ) ;
iput ( sdp - > sd_jindex ) ;
iput ( sdp - > sd_inum_inode ) ;
iput ( sdp - > sd_statfs_inode ) ;
iput ( sdp - > sd_rindex ) ;
iput ( sdp - > sd_quota_inode ) ;
2006-01-16 19:50:04 +03:00
gfs2_glock_put ( sdp - > sd_rename_gl ) ;
gfs2_glock_put ( sdp - > sd_trans_gl ) ;
if ( ! sdp - > sd_args . ar_spectator ) {
gfs2_glock_dq_uninit ( & sdp - > sd_journal_gh ) ;
gfs2_glock_dq_uninit ( & sdp - > sd_jinode_gh ) ;
gfs2_glock_dq_uninit ( & sdp - > sd_ir_gh ) ;
gfs2_glock_dq_uninit ( & sdp - > sd_sc_gh ) ;
gfs2_glock_dq_uninit ( & sdp - > sd_qc_gh ) ;
2006-01-30 21:34:10 +03:00
iput ( sdp - > sd_ir_inode ) ;
iput ( sdp - > sd_sc_inode ) ;
iput ( sdp - > sd_qc_inode ) ;
2006-01-16 19:50:04 +03:00
}
gfs2_glock_dq_uninit ( & sdp - > sd_live_gh ) ;
gfs2_clear_rgrpd ( sdp ) ;
gfs2_jindex_free ( sdp ) ;
/* Take apart glock structures and buffer lists */
gfs2_gl_hash_clear ( sdp , WAIT ) ;
/* Unmount the locking protocol */
gfs2_lm_unmount ( sdp ) ;
/* At this point, we're through participating in the lockspace */
gfs2_sys_fs_del ( sdp ) ;
2006-09-10 00:56:34 +04:00
kfree ( sdp ) ;
2006-01-16 19:50:04 +03:00
}
/**
2006-11-01 17:57:57 +03:00
* gfs2_write_super
* @ sb : the superblock
2006-01-16 19:50:04 +03:00
*
*/
static void gfs2_write_super ( struct super_block * sb )
{
2006-11-01 17:57:57 +03:00
sb - > s_dirt = 0 ;
}
/**
* gfs2_sync_fs - sync the filesystem
* @ sb : the superblock
*
* Flushes the log to disk .
*/
static int gfs2_sync_fs ( struct super_block * sb , int wait )
{
sb - > s_dirt = 0 ;
2006-09-05 00:16:45 +04:00
gfs2_log_flush ( sb - > s_fs_info , NULL ) ;
2006-11-01 17:57:57 +03:00
return 0 ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_write_super_lockfs - prevent further writes to the filesystem
* @ sb : the VFS structure for the filesystem
*
*/
static void gfs2_write_super_lockfs ( struct super_block * sb )
{
2006-02-28 01:23:27 +03:00
struct gfs2_sbd * sdp = sb - > s_fs_info ;
2006-01-16 19:50:04 +03:00
int error ;
for ( ; ; ) {
error = gfs2_freeze_fs ( sdp ) ;
if ( ! error )
break ;
switch ( error ) {
case - EBUSY :
fs_err ( sdp , " waiting for recovery before freeze \n " ) ;
break ;
default :
fs_err ( sdp , " error freezing FS: %d \n " , error ) ;
break ;
}
fs_err ( sdp , " retrying... \n " ) ;
msleep ( 1000 ) ;
}
}
/**
* gfs2_unlockfs - reallow writes to the filesystem
* @ sb : the VFS structure for the filesystem
*
*/
static void gfs2_unlockfs ( struct super_block * sb )
{
2006-09-05 17:34:20 +04:00
gfs2_unfreeze_fs ( sb - > s_fs_info ) ;
2006-01-16 19:50:04 +03:00
}
/**
* gfs2_statfs - Gather and return stats about the filesystem
* @ sb : The superblock
* @ statfsbuf : The buffer
*
* Returns : 0 on success or error code
*/
2006-07-03 19:38:01 +04:00
static int gfs2_statfs ( struct dentry * dentry , struct kstatfs * buf )
2006-01-16 19:50:04 +03:00
{
2006-07-03 19:38:01 +04:00
struct super_block * sb = dentry - > d_inode - > i_sb ;
2006-02-28 01:23:27 +03:00
struct gfs2_sbd * sdp = sb - > s_fs_info ;
2006-01-16 19:50:04 +03:00
struct gfs2_statfs_change sc ;
int error ;
if ( gfs2_tune_get ( sdp , gt_statfs_slow ) )
error = gfs2_statfs_slow ( sdp , & sc ) ;
else
error = gfs2_statfs_i ( sdp , & sc ) ;
if ( error )
return error ;
buf - > f_type = GFS2_MAGIC ;
buf - > f_bsize = sdp - > sd_sb . sb_bsize ;
buf - > f_blocks = sc . sc_total ;
buf - > f_bfree = sc . sc_free ;
buf - > f_bavail = sc . sc_free ;
buf - > f_files = sc . sc_dinodes + sc . sc_free ;
buf - > f_ffree = sc . sc_free ;
buf - > f_namelen = GFS2_FNAMESIZE ;
return 0 ;
}
/**
* gfs2_remount_fs - called when the FS is remounted
* @ sb : the filesystem
* @ flags : the remount flags
* @ data : extra data passed in ( not used right now )
*
* Returns : errno
*/
static int gfs2_remount_fs ( struct super_block * sb , int * flags , char * data )
{
2006-02-28 01:23:27 +03:00
struct gfs2_sbd * sdp = sb - > s_fs_info ;
2006-01-16 19:50:04 +03:00
int error ;
error = gfs2_mount_args ( sdp , data , 1 ) ;
if ( error )
return error ;
if ( sdp - > sd_args . ar_spectator )
* flags | = MS_RDONLY ;
else {
if ( * flags & MS_RDONLY ) {
if ( ! ( sb - > s_flags & MS_RDONLY ) )
error = gfs2_make_fs_ro ( sdp ) ;
} else if ( ! ( * flags & MS_RDONLY ) & &
( sb - > s_flags & MS_RDONLY ) ) {
error = gfs2_make_fs_rw ( sdp ) ;
}
}
if ( * flags & ( MS_NOATIME | MS_NODIRATIME ) )
set_bit ( SDF_NOATIME , & sdp - > sd_flags ) ;
else
clear_bit ( SDF_NOATIME , & sdp - > sd_flags ) ;
/* Don't let the VFS update atimes. GFS2 handles this itself. */
* flags | = MS_NOATIME | MS_NODIRATIME ;
return error ;
}
/**
* gfs2_clear_inode - Deallocate an inode when VFS is done with it
* @ inode : The VFS inode
*
*/
static void gfs2_clear_inode ( struct inode * inode )
{
2006-06-14 23:32:57 +04:00
/* This tells us its a "real" inode and not one which only
* serves to contain an address space ( see rgrp . c , meta_io . c )
* which therefore doesn ' t have its own glocks .
*/
2006-09-27 12:50:31 +04:00
if ( inode - > i_private ) {
2006-06-14 23:32:57 +04:00
struct gfs2_inode * ip = GFS2_I ( inode ) ;
gfs2_glock_inode_squish ( inode ) ;
gfs2_assert ( inode - > i_sb - > s_fs_info , ip - > i_gl - > gl_state = = LM_ST_UNLOCKED ) ;
ip - > i_gl - > gl_object = NULL ;
2006-01-16 19:50:04 +03:00
gfs2_glock_schedule_for_reclaim ( ip - > i_gl ) ;
2006-06-14 23:32:57 +04:00
gfs2_glock_put ( ip - > i_gl ) ;
ip - > i_gl = NULL ;
if ( ip - > i_iopen_gh . gh_gl )
gfs2_glock_dq_uninit ( & ip - > i_iopen_gh ) ;
2006-01-16 19:50:04 +03:00
}
}
/**
* gfs2_show_options - Show mount options for / proc / mounts
* @ s : seq_file structure
* @ mnt : vfsmount
*
* Returns : 0 on success or error code
*/
static int gfs2_show_options ( struct seq_file * s , struct vfsmount * mnt )
{
2006-02-28 01:23:27 +03:00
struct gfs2_sbd * sdp = mnt - > mnt_sb - > s_fs_info ;
2006-01-16 19:50:04 +03:00
struct gfs2_args * args = & sdp - > sd_args ;
if ( args - > ar_lockproto [ 0 ] )
seq_printf ( s , " ,lockproto=%s " , args - > ar_lockproto ) ;
if ( args - > ar_locktable [ 0 ] )
seq_printf ( s , " ,locktable=%s " , args - > ar_locktable ) ;
if ( args - > ar_hostdata [ 0 ] )
seq_printf ( s , " ,hostdata=%s " , args - > ar_hostdata ) ;
if ( args - > ar_spectator )
seq_printf ( s , " ,spectator " ) ;
if ( args - > ar_ignore_local_fs )
seq_printf ( s , " ,ignore_local_fs " ) ;
if ( args - > ar_localflocks )
seq_printf ( s , " ,localflocks " ) ;
if ( args - > ar_localcaching )
seq_printf ( s , " ,localcaching " ) ;
if ( args - > ar_debug )
seq_printf ( s , " ,debug " ) ;
if ( args - > ar_upgrade )
seq_printf ( s , " ,upgrade " ) ;
if ( args - > ar_num_glockd ! = GFS2_GLOCKD_DEFAULT )
seq_printf ( s , " ,num_glockd=%u " , args - > ar_num_glockd ) ;
if ( args - > ar_posix_acl )
seq_printf ( s , " ,acl " ) ;
if ( args - > ar_quota ! = GFS2_QUOTA_DEFAULT ) {
char * state ;
switch ( args - > ar_quota ) {
case GFS2_QUOTA_OFF :
state = " off " ;
break ;
case GFS2_QUOTA_ACCOUNT :
state = " account " ;
break ;
case GFS2_QUOTA_ON :
state = " on " ;
break ;
default :
state = " unknown " ;
break ;
}
seq_printf ( s , " ,quota=%s " , state ) ;
}
if ( args - > ar_suiddir )
seq_printf ( s , " ,suiddir " ) ;
if ( args - > ar_data ! = GFS2_DATA_DEFAULT ) {
char * state ;
switch ( args - > ar_data ) {
case GFS2_DATA_WRITEBACK :
state = " writeback " ;
break ;
case GFS2_DATA_ORDERED :
state = " ordered " ;
break ;
default :
state = " unknown " ;
break ;
}
seq_printf ( s , " ,data=%s " , state ) ;
}
return 0 ;
}
2006-09-25 17:26:04 +04:00
/*
2006-06-14 23:32:57 +04:00
* We have to ( at the moment ) hold the inodes main lock to cover
* the gap between unlocking the shared lock on the iopen lock and
* taking the exclusive lock . I ' d rather do a shared - > exclusive
* conversion on the iopen lock , but we can change that later . This
* is safe , just less efficient .
*/
static void gfs2_delete_inode ( struct inode * inode )
{
struct gfs2_sbd * sdp = inode - > i_sb - > s_fs_info ;
struct gfs2_inode * ip = GFS2_I ( inode ) ;
struct gfs2_holder gh ;
int error ;
2006-09-27 12:50:31 +04:00
if ( ! inode - > i_private )
2006-06-14 23:32:57 +04:00
goto out ;
error = gfs2_glock_nq_init ( ip - > i_gl , LM_ST_EXCLUSIVE , LM_FLAG_TRY_1CB | GL_NOCACHE , & gh ) ;
if ( unlikely ( error ) ) {
gfs2_glock_dq_uninit ( & ip - > i_iopen_gh ) ;
goto out ;
}
gfs2_glock_dq ( & ip - > i_iopen_gh ) ;
gfs2_holder_reinit ( LM_ST_EXCLUSIVE , LM_FLAG_TRY_1CB | GL_NOCACHE , & ip - > i_iopen_gh ) ;
error = gfs2_glock_nq ( & ip - > i_iopen_gh ) ;
if ( error )
goto out_uninit ;
if ( S_ISDIR ( ip - > i_di . di_mode ) & &
( ip - > i_di . di_flags & GFS2_DIF_EXHASH ) ) {
error = gfs2_dir_exhash_dealloc ( ip ) ;
if ( error )
goto out_unlock ;
}
if ( ip - > i_di . di_eattr ) {
error = gfs2_ea_dealloc ( ip ) ;
if ( error )
goto out_unlock ;
}
if ( ! gfs2_is_stuffed ( ip ) ) {
error = gfs2_file_dealloc ( ip ) ;
if ( error )
goto out_unlock ;
}
error = gfs2_dinode_dealloc ( ip ) ;
out_unlock :
gfs2_glock_dq ( & ip - > i_iopen_gh ) ;
out_uninit :
gfs2_holder_uninit ( & ip - > i_iopen_gh ) ;
gfs2_glock_dq_uninit ( & gh ) ;
if ( error )
fs_warn ( sdp , " gfs2_delete_inode: %d \n " , error ) ;
out :
truncate_inode_pages ( & inode - > i_data , 0 ) ;
clear_inode ( inode ) ;
}
2006-05-19 00:25:27 +04:00
static struct inode * gfs2_alloc_inode ( struct super_block * sb )
{
struct gfs2_sbd * sdp = sb - > s_fs_info ;
struct gfs2_inode * ip ;
ip = kmem_cache_alloc ( gfs2_inode_cachep , GFP_KERNEL ) ;
if ( ip ) {
ip - > i_flags = 0 ;
ip - > i_gl = NULL ;
ip - > i_greedy = gfs2_tune_get ( sdp , gt_greedy_default ) ;
ip - > i_last_pfault = jiffies ;
}
return & ip - > i_inode ;
}
static void gfs2_destroy_inode ( struct inode * inode )
{
kmem_cache_free ( gfs2_inode_cachep , inode ) ;
}
2006-01-16 19:50:04 +03:00
struct super_operations gfs2_super_ops = {
2006-11-01 17:57:57 +03:00
. alloc_inode = gfs2_alloc_inode ,
. destroy_inode = gfs2_destroy_inode ,
. write_inode = gfs2_write_inode ,
. delete_inode = gfs2_delete_inode ,
. put_super = gfs2_put_super ,
. write_super = gfs2_write_super ,
. sync_fs = gfs2_sync_fs ,
. write_super_lockfs = gfs2_write_super_lockfs ,
. unlockfs = gfs2_unlockfs ,
. statfs = gfs2_statfs ,
. remount_fs = gfs2_remount_fs ,
. clear_inode = gfs2_clear_inode ,
. show_options = gfs2_show_options ,
2006-01-16 19:50:04 +03:00
} ;