diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-11-19 15:59:28 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-11-19 15:59:28 -0500 |
commit | ae20a6afec1cf21919d97303f2d8b737eac5acc7 (patch) | |
tree | a4ddf02d4f19bdee1119dcc8a0f54edb40fb5986 /fs/btrfs/super.c | |
parent | 9bf1a2445f3c569098b8de7097ca324e65abecc2 (diff) | |
parent | 07103a3cdb24099324a11be1f35279b463cdfc31 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 713 |
1 files changed, 713 insertions, 0 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c new file mode 100644 index 000000000000..77c5eff3e209 --- /dev/null +++ b/fs/btrfs/super.c | |||
@@ -0,0 +1,713 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 Oracle. All rights reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public | ||
6 | * License v2 as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
11 | * General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public | ||
14 | * License along with this program; if not, write to the | ||
15 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
16 | * Boston, MA 021110-1307, USA. | ||
17 | */ | ||
18 | |||
19 | #include <linux/blkdev.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/buffer_head.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/pagemap.h> | ||
24 | #include <linux/highmem.h> | ||
25 | #include <linux/time.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/smp_lock.h> | ||
29 | #include <linux/backing-dev.h> | ||
30 | #include <linux/mount.h> | ||
31 | #include <linux/mpage.h> | ||
32 | #include <linux/swap.h> | ||
33 | #include <linux/writeback.h> | ||
34 | #include <linux/statfs.h> | ||
35 | #include <linux/compat.h> | ||
36 | #include <linux/parser.h> | ||
37 | #include <linux/ctype.h> | ||
38 | #include <linux/namei.h> | ||
39 | #include <linux/miscdevice.h> | ||
40 | #include "ctree.h" | ||
41 | #include "disk-io.h" | ||
42 | #include "transaction.h" | ||
43 | #include "btrfs_inode.h" | ||
44 | #include "ioctl.h" | ||
45 | #include "print-tree.h" | ||
46 | #include "xattr.h" | ||
47 | #include "volumes.h" | ||
48 | #include "version.h" | ||
49 | #include "export.h" | ||
50 | #include "compression.h" | ||
51 | |||
52 | #define BTRFS_SUPER_MAGIC 0x9123683E | ||
53 | |||
54 | static struct super_operations btrfs_super_ops; | ||
55 | |||
56 | static void btrfs_put_super (struct super_block * sb) | ||
57 | { | ||
58 | struct btrfs_root *root = btrfs_sb(sb); | ||
59 | struct btrfs_fs_info *fs = root->fs_info; | ||
60 | int ret; | ||
61 | |||
62 | ret = close_ctree(root); | ||
63 | if (ret) { | ||
64 | printk("close ctree returns %d\n", ret); | ||
65 | } | ||
66 | btrfs_sysfs_del_super(fs); | ||
67 | sb->s_fs_info = NULL; | ||
68 | } | ||
69 | |||
70 | enum { | ||
71 | Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow, | ||
72 | Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, | ||
73 | Opt_ssd, Opt_thread_pool, Opt_noacl, Opt_compress, Opt_err, | ||
74 | }; | ||
75 | |||
76 | static match_table_t tokens = { | ||
77 | {Opt_degraded, "degraded"}, | ||
78 | {Opt_subvol, "subvol=%s"}, | ||
79 | {Opt_device, "device=%s"}, | ||
80 | {Opt_nodatasum, "nodatasum"}, | ||
81 | {Opt_nodatacow, "nodatacow"}, | ||
82 | {Opt_nobarrier, "nobarrier"}, | ||
83 | {Opt_max_extent, "max_extent=%s"}, | ||
84 | {Opt_max_inline, "max_inline=%s"}, | ||
85 | {Opt_alloc_start, "alloc_start=%s"}, | ||
86 | {Opt_thread_pool, "thread_pool=%d"}, | ||
87 | {Opt_compress, "compress"}, | ||
88 | {Opt_ssd, "ssd"}, | ||
89 | {Opt_noacl, "noacl"}, | ||
90 | {Opt_err, NULL}, | ||
91 | }; | ||
92 | |||
93 | u64 btrfs_parse_size(char *str) | ||
94 | { | ||
95 | u64 res; | ||
96 | int mult = 1; | ||
97 | char *end; | ||
98 | char last; | ||
99 | |||
100 | res = simple_strtoul(str, &end, 10); | ||
101 | |||
102 | last = end[0]; | ||
103 | if (isalpha(last)) { | ||
104 | last = tolower(last); | ||
105 | switch (last) { | ||
106 | case 'g': | ||
107 | mult *= 1024; | ||
108 | case 'm': | ||
109 | mult *= 1024; | ||
110 | case 'k': | ||
111 | mult *= 1024; | ||
112 | } | ||
113 | res = res * mult; | ||
114 | } | ||
115 | return res; | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Regular mount options parser. Everything that is needed only when | ||
120 | * reading in a new superblock is parsed here. | ||
121 | */ | ||
122 | int btrfs_parse_options(struct btrfs_root *root, char *options) | ||
123 | { | ||
124 | struct btrfs_fs_info *info = root->fs_info; | ||
125 | substring_t args[MAX_OPT_ARGS]; | ||
126 | char *p, *num; | ||
127 | int intarg; | ||
128 | |||
129 | if (!options) | ||
130 | return 0; | ||
131 | |||
132 | /* | ||
133 | * strsep changes the string, duplicate it because parse_options | ||
134 | * gets called twice | ||
135 | */ | ||
136 | options = kstrdup(options, GFP_NOFS); | ||
137 | if (!options) | ||
138 | return -ENOMEM; | ||
139 | |||
140 | |||
141 | while ((p = strsep(&options, ",")) != NULL) { | ||
142 | int token; | ||
143 | if (!*p) | ||
144 | continue; | ||
145 | |||
146 | token = match_token(p, tokens, args); | ||
147 | switch (token) { | ||
148 | case Opt_degraded: | ||
149 | printk(KERN_INFO "btrfs: allowing degraded mounts\n"); | ||
150 | btrfs_set_opt(info->mount_opt, DEGRADED); | ||
151 | break; | ||
152 | case Opt_subvol: | ||
153 | case Opt_device: | ||
154 | /* | ||
155 | * These are parsed by btrfs_parse_early_options | ||
156 | * and can be happily ignored here. | ||
157 | */ | ||
158 | break; | ||
159 | case Opt_nodatasum: | ||
160 | printk(KERN_INFO "btrfs: setting nodatacsum\n"); | ||
161 | btrfs_set_opt(info->mount_opt, NODATASUM); | ||
162 | break; | ||
163 | case Opt_nodatacow: | ||
164 | printk(KERN_INFO "btrfs: setting nodatacow\n"); | ||
165 | btrfs_set_opt(info->mount_opt, NODATACOW); | ||
166 | btrfs_set_opt(info->mount_opt, NODATASUM); | ||
167 | break; | ||
168 | case Opt_compress: | ||
169 | printk(KERN_INFO "btrfs: use compression\n"); | ||
170 | btrfs_set_opt(info->mount_opt, COMPRESS); | ||
171 | break; | ||
172 | case Opt_ssd: | ||
173 | printk(KERN_INFO "btrfs: use ssd allocation scheme\n"); | ||
174 | btrfs_set_opt(info->mount_opt, SSD); | ||
175 | break; | ||
176 | case Opt_nobarrier: | ||
177 | printk(KERN_INFO "btrfs: turning off barriers\n"); | ||
178 | btrfs_set_opt(info->mount_opt, NOBARRIER); | ||
179 | break; | ||
180 | case Opt_thread_pool: | ||
181 | intarg = 0; | ||
182 | match_int(&args[0], &intarg); | ||
183 | if (intarg) { | ||
184 | info->thread_pool_size = intarg; | ||
185 | printk(KERN_INFO "btrfs: thread pool %d\n", | ||
186 | info->thread_pool_size); | ||
187 | } | ||
188 | break; | ||
189 | case Opt_max_extent: | ||
190 | num = match_strdup(&args[0]); | ||
191 | if (num) { | ||
192 | info->max_extent = btrfs_parse_size(num); | ||
193 | kfree(num); | ||
194 | |||
195 | info->max_extent = max_t(u64, | ||
196 | info->max_extent, root->sectorsize); | ||
197 | printk(KERN_INFO "btrfs: max_extent at %llu\n", | ||
198 | info->max_extent); | ||
199 | } | ||
200 | break; | ||
201 | case Opt_max_inline: | ||
202 | num = match_strdup(&args[0]); | ||
203 | if (num) { | ||
204 | info->max_inline = btrfs_parse_size(num); | ||
205 | kfree(num); | ||
206 | |||
207 | if (info->max_inline) { | ||
208 | info->max_inline = max_t(u64, | ||
209 | info->max_inline, | ||
210 | root->sectorsize); | ||
211 | } | ||
212 | printk(KERN_INFO "btrfs: max_inline at %llu\n", | ||
213 | info->max_inline); | ||
214 | } | ||
215 | break; | ||
216 | case Opt_alloc_start: | ||
217 | num = match_strdup(&args[0]); | ||
218 | if (num) { | ||
219 | info->alloc_start = btrfs_parse_size(num); | ||
220 | kfree(num); | ||
221 | printk(KERN_INFO | ||
222 | "btrfs: allocations start at %llu\n", | ||
223 | info->alloc_start); | ||
224 | } | ||
225 | break; | ||
226 | case Opt_noacl: | ||
227 | root->fs_info->sb->s_flags &= ~MS_POSIXACL; | ||
228 | break; | ||
229 | default: | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | kfree(options); | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | /* | ||
238 | * Parse mount options that are required early in the mount process. | ||
239 | * | ||
240 | * All other options will be parsed on much later in the mount process and | ||
241 | * only when we need to allocate a new super block. | ||
242 | */ | ||
243 | static int btrfs_parse_early_options(const char *options, int flags, | ||
244 | void *holder, char **subvol_name, | ||
245 | struct btrfs_fs_devices **fs_devices) | ||
246 | { | ||
247 | substring_t args[MAX_OPT_ARGS]; | ||
248 | char *opts, *p; | ||
249 | int error = 0; | ||
250 | |||
251 | if (!options) | ||
252 | goto out; | ||
253 | |||
254 | /* | ||
255 | * strsep changes the string, duplicate it because parse_options | ||
256 | * gets called twice | ||
257 | */ | ||
258 | opts = kstrdup(options, GFP_KERNEL); | ||
259 | if (!opts) | ||
260 | return -ENOMEM; | ||
261 | |||
262 | while ((p = strsep(&opts, ",")) != NULL) { | ||
263 | int token; | ||
264 | if (!*p) | ||
265 | continue; | ||
266 | |||
267 | token = match_token(p, tokens, args); | ||
268 | switch (token) { | ||
269 | case Opt_subvol: | ||
270 | *subvol_name = match_strdup(&args[0]); | ||
271 | break; | ||
272 | case Opt_device: | ||
273 | error = btrfs_scan_one_device(match_strdup(&args[0]), | ||
274 | flags, holder, fs_devices); | ||
275 | if (error) | ||
276 | goto out_free_opts; | ||
277 | break; | ||
278 | default: | ||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | out_free_opts: | ||
284 | kfree(opts); | ||
285 | out: | ||
286 | /* | ||
287 | * If no subvolume name is specified we use the default one. Allocate | ||
288 | * a copy of the string "." here so that code later in the | ||
289 | * mount path doesn't care if it's the default volume or another one. | ||
290 | */ | ||
291 | if (!*subvol_name) { | ||
292 | *subvol_name = kstrdup(".", GFP_KERNEL); | ||
293 | if (!*subvol_name) | ||
294 | return -ENOMEM; | ||
295 | } | ||
296 | return error; | ||
297 | } | ||
298 | |||
299 | static int btrfs_fill_super(struct super_block * sb, | ||
300 | struct btrfs_fs_devices *fs_devices, | ||
301 | void * data, int silent) | ||
302 | { | ||
303 | struct inode * inode; | ||
304 | struct dentry * root_dentry; | ||
305 | struct btrfs_super_block *disk_super; | ||
306 | struct btrfs_root *tree_root; | ||
307 | struct btrfs_inode *bi; | ||
308 | int err; | ||
309 | |||
310 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
311 | sb->s_magic = BTRFS_SUPER_MAGIC; | ||
312 | sb->s_op = &btrfs_super_ops; | ||
313 | sb->s_export_op = &btrfs_export_ops; | ||
314 | sb->s_xattr = btrfs_xattr_handlers; | ||
315 | sb->s_time_gran = 1; | ||
316 | sb->s_flags |= MS_POSIXACL; | ||
317 | |||
318 | tree_root = open_ctree(sb, fs_devices, (char *)data); | ||
319 | |||
320 | if (IS_ERR(tree_root)) { | ||
321 | printk("btrfs: open_ctree failed\n"); | ||
322 | return PTR_ERR(tree_root); | ||
323 | } | ||
324 | sb->s_fs_info = tree_root; | ||
325 | disk_super = &tree_root->fs_info->super_copy; | ||
326 | inode = btrfs_iget_locked(sb, BTRFS_FIRST_FREE_OBJECTID, | ||
327 | tree_root->fs_info->fs_root); | ||
328 | bi = BTRFS_I(inode); | ||
329 | bi->location.objectid = inode->i_ino; | ||
330 | bi->location.offset = 0; | ||
331 | bi->root = tree_root->fs_info->fs_root; | ||
332 | |||
333 | btrfs_set_key_type(&bi->location, BTRFS_INODE_ITEM_KEY); | ||
334 | |||
335 | if (!inode) { | ||
336 | err = -ENOMEM; | ||
337 | goto fail_close; | ||
338 | } | ||
339 | if (inode->i_state & I_NEW) { | ||
340 | btrfs_read_locked_inode(inode); | ||
341 | unlock_new_inode(inode); | ||
342 | } | ||
343 | |||
344 | root_dentry = d_alloc_root(inode); | ||
345 | if (!root_dentry) { | ||
346 | iput(inode); | ||
347 | err = -ENOMEM; | ||
348 | goto fail_close; | ||
349 | } | ||
350 | |||
351 | /* this does the super kobj at the same time */ | ||
352 | err = btrfs_sysfs_add_super(tree_root->fs_info); | ||
353 | if (err) | ||
354 | goto fail_close; | ||
355 | |||
356 | sb->s_root = root_dentry; | ||
357 | |||
358 | save_mount_options(sb, data); | ||
359 | return 0; | ||
360 | |||
361 | fail_close: | ||
362 | close_ctree(tree_root); | ||
363 | return err; | ||
364 | } | ||
365 | |||
366 | int btrfs_sync_fs(struct super_block *sb, int wait) | ||
367 | { | ||
368 | struct btrfs_trans_handle *trans; | ||
369 | struct btrfs_root *root; | ||
370 | int ret; | ||
371 | root = btrfs_sb(sb); | ||
372 | |||
373 | if (sb->s_flags & MS_RDONLY) | ||
374 | return 0; | ||
375 | |||
376 | sb->s_dirt = 0; | ||
377 | if (!wait) { | ||
378 | filemap_flush(root->fs_info->btree_inode->i_mapping); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | btrfs_start_delalloc_inodes(root); | ||
383 | btrfs_wait_ordered_extents(root, 0); | ||
384 | |||
385 | btrfs_clean_old_snapshots(root); | ||
386 | trans = btrfs_start_transaction(root, 1); | ||
387 | ret = btrfs_commit_transaction(trans, root); | ||
388 | sb->s_dirt = 0; | ||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | static void btrfs_write_super(struct super_block *sb) | ||
393 | { | ||
394 | sb->s_dirt = 0; | ||
395 | } | ||
396 | |||
397 | static int btrfs_test_super(struct super_block *s, void *data) | ||
398 | { | ||
399 | struct btrfs_fs_devices *test_fs_devices = data; | ||
400 | struct btrfs_root *root = btrfs_sb(s); | ||
401 | |||
402 | return root->fs_info->fs_devices == test_fs_devices; | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | * Find a superblock for the given device / mount point. | ||
407 | * | ||
408 | * Note: This is based on get_sb_bdev from fs/super.c with a few additions | ||
409 | * for multiple device setup. Make sure to keep it in sync. | ||
410 | */ | ||
411 | static int btrfs_get_sb(struct file_system_type *fs_type, int flags, | ||
412 | const char *dev_name, void *data, struct vfsmount *mnt) | ||
413 | { | ||
414 | char *subvol_name = NULL; | ||
415 | struct block_device *bdev = NULL; | ||
416 | struct super_block *s; | ||
417 | struct dentry *root; | ||
418 | struct btrfs_fs_devices *fs_devices = NULL; | ||
419 | int error = 0; | ||
420 | |||
421 | error = btrfs_parse_early_options(data, flags, fs_type, | ||
422 | &subvol_name, &fs_devices); | ||
423 | if (error) | ||
424 | goto error; | ||
425 | |||
426 | error = btrfs_scan_one_device(dev_name, flags, fs_type, &fs_devices); | ||
427 | if (error) | ||
428 | goto error_free_subvol_name; | ||
429 | |||
430 | error = btrfs_open_devices(fs_devices, flags, fs_type); | ||
431 | if (error) | ||
432 | goto error_free_subvol_name; | ||
433 | |||
434 | if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) { | ||
435 | error = -EACCES; | ||
436 | goto error_close_devices; | ||
437 | } | ||
438 | |||
439 | bdev = fs_devices->latest_bdev; | ||
440 | s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices); | ||
441 | if (IS_ERR(s)) | ||
442 | goto error_s; | ||
443 | |||
444 | if (s->s_root) { | ||
445 | if ((flags ^ s->s_flags) & MS_RDONLY) { | ||
446 | up_write(&s->s_umount); | ||
447 | deactivate_super(s); | ||
448 | error = -EBUSY; | ||
449 | goto error_close_devices; | ||
450 | } | ||
451 | |||
452 | btrfs_close_devices(fs_devices); | ||
453 | } else { | ||
454 | char b[BDEVNAME_SIZE]; | ||
455 | |||
456 | s->s_flags = flags; | ||
457 | strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); | ||
458 | error = btrfs_fill_super(s, fs_devices, data, | ||
459 | flags & MS_SILENT ? 1 : 0); | ||
460 | if (error) { | ||
461 | up_write(&s->s_umount); | ||
462 | deactivate_super(s); | ||
463 | goto error; | ||
464 | } | ||
465 | |||
466 | btrfs_sb(s)->fs_info->bdev_holder = fs_type; | ||
467 | s->s_flags |= MS_ACTIVE; | ||
468 | } | ||
469 | |||
470 | if (!strcmp(subvol_name, ".")) | ||
471 | root = dget(s->s_root); | ||
472 | else { | ||
473 | mutex_lock(&s->s_root->d_inode->i_mutex); | ||
474 | root = lookup_one_len(subvol_name, s->s_root, strlen(subvol_name)); | ||
475 | mutex_unlock(&s->s_root->d_inode->i_mutex); | ||
476 | if (IS_ERR(root)) { | ||
477 | up_write(&s->s_umount); | ||
478 | deactivate_super(s); | ||
479 | error = PTR_ERR(root); | ||
480 | goto error; | ||
481 | } | ||
482 | if (!root->d_inode) { | ||
483 | dput(root); | ||
484 | up_write(&s->s_umount); | ||
485 | deactivate_super(s); | ||
486 | error = -ENXIO; | ||
487 | goto error; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | mnt->mnt_sb = s; | ||
492 | mnt->mnt_root = root; | ||
493 | |||
494 | kfree(subvol_name); | ||
495 | return 0; | ||
496 | |||
497 | error_s: | ||
498 | error = PTR_ERR(s); | ||
499 | error_close_devices: | ||
500 | btrfs_close_devices(fs_devices); | ||
501 | error_free_subvol_name: | ||
502 | kfree(subvol_name); | ||
503 | error: | ||
504 | return error; | ||
505 | } | ||
506 | |||
507 | static int btrfs_remount(struct super_block *sb, int *flags, char *data) | ||
508 | { | ||
509 | struct btrfs_root *root = btrfs_sb(sb); | ||
510 | int ret; | ||
511 | |||
512 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) | ||
513 | return 0; | ||
514 | |||
515 | if (*flags & MS_RDONLY) { | ||
516 | sb->s_flags |= MS_RDONLY; | ||
517 | |||
518 | ret = btrfs_commit_super(root); | ||
519 | WARN_ON(ret); | ||
520 | } else { | ||
521 | if (root->fs_info->fs_devices->rw_devices == 0) | ||
522 | return -EACCES; | ||
523 | |||
524 | if (btrfs_super_log_root(&root->fs_info->super_copy) != 0) | ||
525 | return -EINVAL; | ||
526 | |||
527 | ret = btrfs_cleanup_reloc_trees(root); | ||
528 | WARN_ON(ret); | ||
529 | |||
530 | ret = btrfs_cleanup_fs_roots(root->fs_info); | ||
531 | WARN_ON(ret); | ||
532 | |||
533 | sb->s_flags &= ~MS_RDONLY; | ||
534 | } | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) | ||
540 | { | ||
541 | struct btrfs_root *root = btrfs_sb(dentry->d_sb); | ||
542 | struct btrfs_super_block *disk_super = &root->fs_info->super_copy; | ||
543 | int bits = dentry->d_sb->s_blocksize_bits; | ||
544 | __be32 *fsid = (__be32 *)root->fs_info->fsid; | ||
545 | |||
546 | buf->f_namelen = BTRFS_NAME_LEN; | ||
547 | buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; | ||
548 | buf->f_bfree = buf->f_blocks - | ||
549 | (btrfs_super_bytes_used(disk_super) >> bits); | ||
550 | buf->f_bavail = buf->f_bfree; | ||
551 | buf->f_bsize = dentry->d_sb->s_blocksize; | ||
552 | buf->f_type = BTRFS_SUPER_MAGIC; | ||
553 | /* We treat it as constant endianness (it doesn't matter _which_) | ||
554 | because we want the fsid to come out the same whether mounted | ||
555 | on a big-endian or little-endian host */ | ||
556 | buf->f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]); | ||
557 | buf->f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]); | ||
558 | /* Mask in the root object ID too, to disambiguate subvols */ | ||
559 | buf->f_fsid.val[0] ^= BTRFS_I(dentry->d_inode)->root->objectid >> 32; | ||
560 | buf->f_fsid.val[1] ^= BTRFS_I(dentry->d_inode)->root->objectid; | ||
561 | |||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | static struct file_system_type btrfs_fs_type = { | ||
566 | .owner = THIS_MODULE, | ||
567 | .name = "btrfs", | ||
568 | .get_sb = btrfs_get_sb, | ||
569 | .kill_sb = kill_anon_super, | ||
570 | .fs_flags = FS_REQUIRES_DEV, | ||
571 | }; | ||
572 | |||
573 | /* | ||
574 | * used by btrfsctl to scan devices when no FS is mounted | ||
575 | */ | ||
576 | static long btrfs_control_ioctl(struct file *file, unsigned int cmd, | ||
577 | unsigned long arg) | ||
578 | { | ||
579 | struct btrfs_ioctl_vol_args *vol; | ||
580 | struct btrfs_fs_devices *fs_devices; | ||
581 | int ret = 0; | ||
582 | int len; | ||
583 | |||
584 | vol = kmalloc(sizeof(*vol), GFP_KERNEL); | ||
585 | if (copy_from_user(vol, (void __user *)arg, sizeof(*vol))) { | ||
586 | ret = -EFAULT; | ||
587 | goto out; | ||
588 | } | ||
589 | len = strnlen(vol->name, BTRFS_PATH_NAME_MAX); | ||
590 | switch (cmd) { | ||
591 | case BTRFS_IOC_SCAN_DEV: | ||
592 | ret = btrfs_scan_one_device(vol->name, MS_RDONLY, | ||
593 | &btrfs_fs_type, &fs_devices); | ||
594 | break; | ||
595 | } | ||
596 | out: | ||
597 | kfree(vol); | ||
598 | return ret; | ||
599 | } | ||
600 | |||
601 | static void btrfs_write_super_lockfs(struct super_block *sb) | ||
602 | { | ||
603 | struct btrfs_root *root = btrfs_sb(sb); | ||
604 | mutex_lock(&root->fs_info->transaction_kthread_mutex); | ||
605 | mutex_lock(&root->fs_info->cleaner_mutex); | ||
606 | } | ||
607 | |||
608 | static void btrfs_unlockfs(struct super_block *sb) | ||
609 | { | ||
610 | struct btrfs_root *root = btrfs_sb(sb); | ||
611 | mutex_unlock(&root->fs_info->cleaner_mutex); | ||
612 | mutex_unlock(&root->fs_info->transaction_kthread_mutex); | ||
613 | } | ||
614 | |||
615 | static struct super_operations btrfs_super_ops = { | ||
616 | .delete_inode = btrfs_delete_inode, | ||
617 | .put_super = btrfs_put_super, | ||
618 | .write_super = btrfs_write_super, | ||
619 | .sync_fs = btrfs_sync_fs, | ||
620 | .show_options = generic_show_options, | ||
621 | .write_inode = btrfs_write_inode, | ||
622 | .dirty_inode = btrfs_dirty_inode, | ||
623 | .alloc_inode = btrfs_alloc_inode, | ||
624 | .destroy_inode = btrfs_destroy_inode, | ||
625 | .statfs = btrfs_statfs, | ||
626 | .remount_fs = btrfs_remount, | ||
627 | .write_super_lockfs = btrfs_write_super_lockfs, | ||
628 | .unlockfs = btrfs_unlockfs, | ||
629 | }; | ||
630 | |||
631 | static const struct file_operations btrfs_ctl_fops = { | ||
632 | .unlocked_ioctl = btrfs_control_ioctl, | ||
633 | .compat_ioctl = btrfs_control_ioctl, | ||
634 | .owner = THIS_MODULE, | ||
635 | }; | ||
636 | |||
637 | static struct miscdevice btrfs_misc = { | ||
638 | .minor = MISC_DYNAMIC_MINOR, | ||
639 | .name = "btrfs-control", | ||
640 | .fops = &btrfs_ctl_fops | ||
641 | }; | ||
642 | |||
643 | static int btrfs_interface_init(void) | ||
644 | { | ||
645 | return misc_register(&btrfs_misc); | ||
646 | } | ||
647 | |||
648 | void btrfs_interface_exit(void) | ||
649 | { | ||
650 | if (misc_deregister(&btrfs_misc) < 0) | ||
651 | printk("misc_deregister failed for control device"); | ||
652 | } | ||
653 | |||
654 | static int __init init_btrfs_fs(void) | ||
655 | { | ||
656 | int err; | ||
657 | |||
658 | err = btrfs_init_sysfs(); | ||
659 | if (err) | ||
660 | return err; | ||
661 | |||
662 | err = btrfs_init_cachep(); | ||
663 | if (err) | ||
664 | goto free_sysfs; | ||
665 | |||
666 | err = extent_io_init(); | ||
667 | if (err) | ||
668 | goto free_cachep; | ||
669 | |||
670 | err = extent_map_init(); | ||
671 | if (err) | ||
672 | goto free_extent_io; | ||
673 | |||
674 | err = btrfs_interface_init(); | ||
675 | if (err) | ||
676 | goto free_extent_map; | ||
677 | |||
678 | err = register_filesystem(&btrfs_fs_type); | ||
679 | if (err) | ||
680 | goto unregister_ioctl; | ||
681 | |||
682 | printk(KERN_INFO "%s loaded\n", BTRFS_BUILD_VERSION); | ||
683 | return 0; | ||
684 | |||
685 | unregister_ioctl: | ||
686 | btrfs_interface_exit(); | ||
687 | free_extent_map: | ||
688 | extent_map_exit(); | ||
689 | free_extent_io: | ||
690 | extent_io_exit(); | ||
691 | free_cachep: | ||
692 | btrfs_destroy_cachep(); | ||
693 | free_sysfs: | ||
694 | btrfs_exit_sysfs(); | ||
695 | return err; | ||
696 | } | ||
697 | |||
698 | static void __exit exit_btrfs_fs(void) | ||
699 | { | ||
700 | btrfs_destroy_cachep(); | ||
701 | extent_map_exit(); | ||
702 | extent_io_exit(); | ||
703 | btrfs_interface_exit(); | ||
704 | unregister_filesystem(&btrfs_fs_type); | ||
705 | btrfs_exit_sysfs(); | ||
706 | btrfs_cleanup_fs_uuids(); | ||
707 | btrfs_zlib_exit(); | ||
708 | } | ||
709 | |||
710 | module_init(init_btrfs_fs) | ||
711 | module_exit(exit_btrfs_fs) | ||
712 | |||
713 | MODULE_LICENSE("GPL"); | ||