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-08-29 09:11:44 -04:00
# include <linux/parser.h>
2007-12-17 20:14:04 -05:00
# include <linux/ctype.h>
2007-12-18 16:15:09 -05:00
# include <linux/namei.h>
2008-03-24 15:02:04 -04:00
# include <linux/miscdevice.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-11-16 11:45:54 -05:00
# include "xattr.h"
2008-03-24 15:02:07 -04:00
# include "volumes.h"
2007-03-21 11:12:56 -04:00
2007-10-15 16:14:19 -04:00
# define BTRFS_SUPER_MAGIC 0x9123683E
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-08-29 09:11:44 -04:00
enum {
2008-06-10 10:40:46 -04:00
Opt_degraded , Opt_subvol , Opt_device , Opt_nodatasum , Opt_nodatacow ,
2008-05-13 13:46:40 -04:00
Opt_max_extent , Opt_max_inline , Opt_alloc_start , Opt_nobarrier ,
2008-06-11 21:47:56 -04:00
Opt_ssd , Opt_thread_pool , Opt_err ,
2007-08-29 09:11:44 -04:00
} ;
static match_table_t tokens = {
2008-05-13 13:46:40 -04:00
{ Opt_degraded , " degraded " } ,
2007-08-29 09:11:44 -04:00
{ Opt_subvol , " subvol=%s " } ,
2008-06-10 10:40:46 -04:00
{ Opt_device , " device=%s " } ,
2007-12-14 15:30:32 -05:00
{ Opt_nodatasum , " nodatasum " } ,
2007-12-17 20:14:01 -05:00
{ Opt_nodatacow , " nodatacow " } ,
2008-01-09 09:23:21 -05:00
{ Opt_nobarrier , " nobarrier " } ,
2007-12-17 20:14:04 -05:00
{ Opt_max_extent , " max_extent=%s " } ,
2008-01-29 16:03:38 -05:00
{ Opt_max_inline , " max_inline=%s " } ,
2008-01-02 10:01:11 -05:00
{ Opt_alloc_start , " alloc_start=%s " } ,
2008-06-11 21:47:56 -04:00
{ Opt_thread_pool , " thread_pool=%d " } ,
2008-01-18 10:54:22 -05:00
{ Opt_ssd , " ssd " } ,
2007-08-29 09:11:44 -04:00
{ Opt_err , NULL }
} ;
2007-12-21 16:27:24 -05:00
u64 btrfs_parse_size ( char * str )
2007-12-17 20:14:04 -05:00
{
2007-12-21 16:27:24 -05:00
u64 res ;
2007-12-17 20:14:04 -05:00
int mult = 1 ;
char * end ;
char last ;
res = simple_strtoul ( str , & end , 10 ) ;
last = end [ 0 ] ;
if ( isalpha ( last ) ) {
last = tolower ( last ) ;
switch ( last ) {
case ' g ' :
mult * = 1024 ;
case ' m ' :
mult * = 1024 ;
case ' k ' :
mult * = 1024 ;
}
res = res * mult ;
}
return res ;
}
2008-06-10 10:40:29 -04:00
/*
* Regular mount options parser . Everything that is needed only when
* reading in a new superblock is parsed here .
*/
int btrfs_parse_options ( struct btrfs_root * root , char * options )
2007-08-29 09:11:44 -04:00
{
2008-06-10 10:40:29 -04:00
struct btrfs_fs_info * info = root - > fs_info ;
2007-08-29 09:11:44 -04:00
substring_t args [ MAX_OPT_ARGS ] ;
2008-06-10 10:40:29 -04:00
char * p , * num ;
2008-06-11 21:47:56 -04:00
int intarg ;
2007-12-14 15:30:32 -05:00
2007-08-29 09:11:44 -04:00
if ( ! options )
2008-06-10 10:40:29 -04:00
return 0 ;
2007-08-29 09:11:44 -04:00
2007-12-17 20:14:01 -05:00
/*
* strsep changes the string , duplicate it because parse_options
* gets called twice
*/
options = kstrdup ( options , GFP_NOFS ) ;
if ( ! options )
return - ENOMEM ;
2008-06-10 10:40:29 -04:00
while ( ( p = strsep ( & options , " , " ) ) ! = NULL ) {
2007-08-29 09:11:44 -04:00
int token ;
if ( ! * p )
continue ;
token = match_token ( p , tokens , args ) ;
switch ( token ) {
2008-05-13 13:46:40 -04:00
case Opt_degraded :
2008-06-10 10:40:29 -04:00
printk ( KERN_INFO " btrfs: allowing degraded mounts \n " ) ;
btrfs_set_opt ( info - > mount_opt , DEGRADED ) ;
2008-05-13 13:46:40 -04:00
break ;
2007-08-29 09:11:44 -04:00
case Opt_subvol :
2008-06-10 10:40:46 -04:00
case Opt_device :
2008-06-10 10:40:29 -04:00
/*
2008-06-10 10:40:46 -04:00
* These are parsed by btrfs_parse_early_options
2008-06-10 10:40:29 -04:00
* and can be happily ignored here .
*/
2007-12-14 15:30:32 -05:00
break ;
case Opt_nodatasum :
2008-06-10 10:40:29 -04:00
printk ( KERN_INFO " btrfs: setting nodatacsum \n " ) ;
btrfs_set_opt ( info - > mount_opt , NODATASUM ) ;
2007-12-17 20:14:01 -05:00
break ;
case Opt_nodatacow :
2008-06-10 10:40:29 -04:00
printk ( KERN_INFO " btrfs: setting nodatacow \n " ) ;
btrfs_set_opt ( info - > mount_opt , NODATACOW ) ;
btrfs_set_opt ( info - > mount_opt , NODATASUM ) ;
2007-08-29 09:11:44 -04:00
break ;
2008-01-18 10:54:22 -05:00
case Opt_ssd :
2008-06-10 10:40:29 -04:00
printk ( KERN_INFO " btrfs: use ssd allocation scheme \n " ) ;
btrfs_set_opt ( info - > mount_opt , SSD ) ;
2008-01-18 10:54:22 -05:00
break ;
2008-01-09 09:23:21 -05:00
case Opt_nobarrier :
2008-06-10 10:40:29 -04:00
printk ( KERN_INFO " btrfs: turning off barriers \n " ) ;
btrfs_set_opt ( info - > mount_opt , NOBARRIER ) ;
2008-01-09 09:23:21 -05:00
break ;
2008-06-11 21:47:56 -04:00
case Opt_thread_pool :
intarg = 0 ;
match_int ( & args [ 0 ] , & intarg ) ;
if ( intarg ) {
info - > thread_pool_size = intarg ;
printk ( KERN_INFO " btrfs: thread pool %d \n " ,
info - > thread_pool_size ) ;
}
break ;
2007-12-17 20:14:04 -05:00
case Opt_max_extent :
2008-06-10 10:40:29 -04:00
num = match_strdup ( & args [ 0 ] ) ;
if ( num ) {
info - > max_extent = btrfs_parse_size ( num ) ;
kfree ( num ) ;
info - > max_extent = max_t ( u64 ,
info - > max_extent , root - > sectorsize ) ;
printk ( KERN_INFO " btrfs: max_extent at %llu \n " ,
info - > max_extent ) ;
2007-12-17 20:14:04 -05:00
}
break ;
2008-01-29 16:03:38 -05:00
case Opt_max_inline :
2008-06-10 10:40:29 -04:00
num = match_strdup ( & args [ 0 ] ) ;
if ( num ) {
info - > max_inline = btrfs_parse_size ( num ) ;
kfree ( num ) ;
2008-06-11 16:51:38 -04:00
if ( info - > max_inline ) {
info - > max_inline = max_t ( u64 ,
info - > max_inline ,
root - > sectorsize ) ;
}
2008-06-10 10:40:29 -04:00
printk ( KERN_INFO " btrfs: max_inline at %llu \n " ,
info - > max_inline ) ;
2008-01-29 16:03:38 -05:00
}
break ;
2008-01-02 10:01:11 -05:00
case Opt_alloc_start :
2008-06-10 10:40:29 -04:00
num = match_strdup ( & args [ 0 ] ) ;
if ( num ) {
info - > alloc_start = btrfs_parse_size ( num ) ;
kfree ( num ) ;
printk ( KERN_INFO
" btrfs: allocations start at %llu \n " ,
info - > alloc_start ) ;
2008-01-02 10:01:11 -05:00
}
break ;
2007-08-29 09:11:44 -04:00
default :
2007-12-17 20:14:01 -05:00
break ;
2007-08-29 09:11:44 -04:00
}
}
2007-12-17 20:14:01 -05:00
kfree ( options ) ;
2008-06-10 10:40:29 -04:00
return 0 ;
}
/*
* Parse mount options that are required early in the mount process .
*
* All other options will be parsed on much later in the mount process and
* only when we need to allocate a new super block .
*/
2008-06-10 10:40:46 -04:00
static int btrfs_parse_early_options ( const char * options , int flags ,
void * holder , char * * subvol_name ,
struct btrfs_fs_devices * * fs_devices )
2008-06-10 10:40:29 -04:00
{
substring_t args [ MAX_OPT_ARGS ] ;
char * opts , * p ;
int error = 0 ;
if ( ! options )
goto out ;
/*
* strsep changes the string , duplicate it because parse_options
* gets called twice
*/
opts = kstrdup ( options , GFP_KERNEL ) ;
if ( ! opts )
return - ENOMEM ;
while ( ( p = strsep ( & opts , " , " ) ) ! = NULL ) {
int token ;
if ( ! * p )
continue ;
token = match_token ( p , tokens , args ) ;
switch ( token ) {
case Opt_subvol :
* subvol_name = match_strdup ( & args [ 0 ] ) ;
break ;
2008-06-10 10:40:46 -04:00
case Opt_device :
error = btrfs_scan_one_device ( match_strdup ( & args [ 0 ] ) ,
flags , holder , fs_devices ) ;
if ( error )
goto out_free_opts ;
break ;
2008-06-10 10:40:29 -04:00
default :
break ;
}
}
2008-06-10 10:40:46 -04:00
out_free_opts :
2008-06-10 10:40:29 -04:00
kfree ( opts ) ;
out :
/*
* If no subvolume name is specified we use the default one . Allocate
* a copy of the string " default " here so that code later in the
* mount path doesn ' t care if it ' s the default volume or another one .
*/
if ( ! * subvol_name ) {
* subvol_name = kstrdup ( " default " , GFP_KERNEL ) ;
if ( ! * subvol_name )
return - ENOMEM ;
}
return error ;
2007-08-29 09:11:44 -04:00
}
2008-03-24 15:02:07 -04:00
static int btrfs_fill_super ( struct super_block * sb ,
struct btrfs_fs_devices * fs_devices ,
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 ;
2007-11-16 11:45:54 -05:00
sb - > s_xattr = btrfs_xattr_handlers ;
2007-06-12 06:35:45 -04:00
sb - > s_time_gran = 1 ;
2007-04-18 16:15:28 -04:00
2008-05-13 13:46:40 -04:00
tree_root = open_ctree ( sb , fs_devices , ( char * ) data ) ;
2007-04-16 09:22:45 -04:00
2008-04-01 11:21:34 -04:00
if ( IS_ERR ( tree_root ) ) {
2007-06-12 06:35:45 -04:00
printk ( " btrfs: open_ctree failed \n " ) ;
2008-04-01 11:21:34 -04:00
return PTR_ERR ( tree_root ) ;
2007-04-18 16:15:28 -04:00
}
2007-06-12 06:35:45 -04:00
sb - > s_fs_info = tree_root ;
2007-10-15 16:14:19 -04:00
disk_super = & tree_root - > fs_info - > super_copy ;
2007-06-12 06:35:45 -04:00
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 - > 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 ;
2008-02-20 16:11:05 -05:00
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
save_mount_options ( sb , data ) ;
# endif
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
}
2008-06-10 10:07:39 -04:00
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
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-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
}
2008-05-07 11:43:44 -04:00
static int btrfs_test_super ( struct super_block * s , void * data )
2007-08-29 09:11:44 -04:00
{
2008-05-07 11:43:44 -04:00
struct btrfs_fs_devices * test_fs_devices = data ;
struct btrfs_root * root = btrfs_sb ( s ) ;
2007-08-29 09:11:44 -04:00
2008-05-07 11:43:44 -04:00
return root - > fs_info - > fs_devices = = test_fs_devices ;
2007-08-29 09:11:44 -04:00
}
2008-06-10 10:40:29 -04:00
/*
* Find a superblock for the given device / mount point .
*
* Note : This is based on get_sb_bdev from fs / super . c with a few additions
* for multiple device setup . Make sure to keep it in sync .
*/
static int btrfs_get_sb ( struct file_system_type * fs_type , int flags ,
const char * dev_name , void * data , struct vfsmount * mnt )
2007-08-29 09:11:44 -04:00
{
2008-06-10 10:40:29 -04:00
char * subvol_name = NULL ;
2007-08-29 09:11:44 -04:00
struct block_device * bdev = NULL ;
struct super_block * s ;
struct dentry * root ;
2008-03-24 15:02:07 -04:00
struct btrfs_fs_devices * fs_devices = NULL ;
2007-08-29 09:11:44 -04:00
int error = 0 ;
2008-06-10 10:40:46 -04:00
error = btrfs_parse_early_options ( data , flags , fs_type ,
& subvol_name , & fs_devices ) ;
2008-06-10 10:40:29 -04:00
if ( error )
goto error ;
2008-03-24 15:02:07 -04:00
error = btrfs_scan_one_device ( dev_name , flags , fs_type , & fs_devices ) ;
if ( error )
2008-06-10 10:40:29 -04:00
goto error_free_subvol_name ;
2007-08-29 09:11:44 -04:00
2008-03-24 15:02:07 -04:00
error = btrfs_open_devices ( fs_devices , flags , fs_type ) ;
if ( error )
2008-06-10 10:40:29 -04:00
goto error_free_subvol_name ;
2008-03-24 15:02:07 -04:00
2008-05-13 13:46:40 -04:00
bdev = fs_devices - > latest_bdev ;
2008-05-07 11:43:44 -04:00
s = sget ( fs_type , btrfs_test_super , set_anon_super , fs_devices ) ;
2007-08-29 09:11:44 -04:00
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 ;
}
} else {
char b [ BDEVNAME_SIZE ] ;
s - > s_flags = flags ;
strlcpy ( s - > s_id , bdevname ( bdev , b ) , sizeof ( s - > s_id ) ) ;
2008-03-24 15:02:07 -04:00
error = btrfs_fill_super ( s , fs_devices , data ,
flags & MS_SILENT ? 1 : 0 ) ;
2007-08-29 09:11:44 -04:00
if ( error ) {
up_write ( & s - > s_umount ) ;
deactivate_super ( s ) ;
goto error ;
}
2008-04-28 15:29:42 -04:00
btrfs_sb ( s ) - > fs_info - > bdev_holder = fs_type ;
2007-08-29 09:11:44 -04:00
s - > s_flags | = MS_ACTIVE ;
}
2008-06-10 10:40:29 -04:00
root = lookup_one_len ( subvol_name , s - > s_root , strlen ( subvol_name ) ) ;
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 ;
2007-08-29 09:11:44 -04:00
}
mnt - > mnt_sb = s ;
mnt - > mnt_root = root ;
2008-06-10 10:40:29 -04:00
kfree ( subvol_name ) ;
2007-08-29 09:11:44 -04:00
return 0 ;
error_s :
error = PTR_ERR ( s ) ;
error_bdev :
2008-03-24 15:02:07 -04:00
btrfs_close_devices ( fs_devices ) ;
2008-06-10 10:40:29 -04:00
error_free_subvol_name :
kfree ( subvol_name ) ;
2007-08-29 09:11:44 -04:00
error :
return error ;
}
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-10-15 16:15:53 -04:00
int bits = dentry - > d_sb - > s_blocksize_bits ;
2007-04-19 21:01:03 -04:00
buf - > f_namelen = BTRFS_NAME_LEN ;
2007-10-15 16:15:53 -04:00
buf - > f_blocks = btrfs_super_total_bytes ( disk_super ) > > bits ;
buf - > f_bfree = buf - > f_blocks -
( btrfs_super_bytes_used ( disk_super ) > > bits ) ;
2007-04-19 21:01:03 -04:00
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 ,
2008-05-07 11:43:44 -04:00
. kill_sb = kill_anon_super ,
2007-03-21 11:12:56 -04:00
. fs_flags = FS_REQUIRES_DEV ,
} ;
2008-03-24 15:02:04 -04:00
2008-03-24 15:02:07 -04:00
static long btrfs_control_ioctl ( struct file * file , unsigned int cmd ,
unsigned long arg )
{
struct btrfs_ioctl_vol_args * vol ;
struct btrfs_fs_devices * fs_devices ;
2008-06-09 22:17:11 -04:00
int ret = 0 ;
2008-03-24 15:02:07 -04:00
int len ;
vol = kmalloc ( sizeof ( * vol ) , GFP_KERNEL ) ;
if ( copy_from_user ( vol , ( void __user * ) arg , sizeof ( * vol ) ) ) {
ret = - EFAULT ;
goto out ;
}
len = strnlen ( vol - > name , BTRFS_PATH_NAME_MAX ) ;
switch ( cmd ) {
case BTRFS_IOC_SCAN_DEV :
ret = btrfs_scan_one_device ( vol - > name , MS_RDONLY ,
& btrfs_fs_type , & fs_devices ) ;
break ;
}
out :
kfree ( vol ) ;
2008-06-09 22:17:11 -04:00
return ret ;
2008-03-24 15:02:07 -04:00
}
2008-01-22 12:46:56 -05:00
static void btrfs_write_super_lockfs ( struct super_block * sb )
{
struct btrfs_root * root = btrfs_sb ( sb ) ;
2008-06-25 16:01:31 -04:00
mutex_lock ( & root - > fs_info - > transaction_kthread_mutex ) ;
mutex_lock ( & root - > fs_info - > cleaner_mutex ) ;
2008-01-22 12:46:56 -05:00
}
static void btrfs_unlockfs ( struct super_block * sb )
{
struct btrfs_root * root = btrfs_sb ( sb ) ;
2008-06-25 16:01:31 -04:00
mutex_unlock ( & root - > fs_info - > cleaner_mutex ) ;
mutex_unlock ( & root - > fs_info - > transaction_kthread_mutex ) ;
2008-01-22 12:46:56 -05:00
}
2007-03-21 11:12:56 -04:00
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 ,
2007-03-23 10:01:08 -04:00
. write_super = btrfs_write_super ,
. sync_fs = btrfs_sync_fs ,
2008-02-20 16:11:05 -05:00
# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
. read_inode = btrfs_read_locked_inode ,
# else
. show_options = generic_show_options ,
# endif
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 ,
2008-01-22 12:46:56 -05:00
. write_super_lockfs = btrfs_write_super_lockfs ,
. unlockfs = btrfs_unlockfs ,
2007-03-22 12:13:20 -04:00
} ;
2008-03-24 15:02:04 -04:00
static const struct file_operations btrfs_ctl_fops = {
. unlocked_ioctl = btrfs_control_ioctl ,
. compat_ioctl = btrfs_control_ioctl ,
. owner = THIS_MODULE ,
} ;
static struct miscdevice btrfs_misc = {
. minor = MISC_DYNAMIC_MINOR ,
. name = " btrfs-control " ,
. fops = & btrfs_ctl_fops
} ;
static int btrfs_interface_init ( void )
{
return misc_register ( & btrfs_misc ) ;
}
void btrfs_interface_exit ( void )
{
if ( misc_deregister ( & btrfs_misc ) < 0 )
printk ( " misc_deregister failed for control device " ) ;
}
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-12 06:35:45 -04:00
err = btrfs_init_cachep ( ) ;
2007-04-02 10:50:19 -04:00
if ( err )
2008-06-25 16:01:31 -04:00
goto free_sysfs ;
2008-01-24 16:13:08 -05:00
err = extent_io_init ( ) ;
2007-11-19 10:22:33 -05:00
if ( err )
goto free_cachep ;
2008-01-24 16:13:08 -05:00
err = extent_map_init ( ) ;
if ( err )
goto free_extent_io ;
2008-03-24 15:02:04 -04:00
err = btrfs_interface_init ( ) ;
2007-11-19 10:22:33 -05:00
if ( err )
goto free_extent_map ;
2008-03-24 15:02:04 -04:00
err = register_filesystem ( & btrfs_fs_type ) ;
if ( err )
goto unregister_ioctl ;
2007-11-19 10:22:33 -05:00
return 0 ;
2008-03-24 15:02:04 -04:00
unregister_ioctl :
btrfs_interface_exit ( ) ;
2007-11-19 10:22:33 -05:00
free_extent_map :
extent_map_exit ( ) ;
2008-01-24 16:13:08 -05:00
free_extent_io :
extent_io_exit ( ) ;
2007-11-19 10:22:33 -05:00
free_cachep :
btrfs_destroy_cachep ( ) ;
2008-06-25 16:01:31 -04:00
free_sysfs :
2007-11-19 10:22:33 -05:00
btrfs_exit_sysfs ( ) ;
return err ;
2007-03-21 11:12:56 -04:00
}
static void __exit exit_btrfs_fs ( void )
{
2007-06-12 06:35:45 -04:00
btrfs_destroy_cachep ( ) ;
2007-08-27 16:49:44 -04:00
extent_map_exit ( ) ;
2008-01-24 16:13:08 -05:00
extent_io_exit ( ) ;
2008-03-24 15:02:04 -04:00
btrfs_interface_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 ( ) ;
2008-03-24 15:02:07 -04:00
btrfs_cleanup_fs_uuids ( ) ;
2007-03-21 11:12:56 -04:00
}
module_init ( init_btrfs_fs )
module_exit ( exit_btrfs_fs )
MODULE_LICENSE ( " GPL " ) ;