super.c 9.2 KB
Newer Older
C
Chris Mason 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * 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.
 */

Y
Yan 已提交
19
#include <linux/blkdev.h>
20
#include <linux/module.h>
C
Chris Mason 已提交
21
#include <linux/buffer_head.h>
22 23 24 25 26 27 28 29
#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>
Y
Yan 已提交
30
#include <linux/mount.h>
C
Chris Mason 已提交
31
#include <linux/mpage.h>
C
Chris Mason 已提交
32 33
#include <linux/swap.h>
#include <linux/writeback.h>
C
Chris Mason 已提交
34
#include <linux/statfs.h>
C
Chris Mason 已提交
35
#include <linux/compat.h>
36
#include <linux/parser.h>
37
#include "ctree.h"
C
Chris Mason 已提交
38
#include "disk-io.h"
39
#include "transaction.h"
C
Chris Mason 已提交
40
#include "btrfs_inode.h"
C
Chris Mason 已提交
41
#include "ioctl.h"
C
Chris Mason 已提交
42
#include "print-tree.h"
J
Josef Bacik 已提交
43
#include "xattr.h"
44

45
#define BTRFS_SUPER_MAGIC 0x9123683E
C
Chris Mason 已提交
46

C
Chris Mason 已提交
47
static struct super_operations btrfs_super_ops;
C
Chris Mason 已提交
48

C
Chris Mason 已提交
49
static void btrfs_put_super (struct super_block * sb)
C
Chris Mason 已提交
50
{
C
Chris Mason 已提交
51
	struct btrfs_root *root = btrfs_sb(sb);
52
	struct btrfs_fs_info *fs = root->fs_info;
C
Chris Mason 已提交
53 54
	int ret;

C
Chris Mason 已提交
55 56 57
	ret = close_ctree(root);
	if (ret) {
		printk("close ctree returns %d\n", ret);
C
Chris Mason 已提交
58
	}
59
	btrfs_sysfs_del_super(fs);
C
Chris Mason 已提交
60
	sb->s_fs_info = NULL;
C
Chris Mason 已提交
61 62
}

63
enum {
64
	Opt_subvol, Opt_nodatasum, Opt_nodatacow, Opt_err,
65 66 67 68
};

static match_table_t tokens = {
	{Opt_subvol, "subvol=%s"},
69
	{Opt_nodatasum, "nodatasum"},
70
	{Opt_nodatacow, "nodatacow"},
71 72 73 74 75 76 77 78
	{Opt_err, NULL}
};

static int parse_options (char * options,
			  struct btrfs_root *root,
			  char **subvol_name)
{
	char * p;
79
	struct btrfs_fs_info *info = NULL;
80
	substring_t args[MAX_OPT_ARGS];
81

82 83 84
	if (!options)
		return 1;

85 86 87 88 89 90 91 92 93 94 95
	/*
	 * strsep changes the string, duplicate it because parse_options
	 * gets called twice
	 */
	options = kstrdup(options, GFP_NOFS);
	if (!options)
		return -ENOMEM;

	if (root)
		info = root->fs_info;

96 97 98 99 100 101 102 103
	while ((p = strsep (&options, ",")) != NULL) {
		int token;
		if (!*p)
			continue;

		token = match_token(p, tokens, args);
		switch (token) {
		case Opt_subvol:
104
			if (subvol_name) {
105
				*subvol_name = match_strdup(&args[0]);
106
			}
107 108
			break;
		case Opt_nodatasum:
109 110
			if (info) {
				printk("btrfs: setting nodatacsum\n");
111
				btrfs_set_opt(info->mount_opt, NODATASUM);
112 113 114 115 116 117 118 119
			}
			break;
		case Opt_nodatacow:
			if (info) {
				printk("btrfs: setting nodatacow\n");
				btrfs_set_opt(info->mount_opt, NODATACOW);
				btrfs_set_opt(info->mount_opt, NODATASUM);
			}
120 121
			break;
		default:
122
			break;
123 124
		}
	}
125
	kfree(options);
126 127 128
	return 1;
}

