2007-06-12 09:07:21 -04:00
/*
* Copyright ( C ) 2007 Oracle . All rights reserved .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public
* License v2 as published by the Free Software Foundation .
*
* 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 . , 59 Temple Place - Suite 330 ,
* Boston , MA 021110 - 1307 , USA .
*/
2007-08-29 09:11:44 -04:00
# include <linux/blkdev.h>
2007-03-21 11:12:56 -04:00
# include <linux/module.h>
2007-03-22 12:13:20 -04:00
# include <linux/buffer_head.h>
2007-03-21 11:12:56 -04:00
# include <linux/fs.h>
# include <linux/pagemap.h>
# include <linux/highmem.h>
# include <linux/time.h>
# include <linux/init.h>
# include <linux/string.h>
# include <linux/smp_lock.h>
# include <linux/backing-dev.h>
2007-08-29 09:11:44 -04:00
# include <linux/mount.h>
2007-03-26 16:00:06 -04:00
# include <linux/mpage.h>
2007-03-29 11:56:46 -04:00
# include <linux/swap.h>
# include <linux/writeback.h>
2007-04-19 21:01:03 -04:00
# include <linux/statfs.h>
2007-06-08 15:33:54 -04:00
# include <linux/compat.h>
2007-03-21 11:12:56 -04:00
# include "ctree.h"
2007-03-22 12:13:20 -04:00
# include "disk-io.h"
2007-03-23 10:01:08 -04:00
# include "transaction.h"
2007-04-02 10:50:19 -04:00
# include "btrfs_inode.h"
2007-04-10 09:27:04 -04:00
# include "ioctl.h"
2007-05-24 13:35:57 -04:00
# include "print-tree.h"
2007-03-21 11:12:56 -04:00
2007-06-12 06:35:45 -04:00
# define BTRFS_SUPER_MAGIC 0x9123682E
2007-03-29 15:15:27 -04:00
2007-06-12 06:35:45 -04:00
static struct super_operations btrfs_super_ops ;
2007-03-29 11:56:46 -04:00
2007-06-12 06:35:45 -04:00
static void btrfs_put_super ( struct super_block * sb )
2007-04-17 13:26:50 -04:00
{
2007-06-12 06:35:45 -04:00
struct btrfs_root * root = btrfs_sb ( sb ) ;
2007-08-29 15:47:34 -04:00
struct btrfs_fs_info * fs = root - > fs_info ;
2007-04-17 13:26:50 -04:00
int ret ;
2007-06-12 06:35:45 -04:00
ret = close_ctree ( root ) ;
if ( ret ) {
printk ( " close ctree returns %d \n " , ret ) ;
2007-03-29 11:56:46 -04:00
}
2007-08-29 15:47:34 -04:00
btrfs_sysfs_del_super ( fs ) ;
2007-06-12 06:35:45 -04:00
sb - > s_fs_info = NULL ;
2007-03-29 11:56:46 -04:00
}
2007-06-12 06:35:45 -04:00
static int btrfs_fill_super ( struct super_block * sb , void * data , int silent )
2007-03-29 11:56:46 -04:00
{
2007-06-12 06:35:45 -04:00
struct inode * inode ;
struct dentry * root_dentry ;
struct btrfs_super_block * disk_super ;
struct btrfs_root * tree_root ;
struct btrfs_inode * bi ;
int err ;
2007-04-18 16:15:28 -04:00
2007-06-12 06:35:45 -04:00
sb - > s_maxbytes = MAX_LFS_FILESIZE ;
sb - > s_magic = BTRFS_SUPER_MAGIC ;
sb - > s_op = & btrfs_super_ops ;
sb - > s_time_gran = 1 ;
2007-04-18 16:15:28 -04:00
2007-06-12 06:35:45 -04:00
tree_root = open_ctree ( sb ) ;
2007-04-16 09:22:45 -04:00
2007-06-12 06:35:45 -04:00
if ( ! tree_root | | IS_ERR ( tree_root ) ) {
printk ( " btrfs: open_ctree failed \n " ) ;
return - EIO ;
2007-04-18 16:15:28 -04:00
}
2007-06-12 06:35:45 -04:00
sb - > s_fs_info = tree_root ;
disk_super = tree_root - > fs_info - > disk_super ;
inode = btrfs_iget_locked ( sb , btrfs_super_root_dir ( disk_super ) ,
tree_root ) ;
bi = BTRFS_I ( inode ) ;
bi - > location . objectid = inode - > i_ino ;
bi - > location . offset = 0 ;
bi - > location . flags = 0 ;
bi - > root = tree_root ;
2007-08-27 16:49:44 -04:00
2007-06-12 06:35:45 -04:00
btrfs_set_key_type ( & bi - > location , BTRFS_INODE_ITEM_KEY ) ;
2007-04-18 16:15:28 -04:00
2007-06-12 06:35:45 -04:00
if ( ! inode ) {
2007-04-16 09:22:45 -04:00
err = - ENOMEM ;
2007-06-12 06:35:45 -04:00
goto fail_close ;
2007-03-29 15:15:27 -04:00
}
2007-06-12 06:35:45 -04:00
if ( inode - > i_state & I_NEW ) {
btrfs_read_locked_inode ( inode ) ;
unlock_new_inode ( inode ) ;
2007-03-29 15:15:27 -04:00
}
2007-06-12 06:35:45 -04:00
root_dentry = d_alloc_root ( inode ) ;
if ( ! root_dentry ) {
iput ( inode ) ;
err = - ENOMEM ;
goto fail_close ;
2007-03-29 15:15:27 -04:00
}
2007-08-29 15:47:34 -04:00
/* this does the super kobj at the same time */
err = btrfs_sysfs_add_super ( tree_root - > fs_info ) ;
if ( err )
goto fail_close ;
2007-06-12 06:35:45 -04:00
sb - > s_root = root_dentry ;
btrfs_transaction_queue_work ( tree_root , HZ * 30 ) ;
2007-04-10 16:58:11 -04:00
return 0 ;
2007-06-12 06:35:45 -04:00
fail_close :
close_ctree ( tree_root ) ;
return err ;
2007-04-10 16:58:11 -04:00
}
2007-06-12 06:35:45 -04:00
static int btrfs_sync_fs ( struct super_block * sb , int wait )
2007-04-10 09:27:04 -04:00
{
struct btrfs_trans_handle * trans ;
2007-06-12 06:35:45 -04:00
struct btrfs_root * root ;
2007-04-10 09:27:04 -04:00
int ret ;
2007-06-12 06:35:45 -04:00
root = btrfs_sb ( sb ) ;
2007-04-10 16:58:11 -04:00
2007-06-12 06:35:45 -04:00
sb - > s_dirt = 0 ;
if ( ! wait ) {
filemap_flush ( root - > fs_info - > btree_inode - > i_mapping ) ;
return 0 ;
}
2007-08-10 14:06:19 -04:00
btrfs_clean_old_snapshots ( root ) ;
2007-04-10 09:27:04 -04:00
mutex_lock ( & root - > fs_info - > fs_mutex ) ;
2007-08-10 14:06:19 -04:00
btrfs_defrag_dirty_roots ( root - > fs_info ) ;
2007-04-10 09:27:04 -04:00
trans = btrfs_start_transaction ( root , 1 ) ;
ret = btrfs_commit_transaction ( trans , root ) ;
2007-06-12 06:35:45 -04:00
sb - > s_dirt = 0 ;
2007-04-10 09:27:04 -04:00
mutex_unlock ( & root - > fs_info - > fs_mutex ) ;
2007-06-22 14:16:25 -04:00
return ret ;
2007-04-02 10:50:19 -04:00
}
2007-06-12 06:35:45 -04:00
static void btrfs_write_super ( struct super_block * sb )
2007-04-02 10:50:19 -04:00
{
2007-06-12 06:35:45 -04:00
sb - > s_dirt = 0 ;
2007-04-02 10:50:19 -04:00
}
2007-08-29 09:11:44 -04:00
/*
* This is almost a copy of get_sb_bdev in fs / super . c .
* We need the local copy to allow direct mounting of
* subvolumes , but this could be easily integrated back
* into the generic version . - - hch
*/
/* start copy & paste */
static int set_bdev_super ( struct super_block * s , void * data )
{
s - > s_bdev = data ;
s - > s_dev = s - > s_bdev - > bd_dev ;
return 0 ;
}
static int test_bdev_super ( struct super_block * s , void * data )
{
return ( void * ) s - > s_bdev = = data ;
}
int btrfs_get_sb_bdev ( struct file_system_type * fs_type ,
int flags , const char * dev_name , void * data ,
int ( * fill_super ) ( struct super_block * , void * , int ) ,
struct vfsmount * mnt , const char * subvol )
{
struct block_device * bdev = NULL ;
struct super_block * s ;
struct dentry * root ;
int error = 0 ;
bdev = open_bdev_excl ( dev_name , flags , fs_type ) ;
if ( IS_ERR ( bdev ) )
return PTR_ERR ( bdev ) ;
/*
* once the super is inserted into the list by sget , s_umount
* will protect the lockfs code from trying to start a snapshot
* while we are mounting
*/
down ( & bdev - > bd_mount_sem ) ;
s = sget ( fs_type , test_bdev_super , set_bdev_super , bdev ) ;
up ( & bdev - > bd_mount_sem ) ;
if ( IS_ERR ( s ) )
goto error_s ;
if ( s - > s_root ) {
if ( ( flags ^ s - > s_flags ) & MS_RDONLY ) {
up_write ( & s - > s_umount ) ;
deactivate_super ( s ) ;
error = - EBUSY ;
goto error_bdev ;
}
close_bdev_excl ( bdev ) ;
} else {
char b [ BDEVNAME_SIZE ] ;
s - > s_flags = flags ;
strlcpy ( s - > s_id , bdevname ( bdev , b ) , sizeof ( s - > s_id ) ) ;
sb_set_blocksize ( s , block_size ( bdev ) ) ;
error = fill_super ( s , data , flags & MS_SILENT ? 1 : 0 ) ;
if ( error ) {
up_write ( & s - > s_umount ) ;
deactivate_super ( s ) ;
goto error ;
}
s - > s_flags | = MS_ACTIVE ;
}
if ( subvol ) {
root = lookup_one_len ( subvol , s - > s_root , strlen ( subvol ) ) ;
if ( IS_ERR ( root ) ) {
up_write ( & s - > s_umount ) ;
deactivate_super ( s ) ;
error = PTR_ERR ( root ) ;
goto error ;
}
if ( ! root - > d_inode ) {
dput ( root ) ;
up_write ( & s - > s_umount ) ;
deactivate_super ( s ) ;
error = - ENXIO ;
goto error ;
}
} else {
root = dget ( s - > s_root ) ;
}
mnt - > mnt_sb = s ;
mnt - > mnt_root = root ;
return 0 ;
error_s :
error = PTR_ERR ( s ) ;
error_bdev :
close_bdev_excl ( bdev ) ;
error :
return error ;
}
/* end copy & paste */
2007-03-21 11:12:56 -04:00
static int btrfs_get_sb ( struct file_system_type * fs_type ,
2007-08-29 09:11:44 -04:00
int flags , const char * identifier , void * data , struct vfsmount * mnt )
2007-03-21 11:12:56 -04:00
{
2007-08-29 09:11:44 -04:00
int ret ;
char * _identifier = kstrdup ( identifier , GFP_KERNEL ) ;
char * subvol_name ;
const char * dev_name ;
subvol_name = _identifier ;
dev_name = strsep ( & subvol_name , " : " ) ;
if ( ! dev_name )
return - ENOMEM ;
ret = btrfs_get_sb_bdev ( fs_type , flags , dev_name , data ,
btrfs_fill_super , mnt ,
subvol_name ? subvol_name : " default " ) ;
kfree ( _identifier ) ;
return ret ;
2007-03-21 11:12:56 -04:00
}
2007-04-19 21:01:03 -04:00
static int btrfs_statfs ( struct dentry * dentry , struct kstatfs * buf )
{
struct btrfs_root * root = btrfs_sb ( dentry - > d_sb ) ;
2007-06-26 10:06:50 -04:00
struct btrfs_super_block * disk_super = & root - > fs_info - > super_copy ;
2007-04-19 21:01:03 -04:00
buf - > f_namelen = BTRFS_NAME_LEN ;
buf - > f_blocks = btrfs_super_total_blocks ( disk_super ) ;
buf - > f_bfree = buf - > f_blocks - btrfs_super_blocks_used ( disk_super ) ;
buf - > f_bavail = buf - > f_bfree ;
buf - > f_bsize = dentry - > d_sb - > s_blocksize ;
buf - > f_type = BTRFS_SUPER_MAGIC ;
return 0 ;
}
2007-04-24 11:52:22 -04:00
2007-03-21 11:12:56 -04:00
static struct file_system_type btrfs_fs_type = {
. owner = THIS_MODULE ,
. name = " btrfs " ,
. get_sb = btrfs_get_sb ,
. kill_sb = kill_block_super ,
. fs_flags = FS_REQUIRES_DEV ,
} ;
2007-03-22 12:13:20 -04:00
static struct super_operations btrfs_super_ops = {
2007-03-25 13:44:56 -04:00
. delete_inode = btrfs_delete_inode ,
2007-03-22 12:13:20 -04:00
. put_super = btrfs_put_super ,
. read_inode = btrfs_read_locked_inode ,
2007-03-23 10:01:08 -04:00
. write_super = btrfs_write_super ,
. sync_fs = btrfs_sync_fs ,
2007-03-26 12:00:39 -04:00
. write_inode = btrfs_write_inode ,
2007-04-24 11:52:22 -04:00
. dirty_inode = btrfs_dirty_inode ,
2007-04-02 10:50:19 -04:00
. alloc_inode = btrfs_alloc_inode ,
. destroy_inode = btrfs_destroy_inode ,
2007-04-19 21:01:03 -04:00
. statfs = btrfs_statfs ,
2007-03-22 12:13:20 -04:00
} ;
2007-03-21 11:12:56 -04:00
static int __init init_btrfs_fs ( void )
{
2007-04-02 10:50:19 -04:00
int err ;
2007-08-29 15:47:34 -04:00
err = btrfs_init_sysfs ( ) ;
if ( err )
return err ;
2007-06-08 15:33:54 -04:00
btrfs_init_transaction_sys ( ) ;
2007-06-12 06:35:45 -04:00
err = btrfs_init_cachep ( ) ;
2007-04-02 10:50:19 -04:00
if ( err )
return err ;
2007-08-27 16:49:44 -04:00
extent_map_init ( ) ;
2007-03-21 11:12:56 -04:00
return register_filesystem ( & btrfs_fs_type ) ;
}
static void __exit exit_btrfs_fs ( void )
{
2007-06-08 15:33:54 -04:00
btrfs_exit_transaction_sys ( ) ;
2007-06-12 06:35:45 -04:00
btrfs_destroy_cachep ( ) ;
2007-08-27 16:49:44 -04:00
extent_map_exit ( ) ;
2007-03-21 11:12:56 -04:00
unregister_filesystem ( & btrfs_fs_type ) ;
2007-08-29 15:47:34 -04:00
btrfs_exit_sysfs ( ) ;
2007-03-21 11:12:56 -04:00
}
module_init ( init_btrfs_fs )
module_exit ( exit_btrfs_fs )
MODULE_LICENSE ( " GPL " ) ;