xref: /linux/fs/btrfs/super.c (revision 21380931eb4da4e29ac663d0221581282cbba208)
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>
27a9572a15SEric Paris #include <linux/seq_file.h>
282e635a27SChris Mason #include <linux/string.h>
292e635a27SChris Mason #include <linux/smp_lock.h>
302e635a27SChris Mason #include <linux/backing-dev.h>
314b82d6e4SYan #include <linux/mount.h>
32dee26a9fSChris Mason #include <linux/mpage.h>
3375dfe396SChris Mason #include <linux/swap.h>
3475dfe396SChris Mason #include <linux/writeback.h>
358fd17795SChris Mason #include <linux/statfs.h>
3608607c1bSChris Mason #include <linux/compat.h>
3795e05289SChris Mason #include <linux/parser.h>
38c59f8951SChris Mason #include <linux/ctype.h>
396da6abaeSChris Mason #include <linux/namei.h>
40a9218f6bSChris Mason #include <linux/miscdevice.h>
411bcbf313SQinghuang Feng #include <linux/magic.h>
424b4e25f2SChris Mason #include "compat.h"
432e635a27SChris Mason #include "ctree.h"
44e20d96d6SChris Mason #include "disk-io.h"
45d5719762SChris Mason #include "transaction.h"
462c90e5d6SChris Mason #include "btrfs_inode.h"
47c5739bbaSChris Mason #include "ioctl.h"
483a686375SChris Mason #include "print-tree.h"
495103e947SJosef Bacik #include "xattr.h"
508a4b83ccSChris Mason #include "volumes.h"
51b3c3da71SChris Mason #include "version.h"
52be6e8dc0SBalaji Rao #include "export.h"
53c8b97818SChris Mason #include "compression.h"
542e635a27SChris Mason 
55e20d96d6SChris Mason 
56e20d96d6SChris Mason static struct super_operations btrfs_super_ops;
57e20d96d6SChris Mason 
58e20d96d6SChris Mason static void btrfs_put_super(struct super_block *sb)
59e20d96d6SChris Mason {
60e20d96d6SChris Mason 	struct btrfs_root *root = btrfs_sb(sb);
61e20d96d6SChris Mason 	int ret;
62e20d96d6SChris Mason 
63e20d96d6SChris Mason 	ret = close_ctree(root);
64e20d96d6SChris Mason 	sb->s_fs_info = NULL;
65e20d96d6SChris Mason }
662e635a27SChris Mason 
6795e05289SChris Mason enum {
6843e570b0SChristoph Hellwig 	Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow,
69dfe25020SChris Mason 	Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier,
703a5e1404SSage Weil 	Opt_ssd, Opt_thread_pool, Opt_noacl,  Opt_compress, Opt_notreelog,
7197e728d4SJosef Bacik 	Opt_ratio, Opt_flushoncommit, Opt_err,
7295e05289SChris Mason };
7395e05289SChris Mason 
7495e05289SChris Mason static match_table_t tokens = {
75dfe25020SChris Mason 	{Opt_degraded, "degraded"},
7695e05289SChris Mason 	{Opt_subvol, "subvol=%s"},
7743e570b0SChristoph Hellwig 	{Opt_device, "device=%s"},
78b6cda9bcSChris Mason 	{Opt_nodatasum, "nodatasum"},
79be20aa9dSChris Mason 	{Opt_nodatacow, "nodatacow"},
8021ad10cfSChris Mason 	{Opt_nobarrier, "nobarrier"},
81c59f8951SChris Mason 	{Opt_max_extent, "max_extent=%s"},
826f568d35SChris Mason 	{Opt_max_inline, "max_inline=%s"},
838f662a76SChris Mason 	{Opt_alloc_start, "alloc_start=%s"},
844543df7eSChris Mason 	{Opt_thread_pool, "thread_pool=%d"},
85c8b97818SChris Mason 	{Opt_compress, "compress"},
86e18e4809SChris Mason 	{Opt_ssd, "ssd"},
8733268eafSJosef Bacik 	{Opt_noacl, "noacl"},
883a5e1404SSage Weil 	{Opt_notreelog, "notreelog"},
89dccae999SSage Weil 	{Opt_flushoncommit, "flushoncommit"},
9097e728d4SJosef Bacik 	{Opt_ratio, "metadata_ratio=%d"},
9133268eafSJosef Bacik 	{Opt_err, NULL},
9295e05289SChris Mason };
9395e05289SChris Mason 
94edbd8d4eSChris Mason u64 btrfs_parse_size(char *str)
95c59f8951SChris Mason {
96edbd8d4eSChris Mason 	u64 res;
97c59f8951SChris Mason 	int mult = 1;
98c59f8951SChris Mason 	char *end;
99c59f8951SChris Mason 	char last;
100c59f8951SChris Mason 
101c59f8951SChris Mason 	res = simple_strtoul(str, &end, 10);
102c59f8951SChris Mason 
103c59f8951SChris Mason 	last = end[0];
104c59f8951SChris Mason 	if (isalpha(last)) {
105c59f8951SChris Mason 		last = tolower(last);
106c59f8951SChris Mason 		switch (last) {
107c59f8951SChris Mason 		case 'g':
108c59f8951SChris Mason 			mult *= 1024;
109c59f8951SChris Mason 		case 'm':
110c59f8951SChris Mason 			mult *= 1024;
111c59f8951SChris Mason 		case 'k':
112c59f8951SChris Mason 			mult *= 1024;
113c59f8951SChris Mason 		}
114c59f8951SChris Mason 		res = res * mult;
115c59f8951SChris Mason 	}
116c59f8951SChris Mason 	return res;
117c59f8951SChris Mason }
118c59f8951SChris Mason 
119edf24abeSChristoph Hellwig /*
120edf24abeSChristoph Hellwig  * Regular mount options parser.  Everything that is needed only when
121edf24abeSChristoph Hellwig  * reading in a new superblock is parsed here.
122edf24abeSChristoph Hellwig  */
123edf24abeSChristoph Hellwig int btrfs_parse_options(struct btrfs_root *root, char *options)
12495e05289SChris Mason {
125edf24abeSChristoph Hellwig 	struct btrfs_fs_info *info = root->fs_info;
12695e05289SChris Mason 	substring_t args[MAX_OPT_ARGS];
127edf24abeSChristoph Hellwig 	char *p, *num;
1284543df7eSChris Mason 	int intarg;
129b6cda9bcSChris Mason 
13095e05289SChris Mason 	if (!options)
131edf24abeSChristoph Hellwig 		return 0;
13295e05289SChris Mason 
133be20aa9dSChris Mason 	/*
134be20aa9dSChris Mason 	 * strsep changes the string, duplicate it because parse_options
135be20aa9dSChris Mason 	 * gets called twice
136be20aa9dSChris Mason 	 */
137be20aa9dSChris Mason 	options = kstrdup(options, GFP_NOFS);
138be20aa9dSChris Mason 	if (!options)
139be20aa9dSChris Mason 		return -ENOMEM;
140be20aa9dSChris Mason 
141be20aa9dSChris Mason 
14295e05289SChris Mason 	while ((p = strsep(&options, ",")) != NULL) {
14395e05289SChris Mason 		int token;
14495e05289SChris Mason 		if (!*p)
14595e05289SChris Mason 			continue;
14695e05289SChris Mason 
14795e05289SChris Mason 		token = match_token(p, tokens, args);
14895e05289SChris Mason 		switch (token) {
149dfe25020SChris Mason 		case Opt_degraded:
150edf24abeSChristoph Hellwig 			printk(KERN_INFO "btrfs: allowing degraded mounts\n");
151dfe25020SChris Mason 			btrfs_set_opt(info->mount_opt, DEGRADED);
152dfe25020SChris Mason 			break;
15395e05289SChris Mason 		case Opt_subvol:
15443e570b0SChristoph Hellwig 		case Opt_device:
155edf24abeSChristoph Hellwig 			/*
15643e570b0SChristoph Hellwig 			 * These are parsed by btrfs_parse_early_options
157edf24abeSChristoph Hellwig 			 * and can be happily ignored here.
158edf24abeSChristoph Hellwig 			 */
15995e05289SChris Mason 			break;
160b6cda9bcSChris Mason 		case Opt_nodatasum:
161edf24abeSChristoph Hellwig 			printk(KERN_INFO "btrfs: setting nodatacsum\n");
162b6cda9bcSChris Mason 			btrfs_set_opt(info->mount_opt, NODATASUM);
163be20aa9dSChris Mason 			break;
164be20aa9dSChris Mason 		case Opt_nodatacow:
165edf24abeSChristoph Hellwig 			printk(KERN_INFO "btrfs: setting nodatacow\n");
166be20aa9dSChris Mason 			btrfs_set_opt(info->mount_opt, NODATACOW);
167be20aa9dSChris Mason 			btrfs_set_opt(info->mount_opt, NODATASUM);
168b6cda9bcSChris Mason 			break;
169c8b97818SChris Mason 		case Opt_compress:
170c8b97818SChris Mason 			printk(KERN_INFO "btrfs: use compression\n");
171c8b97818SChris Mason 			btrfs_set_opt(info->mount_opt, COMPRESS);
172c8b97818SChris Mason 			break;
173e18e4809SChris Mason 		case Opt_ssd:
174edf24abeSChristoph Hellwig 			printk(KERN_INFO "btrfs: use ssd allocation scheme\n");
175e18e4809SChris Mason 			btrfs_set_opt(info->mount_opt, SSD);
176e18e4809SChris Mason 			break;
17721ad10cfSChris Mason 		case Opt_nobarrier:
178edf24abeSChristoph Hellwig 			printk(KERN_INFO "btrfs: turning off barriers\n");
17921ad10cfSChris Mason 			btrfs_set_opt(info->mount_opt, NOBARRIER);
18021ad10cfSChris Mason 			break;
1814543df7eSChris Mason 		case Opt_thread_pool:
1824543df7eSChris Mason 			intarg = 0;
1834543df7eSChris Mason 			match_int(&args[0], &intarg);
1844543df7eSChris Mason 			if (intarg) {
1854543df7eSChris Mason 				info->thread_pool_size = intarg;
1864543df7eSChris Mason 				printk(KERN_INFO "btrfs: thread pool %d\n",
1874543df7eSChris Mason 				       info->thread_pool_size);
1884543df7eSChris Mason 			}
1894543df7eSChris Mason 			break;
190c59f8951SChris Mason 		case Opt_max_extent:
191edf24abeSChristoph Hellwig 			num = match_strdup(&args[0]);
192c59f8951SChris Mason 			if (num) {
193edf24abeSChristoph Hellwig 				info->max_extent = btrfs_parse_size(num);
194c59f8951SChris Mason 				kfree(num);
195c59f8951SChris Mason 
196c59f8951SChris Mason 				info->max_extent = max_t(u64,
197edf24abeSChristoph Hellwig 					info->max_extent, root->sectorsize);
198edf24abeSChristoph Hellwig 				printk(KERN_INFO "btrfs: max_extent at %llu\n",
199*21380931SJoel Becker 				       (unsigned long long)info->max_extent);
200c59f8951SChris Mason 			}
201c59f8951SChris Mason 			break;
2026f568d35SChris Mason 		case Opt_max_inline:
203edf24abeSChristoph Hellwig 			num = match_strdup(&args[0]);
2046f568d35SChris Mason 			if (num) {
205edf24abeSChristoph Hellwig 				info->max_inline = btrfs_parse_size(num);
2066f568d35SChris Mason 				kfree(num);
2076f568d35SChris Mason 
20815ada040SChris Mason 				if (info->max_inline) {
2096f568d35SChris Mason 					info->max_inline = max_t(u64,
21015ada040SChris Mason 						info->max_inline,
21115ada040SChris Mason 						root->sectorsize);
21215ada040SChris Mason 				}
213edf24abeSChristoph Hellwig 				printk(KERN_INFO "btrfs: max_inline at %llu\n",
214*21380931SJoel Becker 					(unsigned long long)info->max_inline);
2156f568d35SChris Mason 			}
2166f568d35SChris Mason 			break;
2178f662a76SChris Mason 		case Opt_alloc_start:
218edf24abeSChristoph Hellwig 			num = match_strdup(&args[0]);
2198f662a76SChris Mason 			if (num) {
220edf24abeSChristoph Hellwig 				info->alloc_start = btrfs_parse_size(num);
2218f662a76SChris Mason 				kfree(num);
222edf24abeSChristoph Hellwig 				printk(KERN_INFO
223edf24abeSChristoph Hellwig 					"btrfs: allocations start at %llu\n",
224*21380931SJoel Becker 					(unsigned long long)info->alloc_start);
2258f662a76SChris Mason 			}
2268f662a76SChris Mason 			break;
22733268eafSJosef Bacik 		case Opt_noacl:
22833268eafSJosef Bacik 			root->fs_info->sb->s_flags &= ~MS_POSIXACL;
22933268eafSJosef Bacik 			break;
2303a5e1404SSage Weil 		case Opt_notreelog:
2313a5e1404SSage Weil 			printk(KERN_INFO "btrfs: disabling tree log\n");
2323a5e1404SSage Weil 			btrfs_set_opt(info->mount_opt, NOTREELOG);
2333a5e1404SSage Weil 			break;
234dccae999SSage Weil 		case Opt_flushoncommit:
235dccae999SSage Weil 			printk(KERN_INFO "btrfs: turning on flush-on-commit\n");
236dccae999SSage Weil 			btrfs_set_opt(info->mount_opt, FLUSHONCOMMIT);
237dccae999SSage Weil 			break;
23897e728d4SJosef Bacik 		case Opt_ratio:
23997e728d4SJosef Bacik 			intarg = 0;
24097e728d4SJosef Bacik 			match_int(&args[0], &intarg);
24197e728d4SJosef Bacik 			if (intarg) {
24297e728d4SJosef Bacik 				info->metadata_ratio = intarg;
24397e728d4SJosef Bacik 				printk(KERN_INFO "btrfs: metadata ratio %d\n",
24497e728d4SJosef Bacik 				       info->metadata_ratio);
24597e728d4SJosef Bacik 			}
24697e728d4SJosef Bacik 			break;
24795e05289SChris Mason 		default:
248be20aa9dSChris Mason 			break;
24995e05289SChris Mason 		}
25095e05289SChris Mason 	}
251be20aa9dSChris Mason 	kfree(options);
252edf24abeSChristoph Hellwig 	return 0;
253edf24abeSChristoph Hellwig }
254edf24abeSChristoph Hellwig 
255edf24abeSChristoph Hellwig /*
256edf24abeSChristoph Hellwig  * Parse mount options that are required early in the mount process.
257edf24abeSChristoph Hellwig  *
258edf24abeSChristoph Hellwig  * All other options will be parsed on much later in the mount process and
259edf24abeSChristoph Hellwig  * only when we need to allocate a new super block.
260edf24abeSChristoph Hellwig  */
26197288f2cSChristoph Hellwig static int btrfs_parse_early_options(const char *options, fmode_t flags,
26243e570b0SChristoph Hellwig 		void *holder, char **subvol_name,
26343e570b0SChristoph Hellwig 		struct btrfs_fs_devices **fs_devices)
264edf24abeSChristoph Hellwig {
265edf24abeSChristoph Hellwig 	substring_t args[MAX_OPT_ARGS];
266edf24abeSChristoph Hellwig 	char *opts, *p;
267edf24abeSChristoph Hellwig 	int error = 0;
268edf24abeSChristoph Hellwig 
269edf24abeSChristoph Hellwig 	if (!options)
270edf24abeSChristoph Hellwig 		goto out;
271edf24abeSChristoph Hellwig 
272edf24abeSChristoph Hellwig 	/*
273edf24abeSChristoph Hellwig 	 * strsep changes the string, duplicate it because parse_options
274edf24abeSChristoph Hellwig 	 * gets called twice
275edf24abeSChristoph Hellwig 	 */
276edf24abeSChristoph Hellwig 	opts = kstrdup(options, GFP_KERNEL);
277edf24abeSChristoph Hellwig 	if (!opts)
278edf24abeSChristoph Hellwig 		return -ENOMEM;
279edf24abeSChristoph Hellwig 
280edf24abeSChristoph Hellwig 	while ((p = strsep(&opts, ",")) != NULL) {
281edf24abeSChristoph Hellwig 		int token;
282edf24abeSChristoph Hellwig 		if (!*p)
283edf24abeSChristoph Hellwig 			continue;
284edf24abeSChristoph Hellwig 
285edf24abeSChristoph Hellwig 		token = match_token(p, tokens, args);
286edf24abeSChristoph Hellwig 		switch (token) {
287edf24abeSChristoph Hellwig 		case Opt_subvol:
288edf24abeSChristoph Hellwig 			*subvol_name = match_strdup(&args[0]);
289edf24abeSChristoph Hellwig 			break;
29043e570b0SChristoph Hellwig 		case Opt_device:
29143e570b0SChristoph Hellwig 			error = btrfs_scan_one_device(match_strdup(&args[0]),
29243e570b0SChristoph Hellwig 					flags, holder, fs_devices);
29343e570b0SChristoph Hellwig 			if (error)
29443e570b0SChristoph Hellwig 				goto out_free_opts;
29543e570b0SChristoph Hellwig 			break;
296edf24abeSChristoph Hellwig 		default:
297edf24abeSChristoph Hellwig 			break;
298edf24abeSChristoph Hellwig 		}
299edf24abeSChristoph Hellwig 	}
300edf24abeSChristoph Hellwig 
30143e570b0SChristoph Hellwig  out_free_opts:
302edf24abeSChristoph Hellwig 	kfree(opts);
303edf24abeSChristoph Hellwig  out:
304edf24abeSChristoph Hellwig 	/*
305edf24abeSChristoph Hellwig 	 * If no subvolume name is specified we use the default one.  Allocate
3063de4586cSChris Mason 	 * a copy of the string "." here so that code later in the
307edf24abeSChristoph Hellwig 	 * mount path doesn't care if it's the default volume or another one.
308edf24abeSChristoph Hellwig 	 */
309edf24abeSChristoph Hellwig 	if (!*subvol_name) {
3103de4586cSChris Mason 		*subvol_name = kstrdup(".", GFP_KERNEL);
311edf24abeSChristoph Hellwig 		if (!*subvol_name)
312edf24abeSChristoph Hellwig 			return -ENOMEM;
313edf24abeSChristoph Hellwig 	}
314edf24abeSChristoph Hellwig 	return error;
31595e05289SChris Mason }
31695e05289SChris Mason 
3178a4b83ccSChris Mason static int btrfs_fill_super(struct super_block *sb,
3188a4b83ccSChris Mason 			    struct btrfs_fs_devices *fs_devices,
3198a4b83ccSChris Mason 			    void *data, int silent)
3202e635a27SChris Mason {
3212e635a27SChris Mason 	struct inode *inode;
322e20d96d6SChris Mason 	struct dentry *root_dentry;
323e20d96d6SChris Mason 	struct btrfs_super_block *disk_super;
3240f7d52f4SChris Mason 	struct btrfs_root *tree_root;
325d6e4a428SChris Mason 	struct btrfs_inode *bi;
32639279cc3SChris Mason 	int err;
3272e635a27SChris Mason 
3282e635a27SChris Mason 	sb->s_maxbytes = MAX_LFS_FILESIZE;
3292e635a27SChris Mason 	sb->s_magic = BTRFS_SUPER_MAGIC;
330e20d96d6SChris Mason 	sb->s_op = &btrfs_super_ops;
331be6e8dc0SBalaji Rao 	sb->s_export_op = &btrfs_export_ops;
3325103e947SJosef Bacik 	sb->s_xattr = btrfs_xattr_handlers;
3332e635a27SChris Mason 	sb->s_time_gran = 1;
33433268eafSJosef Bacik 	sb->s_flags |= MS_POSIXACL;
335e20d96d6SChris Mason 
336dfe25020SChris Mason 	tree_root = open_ctree(sb, fs_devices, (char *)data);
337d98237b3SChris Mason 
338e58ca020SYan 	if (IS_ERR(tree_root)) {
339e20d96d6SChris Mason 		printk("btrfs: open_ctree failed\n");
340e58ca020SYan 		return PTR_ERR(tree_root);
341e20d96d6SChris Mason 	}
3420f7d52f4SChris Mason 	sb->s_fs_info = tree_root;
3435f39d397SChris Mason 	disk_super = &tree_root->fs_info->super_copy;
3443de4586cSChris Mason 	inode = btrfs_iget_locked(sb, BTRFS_FIRST_FREE_OBJECTID,
3453de4586cSChris Mason 				  tree_root->fs_info->fs_root);
346d6e4a428SChris Mason 	bi = BTRFS_I(inode);
347d6e4a428SChris Mason 	bi->location.objectid = inode->i_ino;
348d6e4a428SChris Mason 	bi->location.offset = 0;
3493de4586cSChris Mason 	bi->root = tree_root->fs_info->fs_root;
350b888db2bSChris Mason 
351d6e4a428SChris Mason 	btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY);
352d6e4a428SChris Mason 
35339279cc3SChris Mason 	if (!inode) {
35439279cc3SChris Mason 		err = -ENOMEM;
35539279cc3SChris Mason 		goto fail_close;
35639279cc3SChris Mason 	}
357e20d96d6SChris Mason 	if (inode->i_state & I_NEW) {
358e20d96d6SChris Mason 		btrfs_read_locked_inode(inode);
359e20d96d6SChris Mason 		unlock_new_inode(inode);
360e20d96d6SChris Mason 	}
3612e635a27SChris Mason 
362e20d96d6SChris Mason 	root_dentry = d_alloc_root(inode);
363e20d96d6SChris Mason 	if (!root_dentry) {
3642e635a27SChris Mason 		iput(inode);
36539279cc3SChris Mason 		err = -ENOMEM;
36639279cc3SChris Mason 		goto fail_close;
3672e635a27SChris Mason 	}
368e4404d6eSYan Zheng #if 0
36958176a96SJosef Bacik 	/* this does the super kobj at the same time */
37058176a96SJosef Bacik 	err = btrfs_sysfs_add_super(tree_root->fs_info);
37158176a96SJosef Bacik 	if (err)
37258176a96SJosef Bacik 		goto fail_close;
373e4404d6eSYan Zheng #endif
37458176a96SJosef Bacik 
375e20d96d6SChris Mason 	sb->s_root = root_dentry;
3766885f308SChris Mason 
3776885f308SChris Mason 	save_mount_options(sb, data);
3782e635a27SChris Mason 	return 0;
3792e635a27SChris Mason 
38039279cc3SChris Mason fail_close:
38139279cc3SChris Mason 	close_ctree(tree_root);
382d5719762SChris Mason 	return err;
383d5719762SChris Mason }
384d5719762SChris Mason 
3856bf13c0cSSage Weil int btrfs_sync_fs(struct super_block *sb, int wait)
386d5719762SChris Mason {
387d5719762SChris Mason 	struct btrfs_trans_handle *trans;
388dccae999SSage Weil 	struct btrfs_root *root = btrfs_sb(sb);
389d5719762SChris Mason 	int ret;
390df2ce34cSChris Mason 
391c146afadSYan Zheng 	if (sb->s_flags & MS_RDONLY)
392c146afadSYan Zheng 		return 0;
393c146afadSYan Zheng 
394d5719762SChris Mason 	sb->s_dirt = 0;
395d561c025SChris Mason 	if (!wait) {
3967cfcc17eSChris Mason 		filemap_flush(root->fs_info->btree_inode->i_mapping);
397df2ce34cSChris Mason 		return 0;
398d561c025SChris Mason 	}
399771ed689SChris Mason 
400771ed689SChris Mason 	btrfs_start_delalloc_inodes(root);
401771ed689SChris Mason 	btrfs_wait_ordered_extents(root, 0);
402771ed689SChris Mason 
403d5719762SChris Mason 	trans = btrfs_start_transaction(root, 1);
404d5719762SChris Mason 	ret = btrfs_commit_transaction(trans, root);
405d5719762SChris Mason 	sb->s_dirt = 0;
40654aa1f4dSChris Mason 	return ret;
407d5719762SChris Mason }
408d5719762SChris Mason 
409a9572a15SEric Paris static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs)
410a9572a15SEric Paris {
411a9572a15SEric Paris 	struct btrfs_root *root = btrfs_sb(vfs->mnt_sb);
412a9572a15SEric Paris 	struct btrfs_fs_info *info = root->fs_info;
413a9572a15SEric Paris 
414a9572a15SEric Paris 	if (btrfs_test_opt(root, DEGRADED))
415a9572a15SEric Paris 		seq_puts(seq, ",degraded");
416a9572a15SEric Paris 	if (btrfs_test_opt(root, NODATASUM))
417a9572a15SEric Paris 		seq_puts(seq, ",nodatasum");
418a9572a15SEric Paris 	if (btrfs_test_opt(root, NODATACOW))
419a9572a15SEric Paris 		seq_puts(seq, ",nodatacow");
420a9572a15SEric Paris 	if (btrfs_test_opt(root, NOBARRIER))
421a9572a15SEric Paris 		seq_puts(seq, ",nobarrier");
422a9572a15SEric Paris 	if (info->max_extent != (u64)-1)
423*21380931SJoel Becker 		seq_printf(seq, ",max_extent=%llu",
424*21380931SJoel Becker 			   (unsigned long long)info->max_extent);
425a9572a15SEric Paris 	if (info->max_inline != 8192 * 1024)
426*21380931SJoel Becker 		seq_printf(seq, ",max_inline=%llu",
427*21380931SJoel Becker 			   (unsigned long long)info->max_inline);
428a9572a15SEric Paris 	if (info->alloc_start != 0)
429*21380931SJoel Becker 		seq_printf(seq, ",alloc_start=%llu",
430*21380931SJoel Becker 			   (unsigned long long)info->alloc_start);
431a9572a15SEric Paris 	if (info->thread_pool_size !=  min_t(unsigned long,
432a9572a15SEric Paris 					     num_online_cpus() + 2, 8))
433a9572a15SEric Paris 		seq_printf(seq, ",thread_pool=%d", info->thread_pool_size);
434a9572a15SEric Paris 	if (btrfs_test_opt(root, COMPRESS))
435a9572a15SEric Paris 		seq_puts(seq, ",compress");
436a9572a15SEric Paris 	if (btrfs_test_opt(root, SSD))
437a9572a15SEric Paris 		seq_puts(seq, ",ssd");
4383a5e1404SSage Weil 	if (btrfs_test_opt(root, NOTREELOG))
439dccae999SSage Weil 		seq_puts(seq, ",no-treelog");
440dccae999SSage Weil 	if (btrfs_test_opt(root, FLUSHONCOMMIT))
441dccae999SSage Weil 		seq_puts(seq, ",flush-on-commit");
442a9572a15SEric Paris 	if (!(root->fs_info->sb->s_flags & MS_POSIXACL))
443a9572a15SEric Paris 		seq_puts(seq, ",noacl");
444a9572a15SEric Paris 	return 0;
445a9572a15SEric Paris }
446a9572a15SEric Paris 
447d561c025SChris Mason static void btrfs_write_super(struct super_block *sb)
448d561c025SChris Mason {
44908607c1bSChris Mason 	sb->s_dirt = 0;
450d561c025SChris Mason }
451d561c025SChris Mason 
452a061fc8dSChris Mason static int btrfs_test_super(struct super_block *s, void *data)
4532e635a27SChris Mason {
454a061fc8dSChris Mason 	struct btrfs_fs_devices *test_fs_devices = data;
455a061fc8dSChris Mason 	struct btrfs_root *root = btrfs_sb(s);
4564b82d6e4SYan 
457a061fc8dSChris Mason 	return root->fs_info->fs_devices == test_fs_devices;
4584b82d6e4SYan }
4594b82d6e4SYan 
460edf24abeSChristoph Hellwig /*
461edf24abeSChristoph Hellwig  * Find a superblock for the given device / mount point.
462edf24abeSChristoph Hellwig  *
463edf24abeSChristoph Hellwig  * Note:  This is based on get_sb_bdev from fs/super.c with a few additions
464edf24abeSChristoph Hellwig  *	  for multiple device setup.  Make sure to keep it in sync.
465edf24abeSChristoph Hellwig  */
466edf24abeSChristoph Hellwig static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
467edf24abeSChristoph Hellwig 		const char *dev_name, void *data, struct vfsmount *mnt)
4684b82d6e4SYan {
469edf24abeSChristoph Hellwig 	char *subvol_name = NULL;
4704b82d6e4SYan 	struct block_device *bdev = NULL;
4714b82d6e4SYan 	struct super_block *s;
4724b82d6e4SYan 	struct dentry *root;
4738a4b83ccSChris Mason 	struct btrfs_fs_devices *fs_devices = NULL;
47497288f2cSChristoph Hellwig 	fmode_t mode = FMODE_READ;
4754b82d6e4SYan 	int error = 0;
4764b82d6e4SYan 
47797288f2cSChristoph Hellwig 	if (!(flags & MS_RDONLY))
47897288f2cSChristoph Hellwig 		mode |= FMODE_WRITE;
47997288f2cSChristoph Hellwig 
48097288f2cSChristoph Hellwig 	error = btrfs_parse_early_options(data, mode, fs_type,
48143e570b0SChristoph Hellwig 					  &subvol_name, &fs_devices);
482edf24abeSChristoph Hellwig 	if (error)
4831f483660SShen Feng 		return error;
484edf24abeSChristoph Hellwig 
48597288f2cSChristoph Hellwig 	error = btrfs_scan_one_device(dev_name, mode, fs_type, &fs_devices);
4868a4b83ccSChris Mason 	if (error)
487edf24abeSChristoph Hellwig 		goto error_free_subvol_name;
4884b82d6e4SYan 
48997288f2cSChristoph Hellwig 	error = btrfs_open_devices(fs_devices, mode, fs_type);
4908a4b83ccSChris Mason 	if (error)
491edf24abeSChristoph Hellwig 		goto error_free_subvol_name;
4928a4b83ccSChris Mason 
4932b82032cSYan Zheng 	if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) {
4942b82032cSYan Zheng 		error = -EACCES;
4952b82032cSYan Zheng 		goto error_close_devices;
4962b82032cSYan Zheng 	}
4972b82032cSYan Zheng 
498dfe25020SChris Mason 	bdev = fs_devices->latest_bdev;
499a061fc8dSChris Mason 	s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices);
5004b82d6e4SYan 	if (IS_ERR(s))
5014b82d6e4SYan 		goto error_s;
5024b82d6e4SYan 
5034b82d6e4SYan 	if (s->s_root) {
5044b82d6e4SYan 		if ((flags ^ s->s_flags) & MS_RDONLY) {
5054b82d6e4SYan 			up_write(&s->s_umount);
5064b82d6e4SYan 			deactivate_super(s);
5074b82d6e4SYan 			error = -EBUSY;
508c146afadSYan Zheng 			goto error_close_devices;
5094b82d6e4SYan 		}
5104b82d6e4SYan 
5112b82032cSYan Zheng 		btrfs_close_devices(fs_devices);
5124b82d6e4SYan 	} else {
5134b82d6e4SYan 		char b[BDEVNAME_SIZE];
5144b82d6e4SYan 
5154b82d6e4SYan 		s->s_flags = flags;
5164b82d6e4SYan 		strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
5178a4b83ccSChris Mason 		error = btrfs_fill_super(s, fs_devices, data,
5188a4b83ccSChris Mason 					 flags & MS_SILENT ? 1 : 0);
5194b82d6e4SYan 		if (error) {
5204b82d6e4SYan 			up_write(&s->s_umount);
5214b82d6e4SYan 			deactivate_super(s);
5221f483660SShen Feng 			goto error_free_subvol_name;
5234b82d6e4SYan 		}
5244b82d6e4SYan 
525788f20ebSChris Mason 		btrfs_sb(s)->fs_info->bdev_holder = fs_type;
5264b82d6e4SYan 		s->s_flags |= MS_ACTIVE;
5274b82d6e4SYan 	}
5284b82d6e4SYan 
52976fcef19SDavid Woodhouse 	if (!strcmp(subvol_name, "."))
53076fcef19SDavid Woodhouse 		root = dget(s->s_root);
53176fcef19SDavid Woodhouse 	else {
532b48652c1SYan Zheng 		mutex_lock(&s->s_root->d_inode->i_mutex);
533d397712bSChris Mason 		root = lookup_one_len(subvol_name, s->s_root,
534d397712bSChris Mason 				      strlen(subvol_name));
535b48652c1SYan Zheng 		mutex_unlock(&s->s_root->d_inode->i_mutex);
536d397712bSChris Mason 
5374b82d6e4SYan 		if (IS_ERR(root)) {
5384b82d6e4SYan 			up_write(&s->s_umount);
5394b82d6e4SYan 			deactivate_super(s);
5404b82d6e4SYan 			error = PTR_ERR(root);
5411f483660SShen Feng 			goto error_free_subvol_name;
5424b82d6e4SYan 		}
5434b82d6e4SYan 		if (!root->d_inode) {
5444b82d6e4SYan 			dput(root);
5454b82d6e4SYan 			up_write(&s->s_umount);
5464b82d6e4SYan 			deactivate_super(s);
5474b82d6e4SYan 			error = -ENXIO;
5481f483660SShen Feng 			goto error_free_subvol_name;
5494b82d6e4SYan 		}
55076fcef19SDavid Woodhouse 	}
5514b82d6e4SYan 
5524b82d6e4SYan 	mnt->mnt_sb = s;
5534b82d6e4SYan 	mnt->mnt_root = root;
554edf24abeSChristoph Hellwig 
555edf24abeSChristoph Hellwig 	kfree(subvol_name);
5564b82d6e4SYan 	return 0;
5574b82d6e4SYan 
5584b82d6e4SYan error_s:
5594b82d6e4SYan 	error = PTR_ERR(s);
560c146afadSYan Zheng error_close_devices:
5618a4b83ccSChris Mason 	btrfs_close_devices(fs_devices);
562edf24abeSChristoph Hellwig error_free_subvol_name:
563edf24abeSChristoph Hellwig 	kfree(subvol_name);
5644b82d6e4SYan 	return error;
5654b82d6e4SYan }
5662e635a27SChris Mason 
567c146afadSYan Zheng static int btrfs_remount(struct super_block *sb, int *flags, char *data)
568c146afadSYan Zheng {
569c146afadSYan Zheng 	struct btrfs_root *root = btrfs_sb(sb);
570c146afadSYan Zheng 	int ret;
571c146afadSYan Zheng 
572b288052eSChris Mason 	ret = btrfs_parse_options(root, data);
573b288052eSChris Mason 	if (ret)
574b288052eSChris Mason 		return -EINVAL;
575b288052eSChris Mason 
576c146afadSYan Zheng 	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
577c146afadSYan Zheng 		return 0;
578c146afadSYan Zheng 
579c146afadSYan Zheng 	if (*flags & MS_RDONLY) {
580c146afadSYan Zheng 		sb->s_flags |= MS_RDONLY;
581c146afadSYan Zheng 
582c146afadSYan Zheng 		ret =  btrfs_commit_super(root);
583c146afadSYan Zheng 		WARN_ON(ret);
584c146afadSYan Zheng 	} else {
5852b82032cSYan Zheng 		if (root->fs_info->fs_devices->rw_devices == 0)
5862b82032cSYan Zheng 			return -EACCES;
5872b82032cSYan Zheng 
588c146afadSYan Zheng 		if (btrfs_super_log_root(&root->fs_info->super_copy) != 0)
589c146afadSYan Zheng 			return -EINVAL;
590c146afadSYan Zheng 
591c146afadSYan Zheng 		ret = btrfs_cleanup_reloc_trees(root);
592c146afadSYan Zheng 		WARN_ON(ret);
593c146afadSYan Zheng 
594c146afadSYan Zheng 		ret = btrfs_cleanup_fs_roots(root->fs_info);
595c146afadSYan Zheng 		WARN_ON(ret);
596c146afadSYan Zheng 
597c146afadSYan Zheng 		sb->s_flags &= ~MS_RDONLY;
598c146afadSYan Zheng 	}
599c146afadSYan Zheng 
600c146afadSYan Zheng 	return 0;
601c146afadSYan Zheng }
602c146afadSYan Zheng 
6038fd17795SChris Mason static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
6048fd17795SChris Mason {
6058fd17795SChris Mason 	struct btrfs_root *root = btrfs_sb(dentry->d_sb);
6064b52dff6SChris Mason 	struct btrfs_super_block *disk_super = &root->fs_info->super_copy;
607db94535dSChris Mason 	int bits = dentry->d_sb->s_blocksize_bits;
6089d03632eSDavid Woodhouse 	__be32 *fsid = (__be32 *)root->fs_info->fsid;
6098fd17795SChris Mason 
6108fd17795SChris Mason 	buf->f_namelen = BTRFS_NAME_LEN;
611db94535dSChris Mason 	buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits;
612db94535dSChris Mason 	buf->f_bfree = buf->f_blocks -
613db94535dSChris Mason 		(btrfs_super_bytes_used(disk_super) >> bits);
6148fd17795SChris Mason 	buf->f_bavail = buf->f_bfree;
6158fd17795SChris Mason 	buf->f_bsize = dentry->d_sb->s_blocksize;
6168fd17795SChris Mason 	buf->f_type = BTRFS_SUPER_MAGIC;
617d397712bSChris Mason 
6189d03632eSDavid Woodhouse 	/* We treat it as constant endianness (it doesn't matter _which_)
6199d03632eSDavid Woodhouse 	   because we want the fsid to come out the same whether mounted
6209d03632eSDavid Woodhouse 	   on a big-endian or little-endian host */
6219d03632eSDavid Woodhouse 	buf->f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]);
6229d03632eSDavid Woodhouse 	buf->f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]);
62332d48fa1SDavid Woodhouse 	/* Mask in the root object ID too, to disambiguate subvols */
62432d48fa1SDavid Woodhouse 	buf->f_fsid.val[0] ^= BTRFS_I(dentry->d_inode)->root->objectid >> 32;
62532d48fa1SDavid Woodhouse 	buf->f_fsid.val[1] ^= BTRFS_I(dentry->d_inode)->root->objectid;
62632d48fa1SDavid Woodhouse 
6278fd17795SChris Mason 	return 0;
6288fd17795SChris Mason }
629b5133862SChris Mason 
6302e635a27SChris Mason static struct file_system_type btrfs_fs_type = {
6312e635a27SChris Mason 	.owner		= THIS_MODULE,
6322e635a27SChris Mason 	.name		= "btrfs",
6332e635a27SChris Mason 	.get_sb		= btrfs_get_sb,
634a061fc8dSChris Mason 	.kill_sb	= kill_anon_super,
6352e635a27SChris Mason 	.fs_flags	= FS_REQUIRES_DEV,
6362e635a27SChris Mason };
637a9218f6bSChris Mason 
638d352ac68SChris Mason /*
639d352ac68SChris Mason  * used by btrfsctl to scan devices when no FS is mounted
640d352ac68SChris Mason  */
6418a4b83ccSChris Mason static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
6428a4b83ccSChris Mason 				unsigned long arg)
6438a4b83ccSChris Mason {
6448a4b83ccSChris Mason 	struct btrfs_ioctl_vol_args *vol;
6458a4b83ccSChris Mason 	struct btrfs_fs_devices *fs_devices;
646c071fcfdSChris Mason 	int ret = -ENOTTY;
6478a4b83ccSChris Mason 
648e441d54dSChris Mason 	if (!capable(CAP_SYS_ADMIN))
649e441d54dSChris Mason 		return -EPERM;
650e441d54dSChris Mason 
6518a4b83ccSChris Mason 	vol = kmalloc(sizeof(*vol), GFP_KERNEL);
65219d00cc1SWang Cong 	if (!vol)
65319d00cc1SWang Cong 		return -ENOMEM;
65419d00cc1SWang Cong 
6558a4b83ccSChris Mason 	if (copy_from_user(vol, (void __user *)arg, sizeof(*vol))) {
6568a4b83ccSChris Mason 		ret = -EFAULT;
6578a4b83ccSChris Mason 		goto out;
6588a4b83ccSChris Mason 	}
659c071fcfdSChris Mason 
6608a4b83ccSChris Mason 	switch (cmd) {
6618a4b83ccSChris Mason 	case BTRFS_IOC_SCAN_DEV:
66297288f2cSChristoph Hellwig 		ret = btrfs_scan_one_device(vol->name, FMODE_READ,
6638a4b83ccSChris Mason 					    &btrfs_fs_type, &fs_devices);
6648a4b83ccSChris Mason 		break;
6658a4b83ccSChris Mason 	}
6668a4b83ccSChris Mason out:
6678a4b83ccSChris Mason 	kfree(vol);
668f819d837SLinda Knippers 	return ret;
6698a4b83ccSChris Mason }
6708a4b83ccSChris Mason 
6710176260fSLinus Torvalds static int btrfs_freeze(struct super_block *sb)
672ed0dab6bSYan {
673ed0dab6bSYan 	struct btrfs_root *root = btrfs_sb(sb);
674a74a4b97SChris Mason 	mutex_lock(&root->fs_info->transaction_kthread_mutex);
675a74a4b97SChris Mason 	mutex_lock(&root->fs_info->cleaner_mutex);
6760176260fSLinus Torvalds 	return 0;
677ed0dab6bSYan }
678ed0dab6bSYan 
6790176260fSLinus Torvalds static int btrfs_unfreeze(struct super_block *sb)
680ed0dab6bSYan {
681ed0dab6bSYan 	struct btrfs_root *root = btrfs_sb(sb);
682a74a4b97SChris Mason 	mutex_unlock(&root->fs_info->cleaner_mutex);
683a74a4b97SChris Mason 	mutex_unlock(&root->fs_info->transaction_kthread_mutex);
6840176260fSLinus Torvalds 	return 0;
685ed0dab6bSYan }
6862e635a27SChris Mason 
687e20d96d6SChris Mason static struct super_operations btrfs_super_ops = {
688134e9731SChris Mason 	.delete_inode	= btrfs_delete_inode,
689e20d96d6SChris Mason 	.put_super	= btrfs_put_super,
690d5719762SChris Mason 	.write_super	= btrfs_write_super,
691d5719762SChris Mason 	.sync_fs	= btrfs_sync_fs,
692a9572a15SEric Paris 	.show_options	= btrfs_show_options,
6934730a4bcSChris Mason 	.write_inode	= btrfs_write_inode,
694b5133862SChris Mason 	.dirty_inode	= btrfs_dirty_inode,
6952c90e5d6SChris Mason 	.alloc_inode	= btrfs_alloc_inode,
6962c90e5d6SChris Mason 	.destroy_inode	= btrfs_destroy_inode,
6978fd17795SChris Mason 	.statfs		= btrfs_statfs,
698c146afadSYan Zheng 	.remount_fs	= btrfs_remount,
6990176260fSLinus Torvalds 	.freeze_fs	= btrfs_freeze,
7000176260fSLinus Torvalds 	.unfreeze_fs	= btrfs_unfreeze,
701e20d96d6SChris Mason };
702a9218f6bSChris Mason 
703a9218f6bSChris Mason static const struct file_operations btrfs_ctl_fops = {
704a9218f6bSChris Mason 	.unlocked_ioctl	 = btrfs_control_ioctl,
705a9218f6bSChris Mason 	.compat_ioctl = btrfs_control_ioctl,
706a9218f6bSChris Mason 	.owner	 = THIS_MODULE,
707a9218f6bSChris Mason };
708a9218f6bSChris Mason 
709a9218f6bSChris Mason static struct miscdevice btrfs_misc = {
710a9218f6bSChris Mason 	.minor		= MISC_DYNAMIC_MINOR,
711a9218f6bSChris Mason 	.name		= "btrfs-control",
712a9218f6bSChris Mason 	.fops		= &btrfs_ctl_fops
713a9218f6bSChris Mason };
714a9218f6bSChris Mason 
715a9218f6bSChris Mason static int btrfs_interface_init(void)
716a9218f6bSChris Mason {
717a9218f6bSChris Mason 	return misc_register(&btrfs_misc);
718a9218f6bSChris Mason }
719a9218f6bSChris Mason 
720b2950863SChristoph Hellwig static void btrfs_interface_exit(void)
721a9218f6bSChris Mason {
722a9218f6bSChris Mason 	if (misc_deregister(&btrfs_misc) < 0)
723d397712bSChris Mason 		printk(KERN_INFO "misc_deregister failed for control device");
724a9218f6bSChris Mason }
725a9218f6bSChris Mason 
7262e635a27SChris Mason static int __init init_btrfs_fs(void)
7272e635a27SChris Mason {
7282c90e5d6SChris Mason 	int err;
72958176a96SJosef Bacik 
73058176a96SJosef Bacik 	err = btrfs_init_sysfs();
73158176a96SJosef Bacik 	if (err)
73258176a96SJosef Bacik 		return err;
73358176a96SJosef Bacik 
73439279cc3SChris Mason 	err = btrfs_init_cachep();
7352c90e5d6SChris Mason 	if (err)
736a74a4b97SChris Mason 		goto free_sysfs;
737d1310b2eSChris Mason 
738d1310b2eSChris Mason 	err = extent_io_init();
7392f4cbe64SWyatt Banks 	if (err)
7402f4cbe64SWyatt Banks 		goto free_cachep;
7412f4cbe64SWyatt Banks 
742d1310b2eSChris Mason 	err = extent_map_init();
743d1310b2eSChris Mason 	if (err)
744d1310b2eSChris Mason 		goto free_extent_io;
745d1310b2eSChris Mason 
746a9218f6bSChris Mason 	err = btrfs_interface_init();
7472f4cbe64SWyatt Banks 	if (err)
7482f4cbe64SWyatt Banks 		goto free_extent_map;
749c8b97818SChris Mason 
750a9218f6bSChris Mason 	err = register_filesystem(&btrfs_fs_type);
751a9218f6bSChris Mason 	if (err)
752a9218f6bSChris Mason 		goto unregister_ioctl;
753b3c3da71SChris Mason 
754b3c3da71SChris Mason 	printk(KERN_INFO "%s loaded\n", BTRFS_BUILD_VERSION);
7552f4cbe64SWyatt Banks 	return 0;
7562f4cbe64SWyatt Banks 
757a9218f6bSChris Mason unregister_ioctl:
758a9218f6bSChris Mason 	btrfs_interface_exit();
7592f4cbe64SWyatt Banks free_extent_map:
7602f4cbe64SWyatt Banks 	extent_map_exit();
761d1310b2eSChris Mason free_extent_io:
762d1310b2eSChris Mason 	extent_io_exit();
7632f4cbe64SWyatt Banks free_cachep:
7642f4cbe64SWyatt Banks 	btrfs_destroy_cachep();
765a74a4b97SChris Mason free_sysfs:
7662f4cbe64SWyatt Banks 	btrfs_exit_sysfs();
7672c90e5d6SChris Mason 	return err;
7682e635a27SChris Mason }
7692e635a27SChris Mason 
7702e635a27SChris Mason static void __exit exit_btrfs_fs(void)
7712e635a27SChris Mason {
77239279cc3SChris Mason 	btrfs_destroy_cachep();
773a52d9a80SChris Mason 	extent_map_exit();
774d1310b2eSChris Mason 	extent_io_exit();
775a9218f6bSChris Mason 	btrfs_interface_exit();
7762e635a27SChris Mason 	unregister_filesystem(&btrfs_fs_type);
77758176a96SJosef Bacik 	btrfs_exit_sysfs();
7788a4b83ccSChris Mason 	btrfs_cleanup_fs_uuids();
779c8b97818SChris Mason 	btrfs_zlib_exit();
7802e635a27SChris Mason }
7812e635a27SChris Mason 
7822e635a27SChris Mason module_init(init_btrfs_fs)
7832e635a27SChris Mason module_exit(exit_btrfs_fs)
7842e635a27SChris Mason 
7852e635a27SChris Mason MODULE_LICENSE("GPL");
786