C
Chris Mason 已提交
129
static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
C
Chris Mason 已提交
130
{
C
Chris Mason 已提交
131 132 133 134 135 136
	struct inode * inode;
	struct dentry * root_dentry;
	struct btrfs_super_block *disk_super;
	struct btrfs_root *tree_root;
	struct btrfs_inode *bi;
	int err;
137

C
Chris Mason 已提交
138 139 140
	sb->s_maxbytes = MAX_LFS_FILESIZE;
	sb->s_magic = BTRFS_SUPER_MAGIC;
	sb->s_op = &btrfs_super_ops;
J
Josef Bacik 已提交
141
	sb->s_xattr = btrfs_xattr_handlers;
C
Chris Mason 已提交
142
	sb->s_time_gran = 1;
143

C
Chris Mason 已提交
144
	tree_root = open_ctree(sb);
145

C
Chris Mason 已提交
146 147 148
	if (!tree_root || IS_ERR(tree_root)) {
		printk("btrfs: open_ctree failed\n");
		return -EIO;
149
	}
C
Chris Mason 已提交
150
	sb->s_fs_info = tree_root;
151
	disk_super = &tree_root->fs_info->super_copy;
C
Chris Mason 已提交
152 153 154 155 156 157
	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;
158

C
Chris Mason 已提交
159
	btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY);
160

C
Chris Mason 已提交
161
	if (!inode) {
162
		err = -ENOMEM;
C
Chris Mason 已提交
163
		goto fail_close;
C
Chris Mason 已提交
164
	}
C
Chris Mason 已提交
165 166 167
	if (inode->i_state & I_NEW) {
		btrfs_read_locked_inode(inode);
		unlock_new_inode(inode);
C
Chris Mason 已提交
168 169
	}

C
Chris Mason 已提交
170 171 172 173 174
	root_dentry = d_alloc_root(inode);
	if (!root_dentry) {
		iput(inode);
		err = -ENOMEM;
		goto fail_close;
C
Chris Mason 已提交
175
	}
176

177 178
	parse_options((char *)data, tree_root, NULL);

179 180 181 182 183
	/* this does the super kobj at the same time */
	err = btrfs_sysfs_add_super(tree_root->fs_info);
	if (err)
		goto fail_close;

C
Chris Mason 已提交
184 185
	sb->s_root = root_dentry;
	btrfs_transaction_queue_work(tree_root, HZ * 30);
C
Chris Mason 已提交
186
	return 0;
C
Chris Mason 已提交
187 188 189 190

fail_close:
	close_ctree(tree_root);
	return err;
C
Chris Mason 已提交
191 192
}

C
Chris Mason 已提交
193
static int btrfs_sync_fs(struct super_block *sb, int wait)
C
Chris Mason 已提交
194 195
{
	struct btrfs_trans_handle *trans;
C
Chris Mason 已提交
196
	struct btrfs_root *root;
C
Chris Mason 已提交
197
	int ret;
C
Chris Mason 已提交
198
	root = btrfs_sb(sb);
C
Chris Mason 已提交
199

C
Chris Mason 已提交
200 201 202 203 204
	sb->s_dirt = 0;
	if (!wait) {
		filemap_flush(root->fs_info->btree_inode->i_mapping);
		return 0;
	}
205
	btrfs_clean_old_snapshots(root);
C
Chris Mason 已提交
206
	mutex_lock(&root->fs_info->fs_mutex);
207
	btrfs_defrag_dirty_roots(root->fs_info);
C
Chris Mason 已提交
208 209
	trans = btrfs_start_transaction(root, 1);
	ret = btrfs_commit_transaction(trans, root);
C
Chris Mason 已提交
210
	sb->s_dirt = 0;
C
Chris Mason 已提交
211
	mutex_unlock(&root->fs_info->fs_mutex);
212
	return ret;
C
Chris Mason 已提交
213 214
}

