16cbd5570SChris Mason /* 26cbd5570SChris Mason * Copyright (C) 2007 Oracle. All rights reserved. 36cbd5570SChris Mason * 46cbd5570SChris Mason * This program is free software; you can redistribute it and/or 56cbd5570SChris Mason * modify it under the terms of the GNU General Public 66cbd5570SChris Mason * License v2 as published by the Free Software Foundation. 76cbd5570SChris Mason * 86cbd5570SChris Mason * This program is distributed in the hope that it will be useful, 96cbd5570SChris Mason * but WITHOUT ANY WARRANTY; without even the implied warranty of 106cbd5570SChris Mason * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 116cbd5570SChris Mason * General Public License for more details. 126cbd5570SChris Mason * 136cbd5570SChris Mason * You should have received a copy of the GNU General Public 146cbd5570SChris Mason * License along with this program; if not, write to the 156cbd5570SChris Mason * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 166cbd5570SChris Mason * Boston, MA 021110-1307, USA. 176cbd5570SChris Mason */ 186cbd5570SChris Mason 194b82d6e4SYan #include <linux/blkdev.h> 202e635a27SChris Mason #include <linux/module.h> 21e20d96d6SChris Mason #include <linux/buffer_head.h> 222e635a27SChris Mason #include <linux/fs.h> 232e635a27SChris Mason #include <linux/pagemap.h> 242e635a27SChris Mason #include <linux/highmem.h> 252e635a27SChris Mason #include <linux/time.h> 262e635a27SChris Mason #include <linux/init.h> 272e635a27SChris Mason #include <linux/string.h> 282e635a27SChris Mason #include <linux/smp_lock.h> 292e635a27SChris Mason #include <linux/backing-dev.h> 304b82d6e4SYan #include <linux/mount.h> 31dee26a9fSChris Mason #include <linux/mpage.h> 3275dfe396SChris Mason #include <linux/swap.h> 3375dfe396SChris Mason #include <linux/writeback.h> 348fd17795SChris Mason #include <linux/statfs.h> 3508607c1bSChris Mason #include <linux/compat.h> 3695e05289SChris Mason #include <linux/parser.h> 37c59f8951SChris Mason #include <linux/ctype.h> 38*6da6abaeSChris Mason #include <linux/namei.h> 392e635a27SChris Mason #include "ctree.h" 40e20d96d6SChris Mason #include "disk-io.h" 41d5719762SChris Mason #include "transaction.h" 422c90e5d6SChris Mason #include "btrfs_inode.h" 43c5739bbaSChris Mason #include "ioctl.h" 443a686375SChris Mason #include "print-tree.h" 455103e947SJosef Bacik #include "xattr.h" 462e635a27SChris Mason 475f39d397SChris Mason #define BTRFS_SUPER_MAGIC 0x9123683E 48e20d96d6SChris Mason 49e20d96d6SChris Mason static struct super_operations btrfs_super_ops; 50e20d96d6SChris Mason 51e20d96d6SChris Mason static void btrfs_put_super (struct super_block * sb) 52e20d96d6SChris Mason { 53e20d96d6SChris Mason struct btrfs_root *root = btrfs_sb(sb); 5458176a96SJosef Bacik struct btrfs_fs_info *fs = root->fs_info; 55e20d96d6SChris Mason int ret; 56e20d96d6SChris Mason 57e20d96d6SChris Mason ret = close_ctree(root); 58e20d96d6SChris Mason if (ret) { 59e20d96d6SChris Mason printk("close ctree returns %d\n", ret); 60e20d96d6SChris Mason } 6158176a96SJosef Bacik btrfs_sysfs_del_super(fs); 62e20d96d6SChris Mason sb->s_fs_info = NULL; 63e20d96d6SChris Mason } 642e635a27SChris Mason 6595e05289SChris Mason enum { 66c59f8951SChris Mason Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_max_extent, Opt_err, 6795e05289SChris Mason }; 6895e05289SChris Mason 6995e05289SChris Mason static match_table_t tokens = { 7095e05289SChris Mason {Opt_subvol, "subvol=%s"}, 71b6cda9bcSChris Mason {Opt_nodatasum, "nodatasum"}, 72be20aa9dSChris Mason {Opt_nodatacow, "nodatacow"}, 73c59f8951SChris Mason {Opt_max_extent, "max_extent=%s"}, 7495e05289SChris Mason {Opt_err, NULL} 7595e05289SChris Mason }; 7695e05289SChris Mason 77c59f8951SChris Mason static unsigned long parse_size(char *str) 78c59f8951SChris Mason { 79c59f8951SChris Mason unsigned long res; 80c59f8951SChris Mason int mult = 1; 81c59f8951SChris Mason char *end; 82c59f8951SChris Mason char last; 83c59f8951SChris Mason 84c59f8951SChris Mason res = simple_strtoul(str, &end, 10); 85c59f8951SChris Mason 86c59f8951SChris Mason last = end[0]; 87c59f8951SChris Mason if (isalpha(last)) { 88c59f8951SChris Mason last = tolower(last); 89c59f8951SChris Mason switch (last) { 90c59f8951SChris Mason case 'g': 91c59f8951SChris Mason mult *= 1024; 92c59f8951SChris Mason case 'm': 93c59f8951SChris Mason mult *= 1024; 94c59f8951SChris Mason case 'k': 95c59f8951SChris Mason mult *= 1024; 96c59f8951SChris Mason } 97c59f8951SChris Mason res = res * mult; 98c59f8951SChris Mason } 99c59f8951SChris Mason return res; 100c59f8951SChris Mason } 101c59f8951SChris Mason 10295e05289SChris Mason static int parse_options (char * options, 10395e05289SChris Mason struct btrfs_root *root, 10495e05289SChris Mason char **subvol_name) 10595e05289SChris Mason { 10695e05289SChris Mason char * p; 107b6cda9bcSChris Mason struct btrfs_fs_info *info = NULL; 10895e05289SChris Mason substring_t args[MAX_OPT_ARGS]; 109b6cda9bcSChris Mason 11095e05289SChris Mason if (!options) 11195e05289SChris Mason return 1; 11295e05289SChris Mason 113be20aa9dSChris Mason /* 114be20aa9dSChris Mason * strsep changes the string, duplicate it because parse_options 115be20aa9dSChris Mason * gets called twice 116be20aa9dSChris Mason */ 117be20aa9dSChris Mason options = kstrdup(options, GFP_NOFS); 118be20aa9dSChris Mason if (!options) 119be20aa9dSChris Mason return -ENOMEM; 120be20aa9dSChris Mason 121be20aa9dSChris Mason if (root) 122be20aa9dSChris Mason info = root->fs_info; 123be20aa9dSChris Mason 12495e05289SChris Mason while ((p = strsep (&options, ",")) != NULL) { 12595e05289SChris Mason int token; 12695e05289SChris Mason if (!*p) 12795e05289SChris Mason continue; 12895e05289SChris Mason 12995e05289SChris Mason token = match_token(p, tokens, args); 13095e05289SChris Mason switch (token) { 13195e05289SChris Mason case Opt_subvol: 132be20aa9dSChris Mason if (subvol_name) { 13395e05289SChris Mason *subvol_name = match_strdup(&args[0]); 134be20aa9dSChris Mason } 13595e05289SChris Mason break; 136b6cda9bcSChris Mason case Opt_nodatasum: 137be20aa9dSChris Mason if (info) { 138be20aa9dSChris Mason printk("btrfs: setting nodatacsum\n"); 139b6cda9bcSChris Mason btrfs_set_opt(info->mount_opt, NODATASUM); 140be20aa9dSChris Mason } 141be20aa9dSChris Mason break; 142be20aa9dSChris Mason case Opt_nodatacow: 143be20aa9dSChris Mason if (info) { 144be20aa9dSChris Mason printk("btrfs: setting nodatacow\n"); 145be20aa9dSChris Mason btrfs_set_opt(info->mount_opt, NODATACOW); 146be20aa9dSChris Mason btrfs_set_opt(info->mount_opt, NODATASUM); 147be20aa9dSChris Mason } 148b6cda9bcSChris Mason break; 149c59f8951SChris Mason case Opt_max_extent: 150c59f8951SChris Mason if (info) { 151c59f8951SChris Mason char *num = match_strdup(&args[0]); 152c59f8951SChris Mason if (num) { 153c59f8951SChris Mason info->max_extent = parse_size(num); 154c59f8951SChris Mason kfree(num); 155c59f8951SChris Mason 156c59f8951SChris Mason info->max_extent = max_t(u64, 157c59f8951SChris Mason info->max_extent, 158c59f8951SChris Mason root->sectorsize); 159c59f8951SChris Mason printk("btrfs: max_extent at %Lu\n", 160c59f8951SChris Mason info->max_extent); 161c59f8951SChris Mason } 162c59f8951SChris Mason } 163c59f8951SChris Mason break; 16495e05289SChris Mason default: 165be20aa9dSChris Mason break; 16695e05289SChris Mason } 16795e05289SChris Mason } 168be20aa9dSChris Mason kfree(options); 16995e05289SChris Mason return 1; 17095e05289SChris Mason } 17195e05289SChris Mason 1722e635a27SChris Mason static int btrfs_fill_super(struct super_block * sb, void * data, int silent) 1732e635a27SChris Mason { 1742e635a27SChris Mason struct inode * inode; 175e20d96d6SChris Mason struct dentry * root_dentry; 176e20d96d6SChris Mason struct btrfs_super_block *disk_super; 1770f7d52f4SChris Mason struct btrfs_root *tree_root; 178d6e4a428SChris Mason struct btrfs_inode *bi; 17939279cc3SChris Mason int err; 1802e635a27SChris Mason 1812e635a27SChris Mason sb->s_maxbytes = MAX_LFS_FILESIZE; 1822e635a27SChris Mason sb->s_magic = BTRFS_SUPER_MAGIC; 183e20d96d6SChris Mason sb->s_op = &btrfs_super_ops; 1845103e947SJosef Bacik sb->s_xattr = btrfs_xattr_handlers; 1852e635a27SChris Mason sb->s_time_gran = 1; 186e20d96d6SChris Mason 1870f7d52f4SChris Mason tree_root = open_ctree(sb); 188d98237b3SChris Mason 18939279cc3SChris Mason if (!tree_root || IS_ERR(tree_root)) { 190e20d96d6SChris Mason printk("btrfs: open_ctree failed\n"); 191e20d96d6SChris Mason return -EIO; 192e20d96d6SChris Mason } 1930f7d52f4SChris Mason sb->s_fs_info = tree_root; 1945f39d397SChris Mason disk_super = &tree_root->fs_info->super_copy; 195c5739bbaSChris Mason inode = btrfs_iget_locked(sb, btrfs_super_root_dir(disk_super), 196c5739bbaSChris Mason tree_root); 197d6e4a428SChris Mason bi = BTRFS_I(inode); 198d6e4a428SChris Mason bi->location.objectid = inode->i_ino; 199d6e4a428SChris Mason bi->location.offset = 0; 2000f7d52f4SChris Mason bi->root = tree_root; 201b888db2bSChris Mason 202d6e4a428SChris Mason btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY); 203d6e4a428SChris Mason 20439279cc3SChris Mason if (!inode) { 20539279cc3SChris Mason err = -ENOMEM; 20639279cc3SChris Mason goto fail_close; 20739279cc3SChris Mason } 208e20d96d6SChris Mason if (inode->i_state & I_NEW) { 209e20d96d6SChris Mason btrfs_read_locked_inode(inode); 210e20d96d6SChris Mason unlock_new_inode(inode); 211e20d96d6SChris Mason } 2122e635a27SChris Mason 213e20d96d6SChris Mason root_dentry = d_alloc_root(inode); 214e20d96d6SChris Mason if (!root_dentry) { 2152e635a27SChris Mason iput(inode); 21639279cc3SChris Mason err = -ENOMEM; 21739279cc3SChris Mason goto fail_close; 2182e635a27SChris Mason } 21958176a96SJosef Bacik 220b6cda9bcSChris Mason parse_options((char *)data, tree_root, NULL); 221b6cda9bcSChris Mason 22258176a96SJosef Bacik /* this does the super kobj at the same time */ 22358176a96SJosef Bacik err = btrfs_sysfs_add_super(tree_root->fs_info); 22458176a96SJosef Bacik if (err) 22558176a96SJosef Bacik goto fail_close; 22658176a96SJosef Bacik 227e20d96d6SChris Mason sb->s_root = root_dentry; 22808607c1bSChris Mason btrfs_transaction_queue_work(tree_root, HZ * 30); 2292e635a27SChris Mason return 0; 2302e635a27SChris Mason 23139279cc3SChris Mason fail_close: 23239279cc3SChris Mason close_ctree(tree_root); 233d5719762SChris Mason return err; 234d5719762SChris Mason } 235d5719762SChris Mason 236d5719762SChris Mason static int btrfs_sync_fs(struct super_block *sb, int wait) 237d5719762SChris Mason { 238d5719762SChris Mason struct btrfs_trans_handle *trans; 239d5719762SChris Mason struct btrfs_root *root; 240d5719762SChris Mason int ret; 241d98237b3SChris Mason root = btrfs_sb(sb); 242df2ce34cSChris Mason 243d5719762SChris Mason sb->s_dirt = 0; 244d561c025SChris Mason if (!wait) { 2457cfcc17eSChris Mason filemap_flush(root->fs_info->btree_inode->i_mapping); 246df2ce34cSChris Mason return 0; 247d561c025SChris Mason } 248e9d0b13bSChris Mason btrfs_clean_old_snapshots(root); 249d561c025SChris Mason mutex_lock(&root->fs_info->fs_mutex); 250e9d0b13bSChris Mason btrfs_defrag_dirty_roots(root->fs_info); 251d5719762SChris Mason trans = btrfs_start_transaction(root, 1); 252d5719762SChris Mason ret = btrfs_commit_transaction(trans, root); 253d5719762SChris Mason sb->s_dirt = 0; 254d561c025SChris Mason mutex_unlock(&root->fs_info->fs_mutex); 25554aa1f4dSChris Mason return ret; 256d5719762SChris Mason } 257d5719762SChris Mason 258d561c025SChris Mason static void btrfs_write_super(struct super_block *sb) 259d561c025SChris Mason { 26008607c1bSChris Mason sb->s_dirt = 0; 261d561c025SChris Mason } 262d561c025SChris Mason 2634b82d6e4SYan /* 2644b82d6e4SYan * This is almost a copy of get_sb_bdev in fs/super.c. 2654b82d6e4SYan * We need the local copy to allow direct mounting of 2664b82d6e4SYan * subvolumes, but this could be easily integrated back 2674b82d6e4SYan * into the generic version. --hch 2684b82d6e4SYan */ 2694b82d6e4SYan 2704b82d6e4SYan /* start copy & paste */ 2714b82d6e4SYan static int set_bdev_super(struct super_block *s, void *data) 2722e635a27SChris Mason { 2734b82d6e4SYan s->s_bdev = data; 2744b82d6e4SYan s->s_dev = s->s_bdev->bd_dev; 2754b82d6e4SYan return 0; 2764b82d6e4SYan } 2774b82d6e4SYan 2784b82d6e4SYan static int test_bdev_super(struct super_block *s, void *data) 2794b82d6e4SYan { 2804b82d6e4SYan return (void *)s->s_bdev == data; 2814b82d6e4SYan } 2824b82d6e4SYan 2834b82d6e4SYan int btrfs_get_sb_bdev(struct file_system_type *fs_type, 2844b82d6e4SYan int flags, const char *dev_name, void *data, 2854b82d6e4SYan int (*fill_super)(struct super_block *, void *, int), 2864b82d6e4SYan struct vfsmount *mnt, const char *subvol) 2874b82d6e4SYan { 2884b82d6e4SYan struct block_device *bdev = NULL; 2894b82d6e4SYan struct super_block *s; 2904b82d6e4SYan struct dentry *root; 2914b82d6e4SYan int error = 0; 2924b82d6e4SYan 2934b82d6e4SYan bdev = open_bdev_excl(dev_name, flags, fs_type); 2944b82d6e4SYan if (IS_ERR(bdev)) 2954b82d6e4SYan return PTR_ERR(bdev); 2964b82d6e4SYan 2974b82d6e4SYan /* 2984b82d6e4SYan * once the super is inserted into the list by sget, s_umount 2994b82d6e4SYan * will protect the lockfs code from trying to start a snapshot 3004b82d6e4SYan * while we are mounting 3014b82d6e4SYan */ 3024b82d6e4SYan down(&bdev->bd_mount_sem); 3034b82d6e4SYan s = sget(fs_type, test_bdev_super, set_bdev_super, bdev); 3044b82d6e4SYan up(&bdev->bd_mount_sem); 3054b82d6e4SYan if (IS_ERR(s)) 3064b82d6e4SYan goto error_s; 3074b82d6e4SYan 3084b82d6e4SYan if (s->s_root) { 3094b82d6e4SYan if ((flags ^ s->s_flags) & MS_RDONLY) { 3104b82d6e4SYan up_write(&s->s_umount); 3114b82d6e4SYan deactivate_super(s); 3124b82d6e4SYan error = -EBUSY; 3134b82d6e4SYan goto error_bdev; 3144b82d6e4SYan } 3154b82d6e4SYan 3164b82d6e4SYan close_bdev_excl(bdev); 3174b82d6e4SYan } else { 3184b82d6e4SYan char b[BDEVNAME_SIZE]; 3194b82d6e4SYan 3204b82d6e4SYan s->s_flags = flags; 3214b82d6e4SYan strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); 3224b82d6e4SYan sb_set_blocksize(s, block_size(bdev)); 3234b82d6e4SYan error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); 3244b82d6e4SYan if (error) { 3254b82d6e4SYan up_write(&s->s_umount); 3264b82d6e4SYan deactivate_super(s); 3274b82d6e4SYan goto error; 3284b82d6e4SYan } 3294b82d6e4SYan 3304b82d6e4SYan s->s_flags |= MS_ACTIVE; 3314b82d6e4SYan } 3324b82d6e4SYan 3334b82d6e4SYan if (subvol) { 3344b82d6e4SYan root = lookup_one_len(subvol, s->s_root, strlen(subvol)); 3354b82d6e4SYan if (IS_ERR(root)) { 3364b82d6e4SYan up_write(&s->s_umount); 3374b82d6e4SYan deactivate_super(s); 3384b82d6e4SYan error = PTR_ERR(root); 3394b82d6e4SYan goto error; 3404b82d6e4SYan } 3414b82d6e4SYan if (!root->d_inode) { 3424b82d6e4SYan dput(root); 3434b82d6e4SYan up_write(&s->s_umount); 3444b82d6e4SYan deactivate_super(s); 3454b82d6e4SYan error = -ENXIO; 3464b82d6e4SYan goto error; 3474b82d6e4SYan } 3484b82d6e4SYan } else { 3494b82d6e4SYan root = dget(s->s_root); 3504b82d6e4SYan } 3514b82d6e4SYan 3524b82d6e4SYan mnt->mnt_sb = s; 3534b82d6e4SYan mnt->mnt_root = root; 3544b82d6e4SYan return 0; 3554b82d6e4SYan 3564b82d6e4SYan error_s: 3574b82d6e4SYan error = PTR_ERR(s); 3584b82d6e4SYan error_bdev: 3594b82d6e4SYan close_bdev_excl(bdev); 3604b82d6e4SYan error: 3614b82d6e4SYan return error; 3624b82d6e4SYan } 3634b82d6e4SYan /* end copy & paste */ 3644b82d6e4SYan 3654b82d6e4SYan static int btrfs_get_sb(struct file_system_type *fs_type, 36695e05289SChris Mason int flags, const char *dev_name, void *data, struct vfsmount *mnt) 3674b82d6e4SYan { 3684b82d6e4SYan int ret; 36995e05289SChris Mason char *subvol_name = NULL; 3704b82d6e4SYan 37195e05289SChris Mason parse_options((char *)data, NULL, &subvol_name); 3724b82d6e4SYan ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, 3734b82d6e4SYan btrfs_fill_super, mnt, 3744b82d6e4SYan subvol_name ? subvol_name : "default"); 375c59f8951SChris Mason if (subvol_name) 376c59f8951SChris Mason kfree(subvol_name); 3774b82d6e4SYan return ret; 3782e635a27SChris Mason } 3792e635a27SChris Mason 3808fd17795SChris Mason static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) 3818fd17795SChris Mason { 3828fd17795SChris Mason struct btrfs_root *root = btrfs_sb(dentry->d_sb); 3834b52dff6SChris Mason struct btrfs_super_block *disk_super = &root->fs_info->super_copy; 384db94535dSChris Mason int bits = dentry->d_sb->s_blocksize_bits; 3858fd17795SChris Mason 3868fd17795SChris Mason buf->f_namelen = BTRFS_NAME_LEN; 387db94535dSChris Mason buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; 388db94535dSChris Mason buf->f_bfree = buf->f_blocks - 389db94535dSChris Mason (btrfs_super_bytes_used(disk_super) >> bits); 3908fd17795SChris Mason buf->f_bavail = buf->f_bfree; 3918fd17795SChris Mason buf->f_bsize = dentry->d_sb->s_blocksize; 3928fd17795SChris Mason buf->f_type = BTRFS_SUPER_MAGIC; 3938fd17795SChris Mason return 0; 3948fd17795SChris Mason } 395b5133862SChris Mason 3962e635a27SChris Mason static struct file_system_type btrfs_fs_type = { 3972e635a27SChris Mason .owner = THIS_MODULE, 3982e635a27SChris Mason .name = "btrfs", 3992e635a27SChris Mason .get_sb = btrfs_get_sb, 4002e635a27SChris Mason .kill_sb = kill_block_super, 4012e635a27SChris Mason .fs_flags = FS_REQUIRES_DEV, 4022e635a27SChris Mason }; 4032e635a27SChris Mason 404e20d96d6SChris Mason static struct super_operations btrfs_super_ops = { 405134e9731SChris Mason .delete_inode = btrfs_delete_inode, 406e20d96d6SChris Mason .put_super = btrfs_put_super, 407e20d96d6SChris Mason .read_inode = btrfs_read_locked_inode, 408d5719762SChris Mason .write_super = btrfs_write_super, 409d5719762SChris Mason .sync_fs = btrfs_sync_fs, 4104730a4bcSChris Mason .write_inode = btrfs_write_inode, 411b5133862SChris Mason .dirty_inode = btrfs_dirty_inode, 4122c90e5d6SChris Mason .alloc_inode = btrfs_alloc_inode, 4132c90e5d6SChris Mason .destroy_inode = btrfs_destroy_inode, 4148fd17795SChris Mason .statfs = btrfs_statfs, 415e20d96d6SChris Mason }; 416e20d96d6SChris Mason 4172e635a27SChris Mason static int __init init_btrfs_fs(void) 4182e635a27SChris Mason { 4192c90e5d6SChris Mason int err; 42058176a96SJosef Bacik 42158176a96SJosef Bacik err = btrfs_init_sysfs(); 42258176a96SJosef Bacik if (err) 42358176a96SJosef Bacik return err; 42458176a96SJosef Bacik 42508607c1bSChris Mason btrfs_init_transaction_sys(); 42639279cc3SChris Mason err = btrfs_init_cachep(); 4272c90e5d6SChris Mason if (err) 4282f4cbe64SWyatt Banks goto free_transaction_sys; 4292f4cbe64SWyatt Banks err = extent_map_init(); 4302f4cbe64SWyatt Banks if (err) 4312f4cbe64SWyatt Banks goto free_cachep; 4322f4cbe64SWyatt Banks 4332f4cbe64SWyatt Banks err = register_filesystem(&btrfs_fs_type); 4342f4cbe64SWyatt Banks if (err) 4352f4cbe64SWyatt Banks goto free_extent_map; 4362f4cbe64SWyatt Banks return 0; 4372f4cbe64SWyatt Banks 4382f4cbe64SWyatt Banks free_extent_map: 4392f4cbe64SWyatt Banks extent_map_exit(); 4402f4cbe64SWyatt Banks free_cachep: 4412f4cbe64SWyatt Banks btrfs_destroy_cachep(); 4422f4cbe64SWyatt Banks free_transaction_sys: 4432f4cbe64SWyatt Banks btrfs_exit_transaction_sys(); 4442f4cbe64SWyatt Banks btrfs_exit_sysfs(); 4452c90e5d6SChris Mason return err; 4462e635a27SChris Mason } 4472e635a27SChris Mason 4482e635a27SChris Mason static void __exit exit_btrfs_fs(void) 4492e635a27SChris Mason { 45008607c1bSChris Mason btrfs_exit_transaction_sys(); 45139279cc3SChris Mason btrfs_destroy_cachep(); 452a52d9a80SChris Mason extent_map_exit(); 4532e635a27SChris Mason unregister_filesystem(&btrfs_fs_type); 45458176a96SJosef Bacik btrfs_exit_sysfs(); 4552e635a27SChris Mason } 4562e635a27SChris Mason 4572e635a27SChris Mason module_init(init_btrfs_fs) 4582e635a27SChris Mason module_exit(exit_btrfs_fs) 4592e635a27SChris Mason 4602e635a27SChris Mason MODULE_LICENSE("GPL"); 461