2009-04-07 06:01:35 +04:00
/*
* super . c - NILFS module and super block management .
*
* Copyright ( C ) 2005 - 2008 Nippon Telegraph and Telephone Corporation .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
*
* Written by Ryusuke Konishi < ryusuke @ osrg . net >
*/
/*
* linux / fs / ext2 / super . c
*
* Copyright ( C ) 1992 , 1993 , 1994 , 1995
* Remy Card ( card @ masi . ibp . fr )
* Laboratoire MASI - Institut Blaise Pascal
* Universite Pierre et Marie Curie ( Paris VI )
*
* from
*
* linux / fs / minix / inode . c
*
* Copyright ( C ) 1991 , 1992 Linus Torvalds
*
* Big - endian to little - endian byte - swapping / bitmaps by
* David S . Miller ( davem @ caip . rutgers . edu ) , 1995
*/
# include <linux/module.h>
# include <linux/string.h>
# include <linux/slab.h>
# include <linux/init.h>
# include <linux/blkdev.h>
# include <linux/parser.h>
# include <linux/random.h>
# include <linux/crc32.h>
# include <linux/smp_lock.h>
# include <linux/vfs.h>
# include <linux/writeback.h>
# include <linux/kobject.h>
# include <linux/exportfs.h>
2009-06-24 15:06:34 +04:00
# include <linux/seq_file.h>
# include <linux/mount.h>
2009-04-07 06:01:35 +04:00
# include "nilfs.h"
# include "mdt.h"
# include "alloc.h"
# include "page.h"
# include "cpfile.h"
# include "ifile.h"
# include "dat.h"
# include "segment.h"
# include "segbuf.h"
MODULE_AUTHOR ( " NTT Corp. " ) ;
MODULE_DESCRIPTION ( " A New Implementation of the Log-structured Filesystem "
" (NILFS) " ) ;
MODULE_LICENSE ( " GPL " ) ;
2009-04-28 20:00:26 +04:00
static void nilfs_write_super ( struct super_block * sb ) ;
2009-04-07 06:01:35 +04:00
static int nilfs_remount ( struct super_block * sb , int * flags , char * data ) ;
/**
* nilfs_error ( ) - report failure condition on a filesystem
*
* nilfs_error ( ) sets an ERROR_FS flag on the superblock as well as
* reporting an error message . It should be called when NILFS detects
* incoherences or defects of meta data on disk . As for sustainable
* errors such as a single - shot I / O error , nilfs_warning ( ) or the printk ( )
* function should be used instead .
*
* The segment constructor must not call this function because it can
* kill itself .
*/
void nilfs_error ( struct super_block * sb , const char * function ,
const char * fmt , . . . )
{
struct nilfs_sb_info * sbi = NILFS_SB ( sb ) ;
va_list args ;
va_start ( args , fmt ) ;
printk ( KERN_CRIT " NILFS error (device %s): %s: " , sb - > s_id , function ) ;
vprintk ( fmt , args ) ;
printk ( " \n " ) ;
va_end ( args ) ;
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
struct the_nilfs * nilfs = sbi - > s_nilfs ;
if ( ! nilfs_test_opt ( sbi , ERRORS_CONT ) )
nilfs_detach_segment_constructor ( sbi ) ;
down_write ( & nilfs - > ns_sem ) ;
if ( ! ( nilfs - > ns_mount_state & NILFS_ERROR_FS ) ) {
nilfs - > ns_mount_state | = NILFS_ERROR_FS ;
2009-04-07 06:01:59 +04:00
nilfs - > ns_sbp [ 0 ] - > s_state | =
cpu_to_le16 ( NILFS_ERROR_FS ) ;
nilfs_commit_super ( sbi , 1 ) ;
2009-04-07 06:01:35 +04:00
}
up_write ( & nilfs - > ns_sem ) ;
if ( nilfs_test_opt ( sbi , ERRORS_RO ) ) {
printk ( KERN_CRIT " Remounting filesystem read-only \n " ) ;
sb - > s_flags | = MS_RDONLY ;
}
}
if ( nilfs_test_opt ( sbi , ERRORS_PANIC ) )
panic ( " NILFS (device %s): panic forced after error \n " ,
sb - > s_id ) ;
}
void nilfs_warning ( struct super_block * sb , const char * function ,
const char * fmt , . . . )
{
va_list args ;
va_start ( args , fmt ) ;
printk ( KERN_WARNING " NILFS warning (device %s): %s: " ,
sb - > s_id , function ) ;
vprintk ( fmt , args ) ;
printk ( " \n " ) ;
va_end ( args ) ;
}
static struct kmem_cache * nilfs_inode_cachep ;
2009-05-27 17:11:46 +04:00
struct inode * nilfs_alloc_inode_common ( struct the_nilfs * nilfs )
2009-04-07 06:01:35 +04:00
{
struct nilfs_inode_info * ii ;
ii = kmem_cache_alloc ( nilfs_inode_cachep , GFP_NOFS ) ;
if ( ! ii )
return NULL ;
ii - > i_bh = NULL ;
ii - > i_state = 0 ;
ii - > vfs_inode . i_version = 1 ;
2009-05-27 17:11:46 +04:00
nilfs_btnode_cache_init ( & ii - > i_btnode_cache , nilfs - > ns_bdi ) ;
2009-04-07 06:01:35 +04:00
return & ii - > vfs_inode ;
}
2009-05-27 17:11:46 +04:00
struct inode * nilfs_alloc_inode ( struct super_block * sb )
{
return nilfs_alloc_inode_common ( NILFS_SB ( sb ) - > s_nilfs ) ;
}
2009-04-07 06:01:35 +04:00
void nilfs_destroy_inode ( struct inode * inode )
{
kmem_cache_free ( nilfs_inode_cachep , NILFS_I ( inode ) ) ;
}
static void init_once ( void * obj )
{
struct nilfs_inode_info * ii = obj ;
INIT_LIST_HEAD ( & ii - > i_dirty ) ;
# ifdef CONFIG_NILFS_XATTR
init_rwsem ( & ii - > xattr_sem ) ;
# endif
nilfs_btnode_cache_init_once ( & ii - > i_btnode_cache ) ;
ii - > i_bmap = ( struct nilfs_bmap * ) & ii - > i_bmap_union ;
inode_init_once ( & ii - > vfs_inode ) ;
}
static int nilfs_init_inode_cache ( void )
{
nilfs_inode_cachep = kmem_cache_create ( " nilfs2_inode_cache " ,
sizeof ( struct nilfs_inode_info ) ,
0 , SLAB_RECLAIM_ACCOUNT ,
init_once ) ;
return ( nilfs_inode_cachep = = NULL ) ? - ENOMEM : 0 ;
}
static inline void nilfs_destroy_inode_cache ( void )
{
kmem_cache_destroy ( nilfs_inode_cachep ) ;
}
static void nilfs_clear_inode ( struct inode * inode )
{
struct nilfs_inode_info * ii = NILFS_I ( inode ) ;
/*
* Free resources allocated in nilfs_read_inode ( ) , here .
*/
2009-04-07 06:01:44 +04:00
BUG_ON ( ! list_empty ( & ii - > i_dirty ) ) ;
2009-04-07 06:01:35 +04:00
brelse ( ii - > i_bh ) ;
ii - > i_bh = NULL ;
if ( test_bit ( NILFS_I_BMAP , & ii - > i_state ) )
nilfs_bmap_clear ( ii - > i_bmap ) ;
nilfs_btnode_cache_clear ( & ii - > i_btnode_cache ) ;
}
2009-04-07 06:01:59 +04:00
static int nilfs_sync_super ( struct nilfs_sb_info * sbi , int dupsb )
2009-04-07 06:01:35 +04:00
{
struct the_nilfs * nilfs = sbi - > s_nilfs ;
int err ;
int barrier_done = 0 ;
if ( nilfs_test_opt ( sbi , BARRIER ) ) {
2009-04-07 06:01:59 +04:00
set_buffer_ordered ( nilfs - > ns_sbh [ 0 ] ) ;
2009-04-07 06:01:35 +04:00
barrier_done = 1 ;
}
retry :
2009-04-07 06:01:59 +04:00
set_buffer_dirty ( nilfs - > ns_sbh [ 0 ] ) ;
err = sync_dirty_buffer ( nilfs - > ns_sbh [ 0 ] ) ;
2009-04-07 06:01:35 +04:00
if ( err = = - EOPNOTSUPP & & barrier_done ) {
nilfs_warning ( sbi - > s_super , __func__ ,
" barrier-based sync failed. "
" disabling barriers \n " ) ;
nilfs_clear_opt ( sbi , BARRIER ) ;
barrier_done = 0 ;
2009-04-07 06:01:59 +04:00
clear_buffer_ordered ( nilfs - > ns_sbh [ 0 ] ) ;
2009-04-07 06:01:35 +04:00
goto retry ;
}
2009-04-07 06:01:59 +04:00
if ( unlikely ( err ) ) {
2009-04-07 06:01:35 +04:00
printk ( KERN_ERR
" NILFS: unable to write superblock (err=%d) \n " , err ) ;
2009-04-07 06:01:59 +04:00
if ( err = = - EIO & & nilfs - > ns_sbh [ 1 ] ) {
nilfs_fall_back_super_block ( nilfs ) ;
goto retry ;
}
} else {
struct nilfs_super_block * sbp = nilfs - > ns_sbp [ 0 ] ;
/*
* The latest segment becomes trailable from the position
* written in superblock .
*/
2009-04-07 06:01:35 +04:00
clear_nilfs_discontinued ( nilfs ) ;
2009-04-07 06:01:59 +04:00
/* update GC protection for recent segments */
if ( nilfs - > ns_sbh [ 1 ] ) {
sbp = NULL ;
if ( dupsb ) {
set_buffer_dirty ( nilfs - > ns_sbh [ 1 ] ) ;
if ( ! sync_dirty_buffer ( nilfs - > ns_sbh [ 1 ] ) )
sbp = nilfs - > ns_sbp [ 1 ] ;
}
}
if ( sbp ) {
spin_lock ( & nilfs - > ns_last_segment_lock ) ;
nilfs - > ns_prot_seq = le64_to_cpu ( sbp - > s_last_seq ) ;
spin_unlock ( & nilfs - > ns_last_segment_lock ) ;
}
2009-04-07 06:01:35 +04:00
}
return err ;
}
2009-04-07 06:01:59 +04:00
int nilfs_commit_super ( struct nilfs_sb_info * sbi , int dupsb )
2009-04-07 06:01:35 +04:00
{
struct the_nilfs * nilfs = sbi - > s_nilfs ;
2009-04-07 06:01:59 +04:00
struct nilfs_super_block * * sbp = nilfs - > ns_sbp ;
2009-04-07 06:01:35 +04:00
sector_t nfreeblocks ;
2009-04-07 06:01:59 +04:00
time_t t ;
2009-04-07 06:01:35 +04:00
int err ;
/* nilfs->sem must be locked by the caller. */
2009-04-07 06:01:59 +04:00
if ( sbp [ 0 ] - > s_magic ! = NILFS_SUPER_MAGIC ) {
if ( sbp [ 1 ] & & sbp [ 1 ] - > s_magic = = NILFS_SUPER_MAGIC )
nilfs_swap_super_block ( nilfs ) ;
else {
printk ( KERN_CRIT " NILFS: superblock broke on dev %s \n " ,
sbi - > s_super - > s_id ) ;
return - EIO ;
}
}
2009-04-07 06:01:35 +04:00
err = nilfs_count_free_blocks ( nilfs , & nfreeblocks ) ;
if ( unlikely ( err ) ) {
printk ( KERN_ERR " NILFS: failed to count free blocks \n " ) ;
return err ;
}
2009-04-07 06:01:59 +04:00
spin_lock ( & nilfs - > ns_last_segment_lock ) ;
sbp [ 0 ] - > s_last_seq = cpu_to_le64 ( nilfs - > ns_last_seq ) ;
sbp [ 0 ] - > s_last_pseg = cpu_to_le64 ( nilfs - > ns_last_pseg ) ;
sbp [ 0 ] - > s_last_cno = cpu_to_le64 ( nilfs - > ns_last_cno ) ;
spin_unlock ( & nilfs - > ns_last_segment_lock ) ;
t = get_seconds ( ) ;
nilfs - > ns_sbwtime [ 0 ] = t ;
sbp [ 0 ] - > s_free_blocks_count = cpu_to_le64 ( nfreeblocks ) ;
sbp [ 0 ] - > s_wtime = cpu_to_le64 ( t ) ;
sbp [ 0 ] - > s_sum = 0 ;
sbp [ 0 ] - > s_sum = cpu_to_le32 ( crc32_le ( nilfs - > ns_crc_seed ,
( unsigned char * ) sbp [ 0 ] ,
nilfs - > ns_sbsize ) ) ;
if ( dupsb & & sbp [ 1 ] ) {
memcpy ( sbp [ 1 ] , sbp [ 0 ] , nilfs - > ns_sbsize ) ;
nilfs - > ns_sbwtime [ 1 ] = t ;
}
2009-04-07 06:01:35 +04:00
sbi - > s_super - > s_dirt = 0 ;
2009-04-07 06:01:59 +04:00
return nilfs_sync_super ( sbi , dupsb ) ;
2009-04-07 06:01:35 +04:00
}
static void nilfs_put_super ( struct super_block * sb )
{
struct nilfs_sb_info * sbi = NILFS_SB ( sb ) ;
struct the_nilfs * nilfs = sbi - > s_nilfs ;
push BKL down into ->put_super
Move BKL into ->put_super from the only caller. A couple of
filesystems had trivial enough ->put_super (only kfree and NULLing of
s_fs_info + stuff in there) to not get any locking: coda, cramfs, efs,
hugetlbfs, omfs, qnx4, shmem, all others got the full treatment. Most
of them probably don't need it, but I'd rather sort that out individually.
Preferably after all the other BKL pushdowns in that area.
[AV: original used to move lock_super() down as well; these changes are
removed since we don't do lock_super() at all in generic_shutdown_super()
now]
[AV: fuse, btrfs and xfs are known to need no damn BKL, exempt]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2009-05-05 17:40:36 +04:00
lock_kernel ( ) ;
2009-04-07 06:01:35 +04:00
nilfs_detach_segment_constructor ( sbi ) ;
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
down_write ( & nilfs - > ns_sem ) ;
2009-04-07 06:01:59 +04:00
nilfs - > ns_sbp [ 0 ] - > s_state = cpu_to_le16 ( nilfs - > ns_mount_state ) ;
nilfs_commit_super ( sbi , 1 ) ;
2009-04-07 06:01:35 +04:00
up_write ( & nilfs - > ns_sem ) ;
}
2009-06-07 20:39:32 +04:00
down_write ( & nilfs - > ns_super_sem ) ;
2009-06-07 20:39:30 +04:00
if ( nilfs - > ns_current = = sbi )
nilfs - > ns_current = NULL ;
2009-06-07 20:39:32 +04:00
up_write ( & nilfs - > ns_super_sem ) ;
2009-04-07 06:01:35 +04:00
nilfs_detach_checkpoint ( sbi ) ;
put_nilfs ( sbi - > s_nilfs ) ;
sbi - > s_super = NULL ;
sb - > s_fs_info = NULL ;
2009-06-07 20:39:31 +04:00
nilfs_put_sbinfo ( sbi ) ;
push BKL down into ->put_super
Move BKL into ->put_super from the only caller. A couple of
filesystems had trivial enough ->put_super (only kfree and NULLing of
s_fs_info + stuff in there) to not get any locking: coda, cramfs, efs,
hugetlbfs, omfs, qnx4, shmem, all others got the full treatment. Most
of them probably don't need it, but I'd rather sort that out individually.
Preferably after all the other BKL pushdowns in that area.
[AV: original used to move lock_super() down as well; these changes are
removed since we don't do lock_super() at all in generic_shutdown_super()
now]
[AV: fuse, btrfs and xfs are known to need no damn BKL, exempt]
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
2009-05-05 17:40:36 +04:00
unlock_kernel ( ) ;
2009-04-07 06:01:35 +04:00
}
/**
* nilfs_write_super - write super block ( s ) of NILFS
* @ sb : super_block
*
* nilfs_write_super ( ) gets a fs - dependent lock , writes super block ( s ) , and
* clears s_dirt . This function is called in the section protected by
* lock_super ( ) .
*
* The s_dirt flag is managed by each filesystem and we protect it by ns_sem
* of the struct the_nilfs . Lock order must be as follows :
*
* 1. lock_super ( )
* 2. down_write ( & nilfs - > ns_sem )
*
* Inside NILFS , locking ns_sem is enough to protect s_dirt and the buffer
2009-04-07 06:01:59 +04:00
* of the super block ( nilfs - > ns_sbp [ ] ) .
2009-04-07 06:01:35 +04:00
*
* In most cases , VFS functions call lock_super ( ) before calling these
* methods . So we must be careful not to bring on deadlocks when using
* lock_super ( ) ; see generic_shutdown_super ( ) , write_super ( ) , and so on .
*
* Note that order of lock_kernel ( ) and lock_super ( ) depends on contexts
* of VFS . We should also note that lock_kernel ( ) can be used in its
* protective section and only the outermost one has an effect .
*/
static void nilfs_write_super ( struct super_block * sb )
{
struct nilfs_sb_info * sbi = NILFS_SB ( sb ) ;
struct the_nilfs * nilfs = sbi - > s_nilfs ;
down_write ( & nilfs - > ns_sem ) ;
2009-04-07 06:01:59 +04:00
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
2009-07-22 20:26:34 +04:00
if ( ! nilfs_discontinued ( nilfs ) & &
! nilfs_sb_need_update ( nilfs ) ) {
2009-04-07 06:01:59 +04:00
up_write ( & nilfs - > ns_sem ) ;
return ;
}
2009-07-22 20:26:34 +04:00
nilfs_commit_super ( sbi , nilfs_altsb_need_update ( nilfs ) ) ;
2009-04-07 06:01:59 +04:00
}
2009-04-07 06:01:35 +04:00
sb - > s_dirt = 0 ;
up_write ( & nilfs - > ns_sem ) ;
}
static int nilfs_sync_fs ( struct super_block * sb , int wait )
{
2009-07-22 20:26:33 +04:00
struct nilfs_sb_info * sbi = NILFS_SB ( sb ) ;
struct the_nilfs * nilfs = sbi - > s_nilfs ;
2009-04-07 06:01:35 +04:00
int err = 0 ;
/* This function is called when super block should be written back */
if ( wait )
err = nilfs_construct_segment ( sb ) ;
2009-07-22 20:26:33 +04:00
down_write ( & nilfs - > ns_sem ) ;
if ( sb - > s_dirt )
nilfs_commit_super ( sbi , 1 ) ;
up_write ( & nilfs - > ns_sem ) ;
2009-04-07 06:01:35 +04:00
return err ;
}
int nilfs_attach_checkpoint ( struct nilfs_sb_info * sbi , __u64 cno )
{
struct the_nilfs * nilfs = sbi - > s_nilfs ;
struct nilfs_checkpoint * raw_cp ;
struct buffer_head * bh_cp ;
int err ;
2009-06-07 20:39:32 +04:00
down_write ( & nilfs - > ns_super_sem ) ;
2009-04-07 06:01:35 +04:00
list_add ( & sbi - > s_list , & nilfs - > ns_supers ) ;
2009-06-07 20:39:32 +04:00
up_write ( & nilfs - > ns_super_sem ) ;
2009-04-07 06:01:35 +04:00
sbi - > s_ifile = nilfs_mdt_new (
nilfs , sbi - > s_super , NILFS_IFILE_INO , NILFS_IFILE_GFP ) ;
if ( ! sbi - > s_ifile )
return - ENOMEM ;
err = nilfs_palloc_init_blockgroup ( sbi - > s_ifile , nilfs - > ns_inode_size ) ;
if ( unlikely ( err ) )
goto failed ;
2009-08-18 10:58:24 +04:00
down_read ( & nilfs - > ns_segctor_sem ) ;
2009-04-07 06:01:35 +04:00
err = nilfs_cpfile_get_checkpoint ( nilfs - > ns_cpfile , cno , 0 , & raw_cp ,
& bh_cp ) ;
2009-08-18 10:58:24 +04:00
up_read ( & nilfs - > ns_segctor_sem ) ;
2009-04-07 06:01:35 +04:00
if ( unlikely ( err ) ) {
if ( err = = - ENOENT | | err = = - EINVAL ) {
printk ( KERN_ERR
" NILFS: Invalid checkpoint "
" (checkpoint number=%llu) \n " ,
( unsigned long long ) cno ) ;
err = - EINVAL ;
}
goto failed ;
}
err = nilfs_read_inode_common ( sbi - > s_ifile , & raw_cp - > cp_ifile_inode ) ;
if ( unlikely ( err ) )
goto failed_bh ;
atomic_set ( & sbi - > s_inodes_count , le64_to_cpu ( raw_cp - > cp_inodes_count ) ) ;
atomic_set ( & sbi - > s_blocks_count , le64_to_cpu ( raw_cp - > cp_blocks_count ) ) ;
nilfs_cpfile_put_checkpoint ( nilfs - > ns_cpfile , cno , bh_cp ) ;
return 0 ;
failed_bh :
nilfs_cpfile_put_checkpoint ( nilfs - > ns_cpfile , cno , bh_cp ) ;
failed :
nilfs_mdt_destroy ( sbi - > s_ifile ) ;
sbi - > s_ifile = NULL ;
2009-06-07 20:39:32 +04:00
down_write ( & nilfs - > ns_super_sem ) ;
2009-04-07 06:01:35 +04:00
list_del_init ( & sbi - > s_list ) ;
2009-06-07 20:39:32 +04:00
up_write ( & nilfs - > ns_super_sem ) ;
2009-04-07 06:01:35 +04:00
return err ;
}
void nilfs_detach_checkpoint ( struct nilfs_sb_info * sbi )
{
struct the_nilfs * nilfs = sbi - > s_nilfs ;
nilfs_mdt_clear ( sbi - > s_ifile ) ;
nilfs_mdt_destroy ( sbi - > s_ifile ) ;
sbi - > s_ifile = NULL ;
2009-06-07 20:39:32 +04:00
down_write ( & nilfs - > ns_super_sem ) ;
2009-04-07 06:01:35 +04:00
list_del_init ( & sbi - > s_list ) ;
2009-06-07 20:39:32 +04:00
up_write ( & nilfs - > ns_super_sem ) ;
2009-04-07 06:01:35 +04:00
}
static int nilfs_mark_recovery_complete ( struct nilfs_sb_info * sbi )
{
struct the_nilfs * nilfs = sbi - > s_nilfs ;
int err = 0 ;
down_write ( & nilfs - > ns_sem ) ;
if ( ! ( nilfs - > ns_mount_state & NILFS_VALID_FS ) ) {
nilfs - > ns_mount_state | = NILFS_VALID_FS ;
2009-04-07 06:01:59 +04:00
err = nilfs_commit_super ( sbi , 1 ) ;
2009-04-07 06:01:35 +04:00
if ( likely ( ! err ) )
printk ( KERN_INFO " NILFS: recovery complete. \n " ) ;
}
up_write ( & nilfs - > ns_sem ) ;
return err ;
}
static int nilfs_statfs ( struct dentry * dentry , struct kstatfs * buf )
{
struct super_block * sb = dentry - > d_sb ;
struct nilfs_sb_info * sbi = NILFS_SB ( sb ) ;
2009-03-26 04:16:57 +03:00
struct the_nilfs * nilfs = sbi - > s_nilfs ;
u64 id = huge_encode_dev ( sb - > s_bdev - > bd_dev ) ;
2009-04-07 06:01:35 +04:00
unsigned long long blocks ;
unsigned long overhead ;
unsigned long nrsvblocks ;
sector_t nfreeblocks ;
int err ;
/*
* Compute all of the segment blocks
*
* The blocks before first segment and after last segment
* are excluded .
*/
blocks = nilfs - > ns_blocks_per_segment * nilfs - > ns_nsegments
- nilfs - > ns_first_data_block ;
nrsvblocks = nilfs - > ns_nrsvsegs * nilfs - > ns_blocks_per_segment ;
/*
* Compute the overhead
*
* When distributing meta data blocks outside semgent structure ,
* We must count them as the overhead .
*/
overhead = 0 ;
err = nilfs_count_free_blocks ( nilfs , & nfreeblocks ) ;
if ( unlikely ( err ) )
return err ;
buf - > f_type = NILFS_SUPER_MAGIC ;
buf - > f_bsize = sb - > s_blocksize ;
buf - > f_blocks = blocks - overhead ;
buf - > f_bfree = nfreeblocks ;
buf - > f_bavail = ( buf - > f_bfree > = nrsvblocks ) ?
( buf - > f_bfree - nrsvblocks ) : 0 ;
buf - > f_files = atomic_read ( & sbi - > s_inodes_count ) ;
buf - > f_ffree = 0 ; /* nilfs_count_free_inodes(sb); */
buf - > f_namelen = NILFS_NAME_LEN ;
2009-03-26 04:16:57 +03:00
buf - > f_fsid . val [ 0 ] = ( u32 ) id ;
buf - > f_fsid . val [ 1 ] = ( u32 ) ( id > > 32 ) ;
2009-04-07 06:01:35 +04:00
return 0 ;
}
2009-06-24 15:06:34 +04:00
static int nilfs_show_options ( struct seq_file * seq , struct vfsmount * vfs )
{
struct super_block * sb = vfs - > mnt_sb ;
struct nilfs_sb_info * sbi = NILFS_SB ( sb ) ;
if ( ! nilfs_test_opt ( sbi , BARRIER ) )
seq_printf ( seq , " ,barrier=off " ) ;
if ( nilfs_test_opt ( sbi , SNAPSHOT ) )
seq_printf ( seq , " ,cp=%llu " ,
( unsigned long long int ) sbi - > s_snapshot_cno ) ;
if ( nilfs_test_opt ( sbi , ERRORS_RO ) )
seq_printf ( seq , " ,errors=remount-ro " ) ;
if ( nilfs_test_opt ( sbi , ERRORS_PANIC ) )
seq_printf ( seq , " ,errors=panic " ) ;
if ( nilfs_test_opt ( sbi , STRICT_ORDER ) )
seq_printf ( seq , " ,order=strict " ) ;
return 0 ;
}
2009-04-07 06:01:35 +04:00
static struct super_operations nilfs_sops = {
. alloc_inode = nilfs_alloc_inode ,
. destroy_inode = nilfs_destroy_inode ,
. dirty_inode = nilfs_dirty_inode ,
/* .write_inode = nilfs_write_inode, */
/* .put_inode = nilfs_put_inode, */
/* .drop_inode = nilfs_drop_inode, */
. delete_inode = nilfs_delete_inode ,
. put_super = nilfs_put_super ,
. write_super = nilfs_write_super ,
. sync_fs = nilfs_sync_fs ,
/* .write_super_lockfs */
/* .unlockfs */
. statfs = nilfs_statfs ,
. remount_fs = nilfs_remount ,
. clear_inode = nilfs_clear_inode ,
/* .umount_begin */
2009-06-24 15:06:34 +04:00
. show_options = nilfs_show_options
2009-04-07 06:01:35 +04:00
} ;
static struct inode *
nilfs_nfs_get_inode ( struct super_block * sb , u64 ino , u32 generation )
{
struct inode * inode ;
if ( ino < NILFS_FIRST_INO ( sb ) & & ino ! = NILFS_ROOT_INO & &
ino ! = NILFS_SKETCH_INO )
return ERR_PTR ( - ESTALE ) ;
inode = nilfs_iget ( sb , ino ) ;
if ( IS_ERR ( inode ) )
return ERR_CAST ( inode ) ;
if ( generation & & inode - > i_generation ! = generation ) {
iput ( inode ) ;
return ERR_PTR ( - ESTALE ) ;
}
return inode ;
}
static struct dentry *
nilfs_fh_to_dentry ( struct super_block * sb , struct fid * fid , int fh_len ,
int fh_type )
{
return generic_fh_to_dentry ( sb , fid , fh_len , fh_type ,
nilfs_nfs_get_inode ) ;
}
static struct dentry *
nilfs_fh_to_parent ( struct super_block * sb , struct fid * fid , int fh_len ,
int fh_type )
{
return generic_fh_to_parent ( sb , fid , fh_len , fh_type ,
nilfs_nfs_get_inode ) ;
}
static struct export_operations nilfs_export_ops = {
. fh_to_dentry = nilfs_fh_to_dentry ,
. fh_to_parent = nilfs_fh_to_parent ,
. get_parent = nilfs_get_parent ,
} ;
enum {
Opt_err_cont , Opt_err_panic , Opt_err_ro ,
Opt_barrier , Opt_snapshot , Opt_order ,
Opt_err ,
} ;
static match_table_t tokens = {
{ Opt_err_cont , " errors=continue " } ,
{ Opt_err_panic , " errors=panic " } ,
{ Opt_err_ro , " errors=remount-ro " } ,
{ Opt_barrier , " barrier=%s " } ,
{ Opt_snapshot , " cp=%u " } ,
{ Opt_order , " order=%s " } ,
{ Opt_err , NULL }
} ;
static int match_bool ( substring_t * s , int * result )
{
int len = s - > to - s - > from ;
if ( strncmp ( s - > from , " on " , len ) = = 0 )
* result = 1 ;
else if ( strncmp ( s - > from , " off " , len ) = = 0 )
* result = 0 ;
else
return 1 ;
return 0 ;
}
static int parse_options ( char * options , struct super_block * sb )
{
struct nilfs_sb_info * sbi = NILFS_SB ( sb ) ;
char * p ;
substring_t args [ MAX_OPT_ARGS ] ;
int option ;
if ( ! options )
return 1 ;
while ( ( p = strsep ( & options , " , " ) ) ! = NULL ) {
int token ;
if ( ! * p )
continue ;
token = match_token ( p , tokens , args ) ;
switch ( token ) {
case Opt_barrier :
if ( match_bool ( & args [ 0 ] , & option ) )
return 0 ;
if ( option )
nilfs_set_opt ( sbi , BARRIER ) ;
else
nilfs_clear_opt ( sbi , BARRIER ) ;
break ;
case Opt_order :
if ( strcmp ( args [ 0 ] . from , " relaxed " ) = = 0 )
/* Ordered data semantics */
nilfs_clear_opt ( sbi , STRICT_ORDER ) ;
else if ( strcmp ( args [ 0 ] . from , " strict " ) = = 0 )
/* Strict in-order semantics */
nilfs_set_opt ( sbi , STRICT_ORDER ) ;
else
return 0 ;
break ;
case Opt_err_panic :
nilfs_write_opt ( sbi , ERROR_MODE , ERRORS_PANIC ) ;
break ;
case Opt_err_ro :
nilfs_write_opt ( sbi , ERROR_MODE , ERRORS_RO ) ;
break ;
case Opt_err_cont :
nilfs_write_opt ( sbi , ERROR_MODE , ERRORS_CONT ) ;
break ;
case Opt_snapshot :
if ( match_int ( & args [ 0 ] , & option ) | | option < = 0 )
return 0 ;
if ( ! ( sb - > s_flags & MS_RDONLY ) )
return 0 ;
sbi - > s_snapshot_cno = option ;
nilfs_set_opt ( sbi , SNAPSHOT ) ;
break ;
default :
printk ( KERN_ERR
" NILFS: Unrecognized mount option \" %s \" \n " , p ) ;
return 0 ;
}
}
return 1 ;
}
static inline void
nilfs_set_default_options ( struct nilfs_sb_info * sbi ,
struct nilfs_super_block * sbp )
{
sbi - > s_mount_opt =
NILFS_MOUNT_ERRORS_CONT | NILFS_MOUNT_BARRIER ;
}
static int nilfs_setup_super ( struct nilfs_sb_info * sbi )
{
struct the_nilfs * nilfs = sbi - > s_nilfs ;
2009-04-07 06:01:59 +04:00
struct nilfs_super_block * sbp = nilfs - > ns_sbp [ 0 ] ;
2009-04-07 06:01:35 +04:00
int max_mnt_count = le16_to_cpu ( sbp - > s_max_mnt_count ) ;
int mnt_count = le16_to_cpu ( sbp - > s_mnt_count ) ;
/* nilfs->sem must be locked by the caller. */
if ( ! ( nilfs - > ns_mount_state & NILFS_VALID_FS ) ) {
printk ( KERN_WARNING " NILFS warning: mounting unchecked fs \n " ) ;
} else if ( nilfs - > ns_mount_state & NILFS_ERROR_FS ) {
printk ( KERN_WARNING
" NILFS warning: mounting fs with errors \n " ) ;
#if 0
} else if ( max_mnt_count > = 0 & & mnt_count > = max_mnt_count ) {
printk ( KERN_WARNING
" NILFS warning: maximal mount count reached \n " ) ;
# endif
}
if ( ! max_mnt_count )
sbp - > s_max_mnt_count = cpu_to_le16 ( NILFS_DFL_MAX_MNT_COUNT ) ;
sbp - > s_mnt_count = cpu_to_le16 ( mnt_count + 1 ) ;
sbp - > s_state = cpu_to_le16 ( le16_to_cpu ( sbp - > s_state ) & ~ NILFS_VALID_FS ) ;
sbp - > s_mtime = cpu_to_le64 ( get_seconds ( ) ) ;
2009-04-07 06:01:59 +04:00
return nilfs_commit_super ( sbi , 1 ) ;
2009-04-07 06:01:35 +04:00
}
2009-04-07 06:01:59 +04:00
struct nilfs_super_block * nilfs_read_super_block ( struct super_block * sb ,
u64 pos , int blocksize ,
struct buffer_head * * pbh )
2009-04-07 06:01:35 +04:00
{
2009-04-07 06:01:59 +04:00
unsigned long long sb_index = pos ;
unsigned long offset ;
2009-04-07 06:01:35 +04:00
2009-04-07 06:01:59 +04:00
offset = do_div ( sb_index , blocksize ) ;
2009-04-07 06:01:35 +04:00
* pbh = sb_bread ( sb , sb_index ) ;
2009-04-07 06:01:59 +04:00
if ( ! * pbh )
2009-04-07 06:01:35 +04:00
return NULL ;
return ( struct nilfs_super_block * ) ( ( char * ) ( * pbh ) - > b_data + offset ) ;
}
int nilfs_store_magic_and_option ( struct super_block * sb ,
struct nilfs_super_block * sbp ,
char * data )
{
struct nilfs_sb_info * sbi = NILFS_SB ( sb ) ;
sb - > s_magic = le16_to_cpu ( sbp - > s_magic ) ;
/* FS independent flags */
# ifdef NILFS_ATIME_DISABLE
sb - > s_flags | = MS_NOATIME ;
# endif
nilfs_set_default_options ( sbi , sbp ) ;
sbi - > s_resuid = le16_to_cpu ( sbp - > s_def_resuid ) ;
sbi - > s_resgid = le16_to_cpu ( sbp - > s_def_resgid ) ;
sbi - > s_interval = le32_to_cpu ( sbp - > s_c_interval ) ;
sbi - > s_watermark = le32_to_cpu ( sbp - > s_c_block_max ) ;
2009-04-07 06:01:59 +04:00
return ! parse_options ( data , sb ) ? - EINVAL : 0 ;
2009-04-07 06:01:35 +04:00
}
/**
* nilfs_fill_super ( ) - initialize a super block instance
* @ sb : super_block
* @ data : mount options
* @ silent : silent mode flag
* @ nilfs : the_nilfs struct
*
2009-06-07 20:39:33 +04:00
* This function is called exclusively by nilfs - > ns_mount_mutex .
2009-04-07 06:01:35 +04:00
* So , the recovery process is protected from other simultaneous mounts .
*/
static int
nilfs_fill_super ( struct super_block * sb , void * data , int silent ,
struct the_nilfs * nilfs )
{
struct nilfs_sb_info * sbi ;
struct inode * root ;
__u64 cno ;
int err ;
sbi = kzalloc ( sizeof ( * sbi ) , GFP_KERNEL ) ;
if ( ! sbi )
return - ENOMEM ;
sb - > s_fs_info = sbi ;
get_nilfs ( nilfs ) ;
sbi - > s_nilfs = nilfs ;
sbi - > s_super = sb ;
2009-06-07 20:39:31 +04:00
atomic_set ( & sbi - > s_count , 1 ) ;
2009-04-07 06:01:35 +04:00
err = init_nilfs ( nilfs , sbi , ( char * ) data ) ;
if ( err )
goto failed_sbi ;
spin_lock_init ( & sbi - > s_inode_lock ) ;
INIT_LIST_HEAD ( & sbi - > s_dirty_files ) ;
INIT_LIST_HEAD ( & sbi - > s_list ) ;
/*
* Following initialization is overlapped because
* nilfs_sb_info structure has been cleared at the beginning .
* But we reserve them to keep our interest and make ready
* for the future change .
*/
get_random_bytes ( & sbi - > s_next_generation ,
sizeof ( sbi - > s_next_generation ) ) ;
spin_lock_init ( & sbi - > s_next_gen_lock ) ;
sb - > s_op = & nilfs_sops ;
sb - > s_export_op = & nilfs_export_ops ;
sb - > s_root = NULL ;
2009-04-07 06:02:00 +04:00
sb - > s_time_gran = 1 ;
2009-04-07 06:01:35 +04:00
if ( ! nilfs_loaded ( nilfs ) ) {
err = load_nilfs ( nilfs , sbi ) ;
if ( err )
goto failed_sbi ;
}
cno = nilfs_last_cno ( nilfs ) ;
if ( sb - > s_flags & MS_RDONLY ) {
if ( nilfs_test_opt ( sbi , SNAPSHOT ) ) {
2009-04-07 06:01:55 +04:00
err = nilfs_cpfile_is_snapshot ( nilfs - > ns_cpfile ,
sbi - > s_snapshot_cno ) ;
if ( err < 0 )
goto failed_sbi ;
if ( ! err ) {
2009-04-07 06:01:35 +04:00
printk ( KERN_ERR
" NILFS: The specified checkpoint is "
" not a snapshot "
" (checkpoint number=%llu). \n " ,
( unsigned long long ) sbi - > s_snapshot_cno ) ;
err = - EINVAL ;
goto failed_sbi ;
}
cno = sbi - > s_snapshot_cno ;
} else
/* Read-only mount */
sbi - > s_snapshot_cno = cno ;
}
err = nilfs_attach_checkpoint ( sbi , cno ) ;
if ( err ) {
printk ( KERN_ERR " NILFS: error loading a checkpoint "
" (checkpoint number=%llu). \n " , ( unsigned long long ) cno ) ;
goto failed_sbi ;
}
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
2009-04-07 06:01:58 +04:00
err = nilfs_attach_segment_constructor ( sbi ) ;
2009-04-07 06:01:35 +04:00
if ( err )
goto failed_checkpoint ;
}
root = nilfs_iget ( sb , NILFS_ROOT_INO ) ;
if ( IS_ERR ( root ) ) {
printk ( KERN_ERR " NILFS: get root inode failed \n " ) ;
err = PTR_ERR ( root ) ;
goto failed_segctor ;
}
if ( ! S_ISDIR ( root - > i_mode ) | | ! root - > i_blocks | | ! root - > i_size ) {
iput ( root ) ;
printk ( KERN_ERR " NILFS: corrupt root inode. \n " ) ;
err = - EINVAL ;
goto failed_segctor ;
}
sb - > s_root = d_alloc_root ( root ) ;
if ( ! sb - > s_root ) {
iput ( root ) ;
printk ( KERN_ERR " NILFS: get root dentry failed \n " ) ;
err = - ENOMEM ;
goto failed_segctor ;
}
if ( ! ( sb - > s_flags & MS_RDONLY ) ) {
down_write ( & nilfs - > ns_sem ) ;
nilfs_setup_super ( sbi ) ;
up_write ( & nilfs - > ns_sem ) ;
}
err = nilfs_mark_recovery_complete ( sbi ) ;
if ( unlikely ( err ) ) {
printk ( KERN_ERR " NILFS: recovery failed. \n " ) ;
goto failed_root ;
}
2009-06-07 20:39:32 +04:00
down_write ( & nilfs - > ns_super_sem ) ;
2009-06-07 20:39:30 +04:00
if ( ! nilfs_test_opt ( sbi , SNAPSHOT ) )
nilfs - > ns_current = sbi ;
2009-06-07 20:39:32 +04:00
up_write ( & nilfs - > ns_super_sem ) ;
2009-06-07 20:39:30 +04:00
2009-04-07 06:01:35 +04:00
return 0 ;
failed_root :
dput ( sb - > s_root ) ;
sb - > s_root = NULL ;
failed_segctor :
nilfs_detach_segment_constructor ( sbi ) ;
failed_checkpoint :
nilfs_detach_checkpoint ( sbi ) ;
failed_sbi :
put_nilfs ( nilfs ) ;
sb - > s_fs_info = NULL ;
2009-06-07 20:39:31 +04:00
nilfs_put_sbinfo ( sbi ) ;
2009-04-07 06:01:35 +04:00
return err ;
}
static int nilfs_remount ( struct super_block * sb , int * flags , char * data )
{
struct nilfs_sb_info * sbi = NILFS_SB ( sb ) ;
struct nilfs_super_block * sbp ;
struct the_nilfs * nilfs = sbi - > s_nilfs ;
unsigned long old_sb_flags ;
struct nilfs_mount_options old_opts ;
int err ;
2009-05-12 17:10:54 +04:00
lock_kernel ( ) ;
2009-06-07 20:39:32 +04:00
down_write ( & nilfs - > ns_super_sem ) ;
2009-04-07 06:01:35 +04:00
old_sb_flags = sb - > s_flags ;
old_opts . mount_opt = sbi - > s_mount_opt ;
old_opts . snapshot_cno = sbi - > s_snapshot_cno ;
if ( ! parse_options ( data , sb ) ) {
err = - EINVAL ;
goto restore_opts ;
}
sb - > s_flags = ( sb - > s_flags & ~ MS_POSIXACL ) ;
if ( ( * flags & MS_RDONLY ) & &
sbi - > s_snapshot_cno ! = old_opts . snapshot_cno ) {
printk ( KERN_WARNING " NILFS (device %s): couldn't "
" remount to a different snapshot. \n " ,
sb - > s_id ) ;
err = - EINVAL ;
goto restore_opts ;
}
if ( ( * flags & MS_RDONLY ) = = ( sb - > s_flags & MS_RDONLY ) )
goto out ;
if ( * flags & MS_RDONLY ) {
/* Shutting down the segment constructor */
nilfs_detach_segment_constructor ( sbi ) ;
sb - > s_flags | = MS_RDONLY ;
sbi - > s_snapshot_cno = nilfs_last_cno ( nilfs ) ;
/* nilfs_set_opt(sbi, SNAPSHOT); */
/*
* Remounting a valid RW partition RDONLY , so set
* the RDONLY flag and then mark the partition as valid again .
*/
down_write ( & nilfs - > ns_sem ) ;
2009-04-07 06:01:59 +04:00
sbp = nilfs - > ns_sbp [ 0 ] ;
2009-04-07 06:01:35 +04:00
if ( ! ( sbp - > s_state & le16_to_cpu ( NILFS_VALID_FS ) ) & &
( nilfs - > ns_mount_state & NILFS_VALID_FS ) )
sbp - > s_state = cpu_to_le16 ( nilfs - > ns_mount_state ) ;
sbp - > s_mtime = cpu_to_le64 ( get_seconds ( ) ) ;
2009-04-07 06:01:59 +04:00
nilfs_commit_super ( sbi , 1 ) ;
2009-04-07 06:01:35 +04:00
up_write ( & nilfs - > ns_sem ) ;
} else {
/*
* Mounting a RDONLY partition read - write , so reread and
* store the current valid flag . ( It may have been changed
* by fsck since we originally mounted the partition . )
*/
2009-06-07 20:39:30 +04:00
if ( nilfs - > ns_current & & nilfs - > ns_current ! = sbi ) {
2009-04-07 06:01:35 +04:00
printk ( KERN_WARNING " NILFS (device %s): couldn't "
2009-06-07 20:39:30 +04:00
" remount because an RW-mount exists. \n " ,
2009-04-07 06:01:35 +04:00
sb - > s_id ) ;
err = - EBUSY ;
2009-06-07 20:39:32 +04:00
goto restore_opts ;
2009-04-07 06:01:35 +04:00
}
if ( sbi - > s_snapshot_cno ! = nilfs_last_cno ( nilfs ) ) {
printk ( KERN_WARNING " NILFS (device %s): couldn't "
" remount because the current RO-mount is not "
" the latest one. \n " ,
sb - > s_id ) ;
err = - EINVAL ;
2009-06-07 20:39:32 +04:00
goto restore_opts ;
2009-04-07 06:01:35 +04:00
}
sb - > s_flags & = ~ MS_RDONLY ;
nilfs_clear_opt ( sbi , SNAPSHOT ) ;
sbi - > s_snapshot_cno = 0 ;
2009-04-07 06:01:58 +04:00
err = nilfs_attach_segment_constructor ( sbi ) ;
2009-04-07 06:01:35 +04:00
if ( err )
2009-06-07 20:39:32 +04:00
goto restore_opts ;
2009-04-07 06:01:35 +04:00
down_write ( & nilfs - > ns_sem ) ;
nilfs_setup_super ( sbi ) ;
up_write ( & nilfs - > ns_sem ) ;
2009-06-07 20:39:32 +04:00
nilfs - > ns_current = sbi ;
2009-04-07 06:01:35 +04:00
}
out :
2009-06-07 20:39:32 +04:00
up_write ( & nilfs - > ns_super_sem ) ;
2009-05-12 17:10:54 +04:00
unlock_kernel ( ) ;
2009-04-07 06:01:35 +04:00
return 0 ;
restore_opts :
sb - > s_flags = old_sb_flags ;
sbi - > s_mount_opt = old_opts . mount_opt ;
sbi - > s_snapshot_cno = old_opts . snapshot_cno ;
2009-06-07 20:39:32 +04:00
up_write ( & nilfs - > ns_super_sem ) ;
2009-05-12 17:10:54 +04:00
unlock_kernel ( ) ;
2009-04-07 06:01:35 +04:00
return err ;
}
struct nilfs_super_data {
struct block_device * bdev ;
2009-06-07 20:39:31 +04:00
struct nilfs_sb_info * sbi ;
2009-04-07 06:01:35 +04:00
__u64 cno ;
int flags ;
} ;
/**
* nilfs_identify - pre - read mount options needed to identify mount instance
* @ data : mount options
* @ sd : nilfs_super_data
*/
static int nilfs_identify ( char * data , struct nilfs_super_data * sd )
{
char * p , * options = data ;
substring_t args [ MAX_OPT_ARGS ] ;
int option , token ;
int ret = 0 ;
do {
p = strsep ( & options , " , " ) ;
if ( p ! = NULL & & * p ) {
token = match_token ( p , tokens , args ) ;
if ( token = = Opt_snapshot ) {
if ( ! ( sd - > flags & MS_RDONLY ) )
ret + + ;
else {
ret = match_int ( & args [ 0 ] , & option ) ;
if ( ! ret ) {
if ( option > 0 )
sd - > cno = option ;
else
ret + + ;
}
}
}
if ( ret )
printk ( KERN_ERR
" NILFS: invalid mount option: %s \n " , p ) ;
}
if ( ! options )
break ;
BUG_ON ( options = = data ) ;
* ( options - 1 ) = ' , ' ;
} while ( ! ret ) ;
return ret ;
}
static int nilfs_set_bdev_super ( struct super_block * s , void * data )
{
struct nilfs_super_data * sd = data ;
s - > s_bdev = sd - > bdev ;
s - > s_dev = s - > s_bdev - > bd_dev ;
return 0 ;
}
static int nilfs_test_bdev_super ( struct super_block * s , void * data )
{
struct nilfs_super_data * sd = data ;
2009-06-07 20:39:31 +04:00
return sd - > sbi & & s - > s_fs_info = = ( void * ) sd - > sbi ;
2009-04-07 06:01:35 +04:00
}
static int
nilfs_get_sb ( struct file_system_type * fs_type , int flags ,
const char * dev_name , void * data , struct vfsmount * mnt )
{
struct nilfs_super_data sd ;
2009-06-07 20:39:29 +04:00
struct super_block * s ;
struct the_nilfs * nilfs ;
2009-04-07 06:01:35 +04:00
int err , need_to_close = 1 ;
sd . bdev = open_bdev_exclusive ( dev_name , flags , fs_type ) ;
if ( IS_ERR ( sd . bdev ) )
return PTR_ERR ( sd . bdev ) ;
/*
* To get mount instance using sget ( ) vfs - routine , NILFS needs
* much more information than normal filesystems to identify mount
* instance . For snapshot mounts , not only a mount type ( ro - mount
* or rw - mount ) but also a checkpoint number is required .
*/
sd . cno = 0 ;
sd . flags = flags ;
if ( nilfs_identify ( ( char * ) data , & sd ) ) {
err = - EINVAL ;
goto failed ;
}
2009-06-07 20:39:29 +04:00
nilfs = find_or_create_nilfs ( sd . bdev ) ;
if ( ! nilfs ) {
err = - ENOMEM ;
goto failed ;
}
2009-06-07 20:39:33 +04:00
mutex_lock ( & nilfs - > ns_mount_mutex ) ;
2009-06-07 20:39:30 +04:00
if ( ! sd . cno ) {
/*
* Check if an exclusive mount exists or not .
* Snapshot mounts coexist with a current mount
* ( i . e . rw - mount or ro - mount ) , whereas rw - mount and
* ro - mount are mutually exclusive .
*/
2009-06-07 20:39:32 +04:00
down_read ( & nilfs - > ns_super_sem ) ;
2009-06-07 20:39:30 +04:00
if ( nilfs - > ns_current & &
( ( nilfs - > ns_current - > s_super - > s_flags ^ flags )
& MS_RDONLY ) ) {
2009-06-07 20:39:32 +04:00
up_read ( & nilfs - > ns_super_sem ) ;
2009-06-07 20:39:30 +04:00
err = - EBUSY ;
goto failed_unlock ;
}
2009-06-07 20:39:32 +04:00
up_read ( & nilfs - > ns_super_sem ) ;
2009-04-07 06:01:35 +04:00
}
/*
2009-06-07 20:39:31 +04:00
* Find existing nilfs_sb_info struct
2009-04-07 06:01:35 +04:00
*/
2009-06-07 20:39:31 +04:00
sd . sbi = nilfs_find_sbinfo ( nilfs , ! ( flags & MS_RDONLY ) , sd . cno ) ;
2009-06-07 20:39:29 +04:00
if ( ! sd . cno )
/* trying to get the latest checkpoint. */
sd . cno = nilfs_last_cno ( nilfs ) ;
2009-04-07 06:01:35 +04:00
2009-06-07 20:39:31 +04:00
/*
* Get super block instance holding the nilfs_sb_info struct .
* A new instance is allocated if no existing mount is present or
* existing instance has been unmounted .
*/
2009-06-07 20:39:29 +04:00
s = sget ( fs_type , nilfs_test_bdev_super , nilfs_set_bdev_super , & sd ) ;
2009-06-07 20:39:31 +04:00
if ( sd . sbi )
nilfs_put_sbinfo ( sd . sbi ) ;
2009-06-07 20:39:29 +04:00
if ( IS_ERR ( s ) ) {
err = PTR_ERR ( s ) ;
goto failed_unlock ;
2009-04-07 06:01:35 +04:00
}
if ( ! s - > s_root ) {
char b [ BDEVNAME_SIZE ] ;
2009-06-07 20:39:29 +04:00
/* New superblock instance created */
2009-04-07 06:01:35 +04:00
s - > s_flags = flags ;
strlcpy ( s - > s_id , bdevname ( sd . bdev , b ) , sizeof ( s - > s_id ) ) ;
sb_set_blocksize ( s , block_size ( sd . bdev ) ) ;
err = nilfs_fill_super ( s , data , flags & MS_VERBOSE , nilfs ) ;
if ( err )
goto cancel_new ;
s - > s_flags | = MS_ACTIVE ;
need_to_close = 0 ;
}
2009-06-07 20:39:33 +04:00
mutex_unlock ( & nilfs - > ns_mount_mutex ) ;
2009-04-07 06:01:35 +04:00
put_nilfs ( nilfs ) ;
if ( need_to_close )
close_bdev_exclusive ( sd . bdev , flags ) ;
simple_set_mnt ( mnt , s ) ;
return 0 ;
failed_unlock :
2009-06-07 20:39:33 +04:00
mutex_unlock ( & nilfs - > ns_mount_mutex ) ;
2009-06-07 20:39:29 +04:00
put_nilfs ( nilfs ) ;
2009-04-07 06:01:35 +04:00
failed :
close_bdev_exclusive ( sd . bdev , flags ) ;
return err ;
cancel_new :
/* Abandoning the newly allocated superblock */
2009-06-07 20:39:33 +04:00
mutex_unlock ( & nilfs - > ns_mount_mutex ) ;
2009-06-07 20:39:29 +04:00
put_nilfs ( nilfs ) ;
2009-04-07 06:01:35 +04:00
up_write ( & s - > s_umount ) ;
deactivate_super ( s ) ;
/*
* deactivate_super ( ) invokes close_bdev_exclusive ( ) .
* We must finish all post - cleaning before this call ;
2009-06-07 20:39:33 +04:00
* put_nilfs ( ) needs the block device .
2009-04-07 06:01:35 +04:00
*/
return err ;
}
struct file_system_type nilfs_fs_type = {
. owner = THIS_MODULE ,
. name = " nilfs2 " ,
. get_sb = nilfs_get_sb ,
. kill_sb = kill_block_super ,
. fs_flags = FS_REQUIRES_DEV ,
} ;
static int __init init_nilfs_fs ( void )
{
int err ;
err = nilfs_init_inode_cache ( ) ;
if ( err )
goto failed ;
err = nilfs_init_transaction_cache ( ) ;
if ( err )
goto failed_inode_cache ;
err = nilfs_init_segbuf_cache ( ) ;
if ( err )
goto failed_transaction_cache ;
err = nilfs_btree_path_cache_init ( ) ;
if ( err )
goto failed_segbuf_cache ;
err = register_filesystem ( & nilfs_fs_type ) ;
if ( err )
goto failed_btree_path_cache ;
return 0 ;
failed_btree_path_cache :
nilfs_btree_path_cache_destroy ( ) ;
failed_segbuf_cache :
nilfs_destroy_segbuf_cache ( ) ;
failed_transaction_cache :
nilfs_destroy_transaction_cache ( ) ;
failed_inode_cache :
nilfs_destroy_inode_cache ( ) ;
failed :
return err ;
}
static void __exit exit_nilfs_fs ( void )
{
nilfs_destroy_segbuf_cache ( ) ;
nilfs_destroy_transaction_cache ( ) ;
nilfs_destroy_inode_cache ( ) ;
nilfs_btree_path_cache_destroy ( ) ;
unregister_filesystem ( & nilfs_fs_type ) ;
}
module_init ( init_nilfs_fs )
module_exit ( exit_nilfs_fs )