C
Chris Mason 已提交
215
static void btrfs_write_super(struct super_block *sb)
C
Chris Mason 已提交
216
{
C
Chris Mason 已提交
217
	sb->s_dirt = 0;
C
Chris Mason 已提交
218 219
}

Y
Yan 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321
/*
 * 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 */

322
static int btrfs_get_sb(struct file_system_type *fs_type,
323
	int flags, const char *dev_name, void *data, struct vfsmount *mnt)
324
{
Y
Yan 已提交
325
	int ret;
326
	char *subvol_name = NULL;
Y
Yan 已提交
327

328
	parse_options((char *)data, NULL, &subvol_name);
Y
Yan 已提交
329 330 331 332
	ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data,
			btrfs_fill_super, mnt,
			subvol_name ? subvol_name : "default");
	return ret;
333 334
}

C
Chris Mason 已提交
335 336 337
static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
	struct btrfs_root *root = btrfs_sb(dentry->d_sb);
338
	struct btrfs_super_block *disk_super = &root->fs_info->super_copy;
339
	int bits = dentry->d_sb->s_blocksize_bits;
C
Chris Mason 已提交
340 341

	buf->f_namelen = BTRFS_NAME_LEN;
342 343 344
	buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits;
	buf->f_bfree = buf->f_blocks -
		(btrfs_super_bytes_used(disk_super) >> bits);
C
Chris Mason 已提交
345 346 347 348 349
	buf->f_bavail = buf->f_bfree;
	buf->f_bsize = dentry->d_sb->s_blocksize;
	buf->f_type = BTRFS_SUPER_MAGIC;
	return 0;
}
C
Chris Mason 已提交
350

351 352 353 354 355 356 357 358
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,
};

C
Chris Mason 已提交
359
static struct super_operations btrfs_super_ops = {
C
Chris Mason 已提交
360
	.delete_inode	= btrfs_delete_inode,
C
Chris Mason 已提交
361 362
	.put_super	= btrfs_put_super,
	.read_inode	= btrfs_read_locked_inode,
363 364
	.write_super	= btrfs_write_super,
	.sync_fs	= btrfs_sync_fs,
C
Chris Mason 已提交
365
	.write_inode	= btrfs_write_inode,
C
Chris Mason 已提交
366
	.dirty_inode	= btrfs_dirty_inode,
C
Chris Mason 已提交
367 368
	.alloc_inode	= btrfs_alloc_inode,
	.destroy_inode	= btrfs_destroy_inode,
C
Chris Mason 已提交
369
	.statfs		= btrfs_statfs,
C
Chris Mason 已提交
370 371
};

372 373
static int __init init_btrfs_fs(void)
{
C
Chris Mason 已提交
374
	int err;
375 376 377 378 379

	err = btrfs_init_sysfs();
	if (err)
		return err;

C
Chris Mason 已提交
380
	btrfs_init_transaction_sys();
C
Chris Mason 已提交
381
	err = btrfs_init_cachep();
C
Chris Mason 已提交
382
	if (err)
383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
		goto free_transaction_sys;
	err = extent_map_init();
	if (err)
		goto free_cachep;

	err = register_filesystem(&btrfs_fs_type);
	if (err)
		goto free_extent_map;
	return 0;

free_extent_map:
	extent_map_exit();
free_cachep:
	btrfs_destroy_cachep();
free_transaction_sys:
	btrfs_exit_transaction_sys();
	btrfs_exit_sysfs();
	return err;
401 402 403 404
}

static void __exit exit_btrfs_fs(void)
{
C
Chris Mason 已提交
405
	btrfs_exit_transaction_sys();
C
Chris Mason 已提交
406
	btrfs_destroy_cachep();
407
	extent_map_exit();
408
	unregister_filesystem(&btrfs_fs_type);
409
	btrfs_exit_sysfs();
410 411 412 413 414 415
}

module_init(init_btrfs_fs)
module_exit(exit_btrfs_fs)

MODULE_LICENSE("GPL");