Root/
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/seq_file.h> |
28 | #include <linux/string.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 <linux/magic.h> |
41 | #include "compat.h" |
42 | #include "ctree.h" |
43 | #include "disk-io.h" |
44 | #include "transaction.h" |
45 | #include "btrfs_inode.h" |
46 | #include "ioctl.h" |
47 | #include "print-tree.h" |
48 | #include "xattr.h" |
49 | #include "volumes.h" |
50 | #include "version.h" |
51 | #include "export.h" |
52 | #include "compression.h" |
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 | int ret; |
60 | |
61 | ret = close_ctree(root); |
62 | sb->s_fs_info = NULL; |
63 | } |
64 | |
65 | enum { |
66 | Opt_degraded, Opt_subvol, Opt_device, Opt_nodatasum, Opt_nodatacow, |
67 | Opt_max_extent, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, |
68 | Opt_ssd, Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, |
69 | Opt_compress, Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_err, |
70 | }; |
71 | |
72 | static match_table_t tokens = { |
73 | {Opt_degraded, "degraded"}, |
74 | {Opt_subvol, "subvol=%s"}, |
75 | {Opt_device, "device=%s"}, |
76 | {Opt_nodatasum, "nodatasum"}, |
77 | {Opt_nodatacow, "nodatacow"}, |
78 | {Opt_nobarrier, "nobarrier"}, |
79 | {Opt_max_extent, "max_extent=%s"}, |
80 | {Opt_max_inline, "max_inline=%s"}, |
81 | {Opt_alloc_start, "alloc_start=%s"}, |
82 | {Opt_thread_pool, "thread_pool=%d"}, |
83 | {Opt_compress, "compress"}, |
84 | {Opt_ssd, "ssd"}, |
85 | {Opt_ssd_spread, "ssd_spread"}, |
86 | {Opt_nossd, "nossd"}, |
87 | {Opt_noacl, "noacl"}, |
88 | {Opt_notreelog, "notreelog"}, |
89 | {Opt_flushoncommit, "flushoncommit"}, |
90 | {Opt_ratio, "metadata_ratio=%d"}, |
91 | {Opt_err, NULL}, |
92 | }; |
93 | |
94 | u64 btrfs_parse_size(char *str) |
95 | { |
96 | u64 res; |
97 | int mult = 1; |
98 | char *end; |
99 | char last; |
100 | |
101 | res = simple_strtoul(str, &end, 10); |
102 | |
103 | last = end[0]; |
104 | if (isalpha(last)) { |
105 | last = tolower(last); |
106 | switch (last) { |
107 | case 'g': |
108 | mult *= 1024; |
109 | case 'm': |
110 | mult *= 1024; |
111 | case 'k': |
112 | mult *= 1024; |
113 | } |
114 | res = res * mult; |
115 | } |
116 | return res; |
117 | } |
118 | |
119 | /* |
120 | * Regular mount options parser. Everything that is needed only when |
121 | * reading in a new superblock is parsed here. |
122 | */ |
123 | int btrfs_parse_options(struct btrfs_root *root, char *options) |
124 | { |
125 | struct btrfs_fs_info *info = root->fs_info; |
126 | substring_t args[MAX_OPT_ARGS]; |
127 | char *p, *num; |
128 | int intarg; |
129 | |
130 | if (!options) |
131 | return 0; |
132 | |
133 | /* |
134 | * strsep changes the string, duplicate it because parse_options |
135 | * gets called twice |
136 | */ |
137 | options = kstrdup(options, GFP_NOFS); |
138 | if (!options) |
139 | return -ENOMEM; |
140 | |
141 | |
142 | while ((p = strsep(&options, ",")) != NULL) { |
143 | int token; |
144 | if (!*p) |
145 | continue; |
146 | |
147 | token = match_token(p, tokens, args); |
148 | switch (token) { |
149 | case Opt_degraded: |
150 | printk(KERN_INFO "btrfs: allowing degraded mounts\n"); |
151 | btrfs_set_opt(info->mount_opt, DEGRADED); |
152 | break; |
153 | case Opt_subvol: |
154 | case Opt_device: |
155 | /* |
156 | * These are parsed by btrfs_parse_early_options |
157 | * and can be happily ignored here. |
158 | */ |
159 | break; |
160 | case Opt_nodatasum: |
161 | printk(KERN_INFO "btrfs: setting nodatasum\n"); |
162 | btrfs_set_opt(info->mount_opt, NODATASUM); |
163 | break; |
164 | case Opt_nodatacow: |
165 | printk(KERN_INFO "btrfs: setting nodatacow\n"); |
166 | btrfs_set_opt(info->mount_opt, NODATACOW); |
167 | btrfs_set_opt(info->mount_opt, NODATASUM); |
168 | break; |
169 | case Opt_compress: |
170 | printk(KERN_INFO "btrfs: use compression\n"); |
171 | btrfs_set_opt(info->mount_opt, COMPRESS); |
172 | break; |
173 | case Opt_ssd: |
174 | printk(KERN_INFO "btrfs: use ssd allocation scheme\n"); |
175 | btrfs_set_opt(info->mount_opt, SSD); |
176 | break; |
177 | case Opt_ssd_spread: |
178 | printk(KERN_INFO "btrfs: use spread ssd " |
179 | "allocation scheme\n"); |
180 | btrfs_set_opt(info->mount_opt, SSD); |
181 | btrfs_set_opt(info->mount_opt, SSD_SPREAD); |
182 | break; |
183 | case Opt_nossd: |
184 | printk(KERN_INFO "btrfs: not using ssd allocation " |
185 | "scheme\n"); |
186 | btrfs_set_opt(info->mount_opt, NOSSD); |
187 | btrfs_clear_opt(info->mount_opt, SSD); |
188 | btrfs_clear_opt(info->mount_opt, SSD_SPREAD); |
189 | break; |
190 | case Opt_nobarrier: |
191 | printk(KERN_INFO "btrfs: turning off barriers\n"); |
192 | btrfs_set_opt(info->mount_opt, NOBARRIER); |
193 | break; |
194 | case Opt_thread_pool: |
195 | intarg = 0; |
196 | match_int(&args[0], &intarg); |
197 | if (intarg) { |
198 | info->thread_pool_size = intarg; |
199 | printk(KERN_INFO "btrfs: thread pool %d\n", |
200 | info->thread_pool_size); |
201 | } |
202 | break; |
203 | case Opt_max_extent: |
204 | num = match_strdup(&args[0]); |
205 | if (num) { |
206 | info->max_extent = btrfs_parse_size(num); |
207 | kfree(num); |
208 | |
209 | info->max_extent = max_t(u64, |
210 | info->max_extent, root->sectorsize); |
211 | printk(KERN_INFO "btrfs: max_extent at %llu\n", |
212 | (unsigned long long)info->max_extent); |
213 | } |
214 | break; |
215 | case Opt_max_inline: |
216 | num = match_strdup(&args[0]); |
217 | if (num) { |
218 | info->max_inline = btrfs_parse_size(num); |
219 | kfree(num); |
220 | |
221 | if (info->max_inline) { |
222 | info->max_inline = max_t(u64, |
223 | info->max_inline, |
224 | root->sectorsize); |
225 | } |
226 | printk(KERN_INFO "btrfs: max_inline at %llu\n", |
227 | (unsigned long long)info->max_inline); |
228 | } |
229 | break; |
230 | case Opt_alloc_start: |
231 | num = match_strdup(&args[0]); |
232 | if (num) { |
233 | info->alloc_start = btrfs_parse_size(num); |
234 | kfree(num); |
235 | printk(KERN_INFO |
236 | "btrfs: allocations start at %llu\n", |
237 | (unsigned long long)info->alloc_start); |
238 | } |
239 | break; |
240 | case Opt_noacl: |
241 | root->fs_info->sb->s_flags &= ~MS_POSIXACL; |
242 | break; |
243 | case Opt_notreelog: |
244 | printk(KERN_INFO "btrfs: disabling tree log\n"); |
245 | btrfs_set_opt(info->mount_opt, NOTREELOG); |
246 | break; |
247 | case Opt_flushoncommit: |
248 | printk(KERN_INFO "btrfs: turning on flush-on-commit\n"); |
249 | btrfs_set_opt(info->mount_opt, FLUSHONCOMMIT); |
250 | break; |
251 | case Opt_ratio: |
252 | intarg = 0; |
253 | match_int(&args[0], &intarg); |
254 | if (intarg) { |
255 | info->metadata_ratio = intarg; |
256 | printk(KERN_INFO "btrfs: metadata ratio %d\n", |
257 | info->metadata_ratio); |
258 | } |
259 | break; |
260 | default: |
261 | break; |
262 | } |
263 | } |
264 | kfree(options); |
265 | return 0; |
266 | } |
267 | |
268 | /* |
269 | * Parse mount options that are required early in the mount process. |
270 | * |
271 | * All other options will be parsed on much later in the mount process and |
272 | * only when we need to allocate a new super block. |
273 | */ |
274 | static int btrfs_parse_early_options(const char *options, fmode_t flags, |
275 | void *holder, char **subvol_name, |
276 | struct btrfs_fs_devices **fs_devices) |
277 | { |
278 | substring_t args[MAX_OPT_ARGS]; |
279 | char *opts, *p; |
280 | int error = 0; |
281 | |
282 | if (!options) |
283 | goto out; |
284 | |
285 | /* |
286 | * strsep changes the string, duplicate it because parse_options |
287 | * gets called twice |
288 | */ |
289 | opts = kstrdup(options, GFP_KERNEL); |
290 | if (!opts) |
291 | return -ENOMEM; |
292 | |
293 | while ((p = strsep(&opts, ",")) != NULL) { |
294 | int token; |
295 | if (!*p) |
296 | continue; |
297 | |
298 | token = match_token(p, tokens, args); |
299 | switch (token) { |
300 | case Opt_subvol: |
301 | *subvol_name = match_strdup(&args[0]); |
302 | break; |
303 | case Opt_device: |
304 | error = btrfs_scan_one_device(match_strdup(&args[0]), |
305 | flags, holder, fs_devices); |
306 | if (error) |
307 | goto out_free_opts; |
308 | break; |
309 | default: |
310 | break; |
311 | } |
312 | } |
313 | |
314 | out_free_opts: |
315 | kfree(opts); |
316 | out: |
317 | /* |
318 | * If no subvolume name is specified we use the default one. Allocate |
319 | * a copy of the string "." here so that code later in the |
320 | * mount path doesn't care if it's the default volume or another one. |
321 | */ |
322 | if (!*subvol_name) { |
323 | *subvol_name = kstrdup(".", GFP_KERNEL); |
324 | if (!*subvol_name) |
325 | return -ENOMEM; |
326 | } |
327 | return error; |
328 | } |
329 | |
330 | static int btrfs_fill_super(struct super_block *sb, |
331 | struct btrfs_fs_devices *fs_devices, |
332 | void *data, int silent) |
333 | { |
334 | struct inode *inode; |
335 | struct dentry *root_dentry; |
336 | struct btrfs_super_block *disk_super; |
337 | struct btrfs_root *tree_root; |
338 | struct btrfs_key key; |
339 | int err; |
340 | |
341 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
342 | sb->s_magic = BTRFS_SUPER_MAGIC; |
343 | sb->s_op = &btrfs_super_ops; |
344 | sb->s_export_op = &btrfs_export_ops; |
345 | sb->s_xattr = btrfs_xattr_handlers; |
346 | sb->s_time_gran = 1; |
347 | sb->s_flags |= MS_POSIXACL; |
348 | |
349 | tree_root = open_ctree(sb, fs_devices, (char *)data); |
350 | |
351 | if (IS_ERR(tree_root)) { |
352 | printk("btrfs: open_ctree failed\n"); |
353 | return PTR_ERR(tree_root); |
354 | } |
355 | sb->s_fs_info = tree_root; |
356 | disk_super = &tree_root->fs_info->super_copy; |
357 | |
358 | key.objectid = BTRFS_FIRST_FREE_OBJECTID; |
359 | key.type = BTRFS_INODE_ITEM_KEY; |
360 | key.offset = 0; |
361 | inode = btrfs_iget(sb, &key, tree_root->fs_info->fs_root); |
362 | if (IS_ERR(inode)) { |
363 | err = PTR_ERR(inode); |
364 | goto fail_close; |
365 | } |
366 | |
367 | root_dentry = d_alloc_root(inode); |
368 | if (!root_dentry) { |
369 | iput(inode); |
370 | err = -ENOMEM; |
371 | goto fail_close; |
372 | } |
373 | #if 0 |
374 | /* this does the super kobj at the same time */ |
375 | err = btrfs_sysfs_add_super(tree_root->fs_info); |
376 | if (err) |
377 | goto fail_close; |
378 | #endif |
379 | |
380 | sb->s_root = root_dentry; |
381 | |
382 | save_mount_options(sb, data); |
383 | return 0; |
384 | |
385 | fail_close: |
386 | close_ctree(tree_root); |
387 | return err; |
388 | } |
389 | |
390 | int btrfs_sync_fs(struct super_block *sb, int wait) |
391 | { |
392 | struct btrfs_trans_handle *trans; |
393 | struct btrfs_root *root = btrfs_sb(sb); |
394 | int ret; |
395 | |
396 | if (!wait) { |
397 | filemap_flush(root->fs_info->btree_inode->i_mapping); |
398 | return 0; |
399 | } |
400 | |
401 | btrfs_start_delalloc_inodes(root); |
402 | btrfs_wait_ordered_extents(root, 0); |
403 | |
404 | trans = btrfs_start_transaction(root, 1); |
405 | ret = btrfs_commit_transaction(trans, root); |
406 | return ret; |
407 | } |
408 | |
409 | static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) |
410 | { |
411 | struct btrfs_root *root = btrfs_sb(vfs->mnt_sb); |
412 | struct btrfs_fs_info *info = root->fs_info; |
413 | |
414 | if (btrfs_test_opt(root, DEGRADED)) |
415 | seq_puts(seq, ",degraded"); |
416 | if (btrfs_test_opt(root, NODATASUM)) |
417 | seq_puts(seq, ",nodatasum"); |
418 | if (btrfs_test_opt(root, NODATACOW)) |
419 | seq_puts(seq, ",nodatacow"); |
420 | if (btrfs_test_opt(root, NOBARRIER)) |
421 | seq_puts(seq, ",nobarrier"); |
422 | if (info->max_extent != (u64)-1) |
423 | seq_printf(seq, ",max_extent=%llu", |
424 | (unsigned long long)info->max_extent); |
425 | if (info->max_inline != 8192 * 1024) |
426 | seq_printf(seq, ",max_inline=%llu", |
427 | (unsigned long long)info->max_inline); |
428 | if (info->alloc_start != 0) |
429 | seq_printf(seq, ",alloc_start=%llu", |
430 | (unsigned long long)info->alloc_start); |
431 | if (info->thread_pool_size != min_t(unsigned long, |
432 | num_online_cpus() + 2, 8)) |
433 | seq_printf(seq, ",thread_pool=%d", info->thread_pool_size); |
434 | if (btrfs_test_opt(root, COMPRESS)) |
435 | seq_puts(seq, ",compress"); |
436 | if (btrfs_test_opt(root, NOSSD)) |
437 | seq_puts(seq, ",nossd"); |
438 | if (btrfs_test_opt(root, SSD_SPREAD)) |
439 | seq_puts(seq, ",ssd_spread"); |
440 | else if (btrfs_test_opt(root, SSD)) |
441 | seq_puts(seq, ",ssd"); |
442 | if (btrfs_test_opt(root, NOTREELOG)) |
443 | seq_puts(seq, ",notreelog"); |
444 | if (btrfs_test_opt(root, FLUSHONCOMMIT)) |
445 | seq_puts(seq, ",flushoncommit"); |
446 | if (!(root->fs_info->sb->s_flags & MS_POSIXACL)) |
447 | seq_puts(seq, ",noacl"); |
448 | return 0; |
449 | } |
450 | |
451 | static int btrfs_test_super(struct super_block *s, void *data) |
452 | { |
453 | struct btrfs_fs_devices *test_fs_devices = data; |
454 | struct btrfs_root *root = btrfs_sb(s); |
455 | |
456 | return root->fs_info->fs_devices == test_fs_devices; |
457 | } |
458 | |
459 | /* |
460 | * Find a superblock for the given device / mount point. |
461 | * |
462 | * Note: This is based on get_sb_bdev from fs/super.c with a few additions |
463 | * for multiple device setup. Make sure to keep it in sync. |
464 | */ |
465 | static int btrfs_get_sb(struct file_system_type *fs_type, int flags, |
466 | const char *dev_name, void *data, struct vfsmount *mnt) |
467 | { |
468 | char *subvol_name = NULL; |
469 | struct block_device *bdev = NULL; |
470 | struct super_block *s; |
471 | struct dentry *root; |
472 | struct btrfs_fs_devices *fs_devices = NULL; |
473 | fmode_t mode = FMODE_READ; |
474 | int error = 0; |
475 | |
476 | if (!(flags & MS_RDONLY)) |
477 | mode |= FMODE_WRITE; |
478 | |
479 | error = btrfs_parse_early_options(data, mode, fs_type, |
480 | &subvol_name, &fs_devices); |
481 | if (error) |
482 | return error; |
483 | |
484 | error = btrfs_scan_one_device(dev_name, mode, fs_type, &fs_devices); |
485 | if (error) |
486 | goto error_free_subvol_name; |
487 | |
488 | error = btrfs_open_devices(fs_devices, mode, fs_type); |
489 | if (error) |
490 | goto error_free_subvol_name; |
491 | |
492 | if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) { |
493 | error = -EACCES; |
494 | goto error_close_devices; |
495 | } |
496 | |
497 | bdev = fs_devices->latest_bdev; |
498 | s = sget(fs_type, btrfs_test_super, set_anon_super, fs_devices); |
499 | if (IS_ERR(s)) |
500 | goto error_s; |
501 | |
502 | if (s->s_root) { |
503 | if ((flags ^ s->s_flags) & MS_RDONLY) { |
504 | deactivate_locked_super(s); |
505 | error = -EBUSY; |
506 | goto error_close_devices; |
507 | } |
508 | |
509 | btrfs_close_devices(fs_devices); |
510 | } else { |
511 | char b[BDEVNAME_SIZE]; |
512 | |
513 | s->s_flags = flags; |
514 | strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id)); |
515 | error = btrfs_fill_super(s, fs_devices, data, |
516 | flags & MS_SILENT ? 1 : 0); |
517 | if (error) { |
518 | deactivate_locked_super(s); |
519 | goto error_free_subvol_name; |
520 | } |
521 | |
522 | btrfs_sb(s)->fs_info->bdev_holder = fs_type; |
523 | s->s_flags |= MS_ACTIVE; |
524 | } |
525 | |
526 | if (!strcmp(subvol_name, ".")) |
527 | root = dget(s->s_root); |
528 | else { |
529 | mutex_lock(&s->s_root->d_inode->i_mutex); |
530 | root = lookup_one_len(subvol_name, s->s_root, |
531 | strlen(subvol_name)); |
532 | mutex_unlock(&s->s_root->d_inode->i_mutex); |
533 | |
534 | if (IS_ERR(root)) { |
535 | deactivate_locked_super(s); |
536 | error = PTR_ERR(root); |
537 | goto error_free_subvol_name; |
538 | } |
539 | if (!root->d_inode) { |
540 | dput(root); |
541 | deactivate_locked_super(s); |
542 | error = -ENXIO; |
543 | goto error_free_subvol_name; |
544 | } |
545 | } |
546 | |
547 | mnt->mnt_sb = s; |
548 | mnt->mnt_root = root; |
549 | |
550 | kfree(subvol_name); |
551 | return 0; |
552 | |
553 | error_s: |
554 | error = PTR_ERR(s); |
555 | error_close_devices: |
556 | btrfs_close_devices(fs_devices); |
557 | error_free_subvol_name: |
558 | kfree(subvol_name); |
559 | return error; |
560 | } |
561 | |
562 | static int btrfs_remount(struct super_block *sb, int *flags, char *data) |
563 | { |
564 | struct btrfs_root *root = btrfs_sb(sb); |
565 | int ret; |
566 | |
567 | ret = btrfs_parse_options(root, data); |
568 | if (ret) |
569 | return -EINVAL; |
570 | |
571 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) |
572 | return 0; |
573 | |
574 | if (*flags & MS_RDONLY) { |
575 | sb->s_flags |= MS_RDONLY; |
576 | |
577 | ret = btrfs_commit_super(root); |
578 | WARN_ON(ret); |
579 | } else { |
580 | if (root->fs_info->fs_devices->rw_devices == 0) |
581 | return -EACCES; |
582 | |
583 | if (btrfs_super_log_root(&root->fs_info->super_copy) != 0) |
584 | return -EINVAL; |
585 | |
586 | /* recover relocation */ |
587 | ret = btrfs_recover_relocation(root); |
588 | WARN_ON(ret); |
589 | |
590 | ret = btrfs_cleanup_fs_roots(root->fs_info); |
591 | WARN_ON(ret); |
592 | |
593 | sb->s_flags &= ~MS_RDONLY; |
594 | } |
595 | |
596 | return 0; |
597 | } |
598 | |
599 | static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
600 | { |
601 | struct btrfs_root *root = btrfs_sb(dentry->d_sb); |
602 | struct btrfs_super_block *disk_super = &root->fs_info->super_copy; |
603 | int bits = dentry->d_sb->s_blocksize_bits; |
604 | __be32 *fsid = (__be32 *)root->fs_info->fsid; |
605 | |
606 | buf->f_namelen = BTRFS_NAME_LEN; |
607 | buf->f_blocks = btrfs_super_total_bytes(disk_super) >> bits; |
608 | buf->f_bfree = buf->f_blocks - |
609 | (btrfs_super_bytes_used(disk_super) >> bits); |
610 | buf->f_bavail = buf->f_bfree; |
611 | buf->f_bsize = dentry->d_sb->s_blocksize; |
612 | buf->f_type = BTRFS_SUPER_MAGIC; |
613 | |
614 | /* We treat it as constant endianness (it doesn't matter _which_) |
615 | because we want the fsid to come out the same whether mounted |
616 | on a big-endian or little-endian host */ |
617 | buf->f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]); |
618 | buf->f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]); |
619 | /* Mask in the root object ID too, to disambiguate subvols */ |
620 | buf->f_fsid.val[0] ^= BTRFS_I(dentry->d_inode)->root->objectid >> 32; |
621 | buf->f_fsid.val[1] ^= BTRFS_I(dentry->d_inode)->root->objectid; |
622 | |
623 | return 0; |
624 | } |
625 | |
626 | static struct file_system_type btrfs_fs_type = { |
627 | .owner = THIS_MODULE, |
628 | .name = "btrfs", |
629 | .get_sb = btrfs_get_sb, |
630 | .kill_sb = kill_anon_super, |
631 | .fs_flags = FS_REQUIRES_DEV, |
632 | }; |
633 | |
634 | /* |
635 | * used by btrfsctl to scan devices when no FS is mounted |
636 | */ |
637 | static long btrfs_control_ioctl(struct file *file, unsigned int cmd, |
638 | unsigned long arg) |
639 | { |
640 | struct btrfs_ioctl_vol_args *vol; |
641 | struct btrfs_fs_devices *fs_devices; |
642 | int ret = -ENOTTY; |
643 | |
644 | if (!capable(CAP_SYS_ADMIN)) |
645 | return -EPERM; |
646 | |
647 | vol = memdup_user((void __user *)arg, sizeof(*vol)); |
648 | if (IS_ERR(vol)) |
649 | return PTR_ERR(vol); |
650 | |
651 | switch (cmd) { |
652 | case BTRFS_IOC_SCAN_DEV: |
653 | ret = btrfs_scan_one_device(vol->name, FMODE_READ, |
654 | &btrfs_fs_type, &fs_devices); |
655 | break; |
656 | } |
657 | |
658 | kfree(vol); |
659 | return ret; |
660 | } |
661 | |
662 | static int btrfs_freeze(struct super_block *sb) |
663 | { |
664 | struct btrfs_root *root = btrfs_sb(sb); |
665 | mutex_lock(&root->fs_info->transaction_kthread_mutex); |
666 | mutex_lock(&root->fs_info->cleaner_mutex); |
667 | return 0; |
668 | } |
669 | |
670 | static int btrfs_unfreeze(struct super_block *sb) |
671 | { |
672 | struct btrfs_root *root = btrfs_sb(sb); |
673 | mutex_unlock(&root->fs_info->cleaner_mutex); |
674 | mutex_unlock(&root->fs_info->transaction_kthread_mutex); |
675 | return 0; |
676 | } |
677 | |
678 | static struct super_operations btrfs_super_ops = { |
679 | .delete_inode = btrfs_delete_inode, |
680 | .put_super = btrfs_put_super, |
681 | .sync_fs = btrfs_sync_fs, |
682 | .show_options = btrfs_show_options, |
683 | .write_inode = btrfs_write_inode, |
684 | .dirty_inode = btrfs_dirty_inode, |
685 | .alloc_inode = btrfs_alloc_inode, |
686 | .destroy_inode = btrfs_destroy_inode, |
687 | .statfs = btrfs_statfs, |
688 | .remount_fs = btrfs_remount, |
689 | .freeze_fs = btrfs_freeze, |
690 | .unfreeze_fs = btrfs_unfreeze, |
691 | }; |
692 | |
693 | static const struct file_operations btrfs_ctl_fops = { |
694 | .unlocked_ioctl = btrfs_control_ioctl, |
695 | .compat_ioctl = btrfs_control_ioctl, |
696 | .owner = THIS_MODULE, |
697 | }; |
698 | |
699 | static struct miscdevice btrfs_misc = { |
700 | .minor = MISC_DYNAMIC_MINOR, |
701 | .name = "btrfs-control", |
702 | .fops = &btrfs_ctl_fops |
703 | }; |
704 | |
705 | static int btrfs_interface_init(void) |
706 | { |
707 | return misc_register(&btrfs_misc); |
708 | } |
709 | |
710 | static void btrfs_interface_exit(void) |
711 | { |
712 | if (misc_deregister(&btrfs_misc) < 0) |
713 | printk(KERN_INFO "misc_deregister failed for control device"); |
714 | } |
715 | |
716 | static int __init init_btrfs_fs(void) |
717 | { |
718 | int err; |
719 | |
720 | err = btrfs_init_sysfs(); |
721 | if (err) |
722 | return err; |
723 | |
724 | err = btrfs_init_cachep(); |
725 | if (err) |
726 | goto free_sysfs; |
727 | |
728 | err = extent_io_init(); |
729 | if (err) |
730 | goto free_cachep; |
731 | |
732 | err = extent_map_init(); |
733 | if (err) |
734 | goto free_extent_io; |
735 | |
736 | err = btrfs_interface_init(); |
737 | if (err) |
738 | goto free_extent_map; |
739 | |
740 | err = register_filesystem(&btrfs_fs_type); |
741 | if (err) |
742 | goto unregister_ioctl; |
743 | |
744 | printk(KERN_INFO "%s loaded\n", BTRFS_BUILD_VERSION); |
745 | return 0; |
746 | |
747 | unregister_ioctl: |
748 | btrfs_interface_exit(); |
749 | free_extent_map: |
750 | extent_map_exit(); |
751 | free_extent_io: |
752 | extent_io_exit(); |
753 | free_cachep: |
754 | btrfs_destroy_cachep(); |
755 | free_sysfs: |
756 | btrfs_exit_sysfs(); |
757 | return err; |
758 | } |
759 | |
760 | static void __exit exit_btrfs_fs(void) |
761 | { |
762 | btrfs_destroy_cachep(); |
763 | extent_map_exit(); |
764 | extent_io_exit(); |
765 | btrfs_interface_exit(); |
766 | unregister_filesystem(&btrfs_fs_type); |
767 | btrfs_exit_sysfs(); |
768 | btrfs_cleanup_fs_uuids(); |
769 | btrfs_zlib_exit(); |
770 | } |
771 | |
772 | module_init(init_btrfs_fs) |
773 | module_exit(exit_btrfs_fs) |
774 | |
775 | MODULE_LICENSE("GPL"); |
776 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9