diff options
author | Josef Bacik <jbacik@redhat.com> | 2007-08-29 15:47:34 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-08-29 15:47:34 -0400 |
commit | 58176a9604c5db1784d2c979aea472b3be40b6f0 (patch) | |
tree | a0d887c81b2f174de619dfefca19674a43756971 | |
parent | b888db2bd7b67f190b32934e6a86181f262ac3ec (diff) |
Btrfs: Add per-root block accounting and sysfs entries
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/Makefile | 2 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 54 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 31 | ||||
-rw-r--r-- | fs/btrfs/disk-io.h | 3 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 17 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 13 | ||||
-rw-r--r-- | fs/btrfs/super.c | 14 | ||||
-rw-r--r-- | fs/btrfs/sysfs.c | 236 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 34 |
9 files changed, 393 insertions, 11 deletions
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile index ea7a22870350..ee505c87ecf3 100644 --- a/fs/btrfs/Makefile +++ b/fs/btrfs/Makefile | |||
@@ -5,7 +5,7 @@ obj-m := btrfs.o | |||
5 | btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ | 5 | btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ |
6 | hash.o file-item.o inode-item.o inode-map.o disk-io.o \ | 6 | hash.o file-item.o inode-item.o inode-map.o disk-io.o \ |
7 | transaction.o bit-radix.o inode.o file.o tree-defrag.o \ | 7 | transaction.o bit-radix.o inode.o file.o tree-defrag.o \ |
8 | extent_map.o | 8 | extent_map.o sysfs.o |
9 | 9 | ||
10 | #btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ | 10 | #btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ |
11 | # root-tree.o dir-item.o hash.o file-item.o inode-item.o \ | 11 | # root-tree.o dir-item.o hash.o file-item.o inode-item.o \ |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 947f061ed118..ffeee546a0d7 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/fs.h> | 22 | #include <linux/fs.h> |
23 | #include <linux/buffer_head.h> | 23 | #include <linux/buffer_head.h> |
24 | #include <linux/workqueue.h> | 24 | #include <linux/workqueue.h> |
25 | #include <linux/completion.h> | ||
25 | #include "bit-radix.h" | 26 | #include "bit-radix.h" |
26 | 27 | ||
27 | struct btrfs_trans_handle; | 28 | struct btrfs_trans_handle; |
@@ -313,6 +314,8 @@ struct btrfs_fs_info { | |||
313 | struct list_head trans_list; | 314 | struct list_head trans_list; |
314 | struct list_head dead_roots; | 315 | struct list_head dead_roots; |
315 | struct delayed_work trans_work; | 316 | struct delayed_work trans_work; |
317 | struct kobject super_kobj; | ||
318 | struct completion kobj_unregister; | ||
316 | int do_barriers; | 319 | int do_barriers; |
317 | int closing; | 320 | int closing; |
318 | }; | 321 | }; |
@@ -328,6 +331,8 @@ struct btrfs_root { | |||
328 | struct btrfs_key root_key; | 331 | struct btrfs_key root_key; |
329 | struct btrfs_fs_info *fs_info; | 332 | struct btrfs_fs_info *fs_info; |
330 | struct inode *inode; | 333 | struct inode *inode; |
334 | struct kobject root_kobj; | ||
335 | struct completion kobj_unregister; | ||
331 | u64 objectid; | 336 | u64 objectid; |
332 | u64 last_trans; | 337 | u64 last_trans; |
333 | u32 blocksize; | 338 | u32 blocksize; |
@@ -338,6 +343,7 @@ struct btrfs_root { | |||
338 | struct btrfs_key defrag_progress; | 343 | struct btrfs_key defrag_progress; |
339 | int defrag_running; | 344 | int defrag_running; |
340 | int defrag_level; | 345 | int defrag_level; |
346 | char *name; | ||
341 | }; | 347 | }; |
342 | 348 | ||
343 | /* the lower bits in the key flags defines the item type */ | 349 | /* the lower bits in the key flags defines the item type */ |
@@ -814,6 +820,28 @@ static inline void btrfs_set_root_flags(struct btrfs_root_item *item, u32 val) | |||
814 | item->flags = cpu_to_le32(val); | 820 | item->flags = cpu_to_le32(val); |
815 | } | 821 | } |
816 | 822 | ||
823 | static inline void btrfs_set_root_blocks_used(struct btrfs_root_item *item, | ||
824 | u64 val) | ||
825 | { | ||
826 | item->blocks_used = cpu_to_le64(val); | ||
827 | } | ||
828 | |||
829 | static inline u64 btrfs_root_blocks_used(struct btrfs_root_item *item) | ||
830 | { | ||
831 | return le64_to_cpu(item->blocks_used); | ||
832 | } | ||
833 | |||
834 | static inline void btrfs_set_root_block_limit(struct btrfs_root_item *item, | ||
835 | u64 val) | ||
836 | { | ||
837 | item->block_limit = cpu_to_le64(val); | ||
838 | } | ||
839 | |||
840 | static inline u64 btrfs_root_block_limit(struct btrfs_root_item *item) | ||
841 | { | ||
842 | return le64_to_cpu(item->block_limit); | ||
843 | } | ||
844 | |||
817 | static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s) | 845 | static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s) |
818 | { | 846 | { |
819 | return le64_to_cpu(s->blocknr); | 847 | return le64_to_cpu(s->blocknr); |
@@ -1014,6 +1042,23 @@ static inline void btrfs_memmove(struct btrfs_root *root, | |||
1014 | memmove(dst, src, nr); | 1042 | memmove(dst, src, nr); |
1015 | } | 1043 | } |
1016 | 1044 | ||
1045 | static inline int btrfs_set_root_name(struct btrfs_root *root, | ||
1046 | const char *name, int len) | ||
1047 | { | ||
1048 | /* if we already have a name just free it */ | ||
1049 | if (root->name) | ||
1050 | kfree(root->name); | ||
1051 | |||
1052 | root->name = kmalloc(len+1, GFP_KERNEL); | ||
1053 | if (!root->name) | ||
1054 | return -ENOMEM; | ||
1055 | |||
1056 | memcpy(root->name, name, len); | ||
1057 | root->name[len] ='\0'; | ||
1058 | |||
1059 | return 0; | ||
1060 | } | ||
1061 | |||
1017 | /* helper function to cast into the data area of the leaf. */ | 1062 | /* helper function to cast into the data area of the leaf. */ |
1018 | #define btrfs_item_ptr(leaf, slot, type) \ | 1063 | #define btrfs_item_ptr(leaf, slot, type) \ |
1019 | ((type *)(btrfs_leaf_data(leaf) + \ | 1064 | ((type *)(btrfs_leaf_data(leaf) + \ |
@@ -1191,4 +1236,13 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, | |||
1191 | /* tree-defrag.c */ | 1236 | /* tree-defrag.c */ |
1192 | int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, | 1237 | int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, |
1193 | struct btrfs_root *root, int cache_only); | 1238 | struct btrfs_root *root, int cache_only); |
1239 | |||
1240 | /* sysfs.c */ | ||
1241 | int btrfs_init_sysfs(void); | ||
1242 | void btrfs_exit_sysfs(void); | ||
1243 | int btrfs_sysfs_add_super(struct btrfs_fs_info *fs); | ||
1244 | int btrfs_sysfs_add_root(struct btrfs_root *root); | ||
1245 | void btrfs_sysfs_del_root(struct btrfs_root *root); | ||
1246 | void btrfs_sysfs_del_super(struct btrfs_fs_info *root); | ||
1247 | |||
1194 | #endif | 1248 | #endif |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index b2f79878d51a..c25ef0a68f18 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -294,9 +294,12 @@ static int __setup_root(int blocksize, | |||
294 | root->last_trans = 0; | 294 | root->last_trans = 0; |
295 | root->highest_inode = 0; | 295 | root->highest_inode = 0; |
296 | root->last_inode_alloc = 0; | 296 | root->last_inode_alloc = 0; |
297 | root->name = NULL; | ||
297 | memset(&root->root_key, 0, sizeof(root->root_key)); | 298 | memset(&root->root_key, 0, sizeof(root->root_key)); |
298 | memset(&root->root_item, 0, sizeof(root->root_item)); | 299 | memset(&root->root_item, 0, sizeof(root->root_item)); |
299 | memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); | 300 | memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); |
301 | memset(&root->root_kobj, 0, sizeof(root->root_kobj)); | ||
302 | init_completion(&root->kobj_unregister); | ||
300 | root->defrag_running = 0; | 303 | root->defrag_running = 0; |
301 | root->defrag_level = 0; | 304 | root->defrag_level = 0; |
302 | root->root_key.objectid = objectid; | 305 | root->root_key.objectid = objectid; |
@@ -384,7 +387,8 @@ insert: | |||
384 | } | 387 | } |
385 | 388 | ||
386 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | 389 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, |
387 | struct btrfs_key *location) | 390 | struct btrfs_key *location, |
391 | const char *name, int namelen) | ||
388 | { | 392 | { |
389 | struct btrfs_root *root; | 393 | struct btrfs_root *root; |
390 | int ret; | 394 | int ret; |
@@ -405,6 +409,22 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | |||
405 | kfree(root); | 409 | kfree(root); |
406 | return ERR_PTR(ret); | 410 | return ERR_PTR(ret); |
407 | } | 411 | } |
412 | |||
413 | ret = btrfs_set_root_name(root, name, namelen); | ||
414 | if (ret) { | ||
415 | brelse(root->node); | ||
416 | kfree(root); | ||
417 | return ERR_PTR(ret); | ||
418 | } | ||
419 | |||
420 | ret = btrfs_sysfs_add_root(root); | ||
421 | if (ret) { | ||
422 | brelse(root->node); | ||
423 | kfree(root->name); | ||
424 | kfree(root); | ||
425 | return ERR_PTR(ret); | ||
426 | } | ||
427 | |||
408 | return root; | 428 | return root; |
409 | } | 429 | } |
410 | 430 | ||
@@ -433,6 +453,8 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
433 | INIT_RADIX_TREE(&fs_info->block_group_data_radix, GFP_KERNEL); | 453 | INIT_RADIX_TREE(&fs_info->block_group_data_radix, GFP_KERNEL); |
434 | INIT_LIST_HEAD(&fs_info->trans_list); | 454 | INIT_LIST_HEAD(&fs_info->trans_list); |
435 | INIT_LIST_HEAD(&fs_info->dead_roots); | 455 | INIT_LIST_HEAD(&fs_info->dead_roots); |
456 | memset(&fs_info->super_kobj, 0, sizeof(fs_info->super_kobj)); | ||
457 | init_completion(&fs_info->kobj_unregister); | ||
436 | sb_set_blocksize(sb, 4096); | 458 | sb_set_blocksize(sb, 4096); |
437 | fs_info->running_transaction = NULL; | 459 | fs_info->running_transaction = NULL; |
438 | fs_info->last_trans_committed = 0; | 460 | fs_info->last_trans_committed = 0; |
@@ -500,8 +522,10 @@ struct btrfs_root *open_ctree(struct super_block *sb) | |||
500 | 522 | ||
501 | fs_info->generation = btrfs_super_generation(disk_super) + 1; | 523 | fs_info->generation = btrfs_super_generation(disk_super) + 1; |
502 | ret = btrfs_find_dead_roots(tree_root); | 524 | ret = btrfs_find_dead_roots(tree_root); |
503 | if (ret) | 525 | if (ret) { |
526 | mutex_unlock(&fs_info->fs_mutex); | ||
504 | goto fail_tree_root; | 527 | goto fail_tree_root; |
528 | } | ||
505 | mutex_unlock(&fs_info->fs_mutex); | 529 | mutex_unlock(&fs_info->fs_mutex); |
506 | return tree_root; | 530 | return tree_root; |
507 | 531 | ||
@@ -553,12 +577,15 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) | |||
553 | { | 577 | { |
554 | radix_tree_delete(&fs_info->fs_roots_radix, | 578 | radix_tree_delete(&fs_info->fs_roots_radix, |
555 | (unsigned long)root->root_key.objectid); | 579 | (unsigned long)root->root_key.objectid); |
580 | btrfs_sysfs_del_root(root); | ||
556 | if (root->inode) | 581 | if (root->inode) |
557 | iput(root->inode); | 582 | iput(root->inode); |
558 | if (root->node) | 583 | if (root->node) |
559 | brelse(root->node); | 584 | brelse(root->node); |
560 | if (root->commit_root) | 585 | if (root->commit_root) |
561 | brelse(root->commit_root); | 586 | brelse(root->commit_root); |
587 | if (root->name) | ||
588 | kfree(root->name); | ||
562 | kfree(root); | 589 | kfree(root); |
563 | return 0; | 590 | return 0; |
564 | } | 591 | } |
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index 5261733b8735..da6bb72750f2 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h | |||
@@ -66,7 +66,8 @@ struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr); | |||
66 | int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, | 66 | int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, |
67 | char *result); | 67 | char *result); |
68 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, | 68 | struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, |
69 | struct btrfs_key *location); | 69 | struct btrfs_key *location, |
70 | const char *name, int namelen); | ||
70 | struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, | 71 | struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, |
71 | struct btrfs_key *location); | 72 | struct btrfs_key *location); |
72 | u64 bh_blocknr(struct buffer_head *bh); | 73 | u64 bh_blocknr(struct buffer_head *bh); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index c31e84d42653..ff3f7c2be605 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -858,16 +858,23 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
858 | btrfs_set_extent_refs(ei, refs); | 858 | btrfs_set_extent_refs(ei, refs); |
859 | btrfs_mark_buffer_dirty(path->nodes[0]); | 859 | btrfs_mark_buffer_dirty(path->nodes[0]); |
860 | if (refs == 0) { | 860 | if (refs == 0) { |
861 | u64 super_blocks_used; | 861 | u64 super_blocks_used, root_blocks_used; |
862 | 862 | ||
863 | if (pin) { | 863 | if (pin) { |
864 | ret = pin_down_block(root, blocknr, 0); | 864 | ret = pin_down_block(root, blocknr, 0); |
865 | BUG_ON(ret); | 865 | BUG_ON(ret); |
866 | } | 866 | } |
867 | 867 | ||
868 | /* block accounting for super block */ | ||
868 | super_blocks_used = btrfs_super_blocks_used(&info->super_copy); | 869 | super_blocks_used = btrfs_super_blocks_used(&info->super_copy); |
869 | btrfs_set_super_blocks_used(&info->super_copy, | 870 | btrfs_set_super_blocks_used(&info->super_copy, |
870 | super_blocks_used - num_blocks); | 871 | super_blocks_used - num_blocks); |
872 | |||
873 | /* block accounting for root item */ | ||
874 | root_blocks_used = btrfs_root_blocks_used(&root->root_item); | ||
875 | btrfs_set_root_blocks_used(&root->root_item, | ||
876 | root_blocks_used - num_blocks); | ||
877 | |||
871 | ret = btrfs_del_item(trans, extent_root, path); | 878 | ret = btrfs_del_item(trans, extent_root, path); |
872 | if (ret) { | 879 | if (ret) { |
873 | return ret; | 880 | return ret; |
@@ -1175,7 +1182,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1175 | { | 1182 | { |
1176 | int ret; | 1183 | int ret; |
1177 | int pending_ret; | 1184 | int pending_ret; |
1178 | u64 super_blocks_used; | 1185 | u64 super_blocks_used, root_blocks_used; |
1179 | u64 search_start = 0; | 1186 | u64 search_start = 0; |
1180 | struct btrfs_fs_info *info = root->fs_info; | 1187 | struct btrfs_fs_info *info = root->fs_info; |
1181 | struct btrfs_root *extent_root = info->extent_root; | 1188 | struct btrfs_root *extent_root = info->extent_root; |
@@ -1193,10 +1200,16 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1193 | if (ret) | 1200 | if (ret) |
1194 | return ret; | 1201 | return ret; |
1195 | 1202 | ||
1203 | /* block accounting for super block */ | ||
1196 | super_blocks_used = btrfs_super_blocks_used(&info->super_copy); | 1204 | super_blocks_used = btrfs_super_blocks_used(&info->super_copy); |
1197 | btrfs_set_super_blocks_used(&info->super_copy, super_blocks_used + | 1205 | btrfs_set_super_blocks_used(&info->super_copy, super_blocks_used + |
1198 | num_blocks); | 1206 | num_blocks); |
1199 | 1207 | ||
1208 | /* block accounting for root item */ | ||
1209 | root_blocks_used = btrfs_root_blocks_used(&root->root_item); | ||
1210 | btrfs_set_root_blocks_used(&root->root_item, root_blocks_used + | ||
1211 | num_blocks); | ||
1212 | |||
1200 | if (root == extent_root) { | 1213 | if (root == extent_root) { |
1201 | BUG_ON(num_blocks != 1); | 1214 | BUG_ON(num_blocks != 1); |
1202 | set_radix_bit(&root->fs_info->extent_ins_radix, ins->objectid); | 1215 | set_radix_bit(&root->fs_info->extent_ins_radix, ins->objectid); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index dc181089aa74..2e3918e6049e 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -733,7 +733,8 @@ out: | |||
733 | */ | 733 | */ |
734 | static int fixup_tree_root_location(struct btrfs_root *root, | 734 | static int fixup_tree_root_location(struct btrfs_root *root, |
735 | struct btrfs_key *location, | 735 | struct btrfs_key *location, |
736 | struct btrfs_root **sub_root) | 736 | struct btrfs_root **sub_root, |
737 | struct dentry *dentry) | ||
737 | { | 738 | { |
738 | struct btrfs_path *path; | 739 | struct btrfs_path *path; |
739 | struct btrfs_root_item *ri; | 740 | struct btrfs_root_item *ri; |
@@ -747,7 +748,9 @@ static int fixup_tree_root_location(struct btrfs_root *root, | |||
747 | BUG_ON(!path); | 748 | BUG_ON(!path); |
748 | mutex_lock(&root->fs_info->fs_mutex); | 749 | mutex_lock(&root->fs_info->fs_mutex); |
749 | 750 | ||
750 | *sub_root = btrfs_read_fs_root(root->fs_info, location); | 751 | *sub_root = btrfs_read_fs_root(root->fs_info, location, |
752 | dentry->d_name.name, | ||
753 | dentry->d_name.len); | ||
751 | if (IS_ERR(*sub_root)) | 754 | if (IS_ERR(*sub_root)) |
752 | return PTR_ERR(*sub_root); | 755 | return PTR_ERR(*sub_root); |
753 | 756 | ||
@@ -812,7 +815,8 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
812 | return ERR_PTR(ret); | 815 | return ERR_PTR(ret); |
813 | inode = NULL; | 816 | inode = NULL; |
814 | if (location.objectid) { | 817 | if (location.objectid) { |
815 | ret = fixup_tree_root_location(root, &location, &sub_root); | 818 | ret = fixup_tree_root_location(root, &location, &sub_root, |
819 | dentry); | ||
816 | if (ret < 0) | 820 | if (ret < 0) |
817 | return ERR_PTR(ret); | 821 | return ERR_PTR(ret); |
818 | if (ret > 0) | 822 | if (ret > 0) |
@@ -1829,6 +1833,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen) | |||
1829 | 1833 | ||
1830 | btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol)); | 1834 | btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol)); |
1831 | btrfs_set_root_refs(&root_item, 1); | 1835 | btrfs_set_root_refs(&root_item, 1); |
1836 | btrfs_set_root_blocks_used(&root_item, 0); | ||
1832 | memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); | 1837 | memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); |
1833 | root_item.drop_level = 0; | 1838 | root_item.drop_level = 0; |
1834 | brelse(subvol); | 1839 | brelse(subvol); |
@@ -1865,7 +1870,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen) | |||
1865 | if (ret) | 1870 | if (ret) |
1866 | goto fail_commit; | 1871 | goto fail_commit; |
1867 | 1872 | ||
1868 | new_root = btrfs_read_fs_root(root->fs_info, &key); | 1873 | new_root = btrfs_read_fs_root(root->fs_info, &key, name, namelen); |
1869 | BUG_ON(!new_root); | 1874 | BUG_ON(!new_root); |
1870 | 1875 | ||
1871 | trans = btrfs_start_transaction(new_root, 1); | 1876 | trans = btrfs_start_transaction(new_root, 1); |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 7da95538745f..a68101ae1a3b 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -45,12 +45,14 @@ static struct super_operations btrfs_super_ops; | |||
45 | static void btrfs_put_super (struct super_block * sb) | 45 | static void btrfs_put_super (struct super_block * sb) |
46 | { | 46 | { |
47 | struct btrfs_root *root = btrfs_sb(sb); | 47 | struct btrfs_root *root = btrfs_sb(sb); |
48 | struct btrfs_fs_info *fs = root->fs_info; | ||
48 | int ret; | 49 | int ret; |
49 | 50 | ||
50 | ret = close_ctree(root); | 51 | ret = close_ctree(root); |
51 | if (ret) { | 52 | if (ret) { |
52 | printk("close ctree returns %d\n", ret); | 53 | printk("close ctree returns %d\n", ret); |
53 | } | 54 | } |
55 | btrfs_sysfs_del_super(fs); | ||
54 | sb->s_fs_info = NULL; | 56 | sb->s_fs_info = NULL; |
55 | } | 57 | } |
56 | 58 | ||
@@ -101,6 +103,12 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent) | |||
101 | err = -ENOMEM; | 103 | err = -ENOMEM; |
102 | goto fail_close; | 104 | goto fail_close; |
103 | } | 105 | } |
106 | |||
107 | /* this does the super kobj at the same time */ | ||
108 | err = btrfs_sysfs_add_super(tree_root->fs_info); | ||
109 | if (err) | ||
110 | goto fail_close; | ||
111 | |||
104 | sb->s_root = root_dentry; | 112 | sb->s_root = root_dentry; |
105 | btrfs_transaction_queue_work(tree_root, HZ * 30); | 113 | btrfs_transaction_queue_work(tree_root, HZ * 30); |
106 | return 0; | 114 | return 0; |
@@ -182,6 +190,11 @@ static struct super_operations btrfs_super_ops = { | |||
182 | static int __init init_btrfs_fs(void) | 190 | static int __init init_btrfs_fs(void) |
183 | { | 191 | { |
184 | int err; | 192 | int err; |
193 | |||
194 | err = btrfs_init_sysfs(); | ||
195 | if (err) | ||
196 | return err; | ||
197 | |||
185 | btrfs_init_transaction_sys(); | 198 | btrfs_init_transaction_sys(); |
186 | err = btrfs_init_cachep(); | 199 | err = btrfs_init_cachep(); |
187 | if (err) | 200 | if (err) |
@@ -196,6 +209,7 @@ static void __exit exit_btrfs_fs(void) | |||
196 | btrfs_destroy_cachep(); | 209 | btrfs_destroy_cachep(); |
197 | extent_map_exit(); | 210 | extent_map_exit(); |
198 | unregister_filesystem(&btrfs_fs_type); | 211 | unregister_filesystem(&btrfs_fs_type); |
212 | btrfs_exit_sysfs(); | ||
199 | } | 213 | } |
200 | 214 | ||
201 | module_init(init_btrfs_fs) | 215 | module_init(init_btrfs_fs) |
diff --git a/fs/btrfs/sysfs.c b/fs/btrfs/sysfs.c index db8917e5b256..2058783373eb 100644 --- a/fs/btrfs/sysfs.c +++ b/fs/btrfs/sysfs.c | |||
@@ -16,6 +16,242 @@ | |||
16 | * Boston, MA 021110-1307, USA. | 16 | * Boston, MA 021110-1307, USA. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/spinlock.h> | ||
22 | #include <linux/completion.h> | ||
23 | #include <linux/buffer_head.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/kobject.h> | ||
26 | |||
19 | #include "ctree.h" | 27 | #include "ctree.h" |
20 | #include "disk-io.h" | 28 | #include "disk-io.h" |
21 | #include "transaction.h" | 29 | #include "transaction.h" |
30 | |||
31 | static ssize_t root_blocks_used_show(struct btrfs_root *root, char *buf) | ||
32 | { | ||
33 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
34 | (unsigned long long)btrfs_root_blocks_used(&root->root_item)); | ||
35 | } | ||
36 | |||
37 | static ssize_t root_block_limit_show(struct btrfs_root *root, char *buf) | ||
38 | { | ||
39 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
40 | (unsigned long long)btrfs_root_block_limit(&root->root_item)); | ||
41 | } | ||
42 | |||
43 | static ssize_t super_blocks_used_show(struct btrfs_fs_info *fs, char *buf) | ||
44 | { | ||
45 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
46 | (unsigned long long)btrfs_super_blocks_used(fs->disk_super)); | ||
47 | } | ||
48 | |||
49 | static ssize_t super_total_blocks_show(struct btrfs_fs_info *fs, char *buf) | ||
50 | { | ||
51 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
52 | (unsigned long long)btrfs_super_total_blocks(fs->disk_super)); | ||
53 | } | ||
54 | |||
55 | static ssize_t super_blocksize_show(struct btrfs_fs_info *fs, char *buf) | ||
56 | { | ||
57 | return snprintf(buf, PAGE_SIZE, "%llu\n", | ||
58 | (unsigned long long)btrfs_super_blocksize(fs->disk_super)); | ||
59 | } | ||
60 | |||
61 | /* this is for root attrs (subvols/snapshots) */ | ||
62 | struct btrfs_root_attr { | ||
63 | struct attribute attr; | ||
64 | ssize_t (*show)(struct btrfs_root *, char *); | ||
65 | ssize_t (*store)(struct btrfs_root *, const char *, size_t); | ||
66 | }; | ||
67 | |||
68 | #define ROOT_ATTR(name, mode, show, store) \ | ||
69 | static struct btrfs_root_attr btrfs_root_attr_##name = __ATTR(name, mode, show, store) | ||
70 | |||
71 | ROOT_ATTR(blocks_used, 0444, root_blocks_used_show, NULL); | ||
72 | ROOT_ATTR(block_limit, 0644, root_block_limit_show, NULL); | ||
73 | |||
74 | static struct attribute *btrfs_root_attrs[] = { | ||
75 | &btrfs_root_attr_blocks_used.attr, | ||
76 | &btrfs_root_attr_block_limit.attr, | ||
77 | NULL, | ||
78 | }; | ||
79 | |||
80 | /* this is for super attrs (actual full fs) */ | ||
81 | struct btrfs_super_attr { | ||
82 | struct attribute attr; | ||
83 | ssize_t (*show)(struct btrfs_fs_info *, char *); | ||
84 | ssize_t (*store)(struct btrfs_fs_info *, const char *, size_t); | ||
85 | }; | ||
86 | |||
87 | #define SUPER_ATTR(name, mode, show, store) \ | ||
88 | static struct btrfs_super_attr btrfs_super_attr_##name = __ATTR(name, mode, show, store) | ||
89 | |||
90 | SUPER_ATTR(blocks_used, 0444, super_blocks_used_show, NULL); | ||
91 | SUPER_ATTR(total_blocks, 0444, super_total_blocks_show, NULL); | ||
92 | SUPER_ATTR(blocksize, 0444, super_blocksize_show, NULL); | ||
93 | |||
94 | static struct attribute *btrfs_super_attrs[] = { | ||
95 | &btrfs_super_attr_blocks_used.attr, | ||
96 | &btrfs_super_attr_total_blocks.attr, | ||
97 | &btrfs_super_attr_blocksize.attr, | ||
98 | NULL, | ||
99 | }; | ||
100 | |||
101 | static ssize_t btrfs_super_attr_show(struct kobject *kobj, | ||
102 | struct attribute *attr, char *buf) | ||
103 | { | ||
104 | struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info, | ||
105 | super_kobj); | ||
106 | struct btrfs_super_attr *a = container_of(attr, | ||
107 | struct btrfs_super_attr, | ||
108 | attr); | ||
109 | |||
110 | return a->show ? a->show(fs, buf) : 0; | ||
111 | } | ||
112 | |||
113 | static ssize_t btrfs_super_attr_store(struct kobject *kobj, | ||
114 | struct attribute *attr, | ||
115 | const char *buf, size_t len) | ||
116 | { | ||
117 | struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info, | ||
118 | super_kobj); | ||
119 | struct btrfs_super_attr *a = container_of(attr, | ||
120 | struct btrfs_super_attr, | ||
121 | attr); | ||
122 | |||
123 | return a->store ? a->store(fs, buf, len) : 0; | ||
124 | } | ||
125 | |||
126 | static ssize_t btrfs_root_attr_show(struct kobject *kobj, | ||
127 | struct attribute *attr, char *buf) | ||
128 | { | ||
129 | struct btrfs_root *root = container_of(kobj, struct btrfs_root, | ||
130 | root_kobj); | ||
131 | struct btrfs_root_attr *a = container_of(attr, | ||
132 | struct btrfs_root_attr, | ||
133 | attr); | ||
134 | |||
135 | return a->show ? a->show(root, buf) : 0; | ||
136 | } | ||
137 | |||
138 | static ssize_t btrfs_root_attr_store(struct kobject *kobj, | ||
139 | struct attribute *attr, | ||
140 | const char *buf, size_t len) | ||
141 | { | ||
142 | struct btrfs_root *root = container_of(kobj, struct btrfs_root, | ||
143 | root_kobj); | ||
144 | struct btrfs_root_attr *a = container_of(attr, | ||
145 | struct btrfs_root_attr, | ||
146 | attr); | ||
147 | return a->store ? a->store(root, buf, len) : 0; | ||
148 | } | ||
149 | |||
150 | static void btrfs_super_release(struct kobject *kobj) | ||
151 | { | ||
152 | struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info, | ||
153 | super_kobj); | ||
154 | complete(&fs->kobj_unregister); | ||
155 | } | ||
156 | |||
157 | static void btrfs_root_release(struct kobject *kobj) | ||
158 | { | ||
159 | struct btrfs_root *root = container_of(kobj, struct btrfs_root, | ||
160 | root_kobj); | ||
161 | complete(&root->kobj_unregister); | ||
162 | } | ||
163 | |||
164 | static struct sysfs_ops btrfs_super_attr_ops = { | ||
165 | .show = btrfs_super_attr_show, | ||
166 | .store = btrfs_super_attr_store, | ||
167 | }; | ||
168 | |||
169 | static struct sysfs_ops btrfs_root_attr_ops = { | ||
170 | .show = btrfs_root_attr_show, | ||
171 | .store = btrfs_root_attr_store, | ||
172 | }; | ||
173 | |||
174 | static struct kobj_type btrfs_root_ktype = { | ||
175 | .default_attrs = btrfs_root_attrs, | ||
176 | .sysfs_ops = &btrfs_root_attr_ops, | ||
177 | .release = btrfs_root_release, | ||
178 | }; | ||
179 | |||
180 | static struct kobj_type btrfs_super_ktype = { | ||
181 | .default_attrs = btrfs_super_attrs, | ||
182 | .sysfs_ops = &btrfs_super_attr_ops, | ||
183 | .release = btrfs_super_release, | ||
184 | }; | ||
185 | |||
186 | static struct kset btrfs_kset = { | ||
187 | .kobj = {.name = "btrfs"}, | ||
188 | }; | ||
189 | |||
190 | int btrfs_sysfs_add_super(struct btrfs_fs_info *fs) | ||
191 | { | ||
192 | int error; | ||
193 | |||
194 | fs->super_kobj.kset = &btrfs_kset; | ||
195 | fs->super_kobj.ktype = &btrfs_super_ktype; | ||
196 | |||
197 | error = kobject_set_name(&fs->super_kobj, "%s", | ||
198 | fs->sb->s_id); | ||
199 | if (error) | ||
200 | goto fail; | ||
201 | |||
202 | error = kobject_register(&fs->super_kobj); | ||
203 | if (error) | ||
204 | goto fail; | ||
205 | |||
206 | return 0; | ||
207 | |||
208 | fail: | ||
209 | printk(KERN_ERR "btrfs: sysfs creation for super failed\n"); | ||
210 | return error; | ||
211 | } | ||
212 | |||
213 | int btrfs_sysfs_add_root(struct btrfs_root *root) | ||
214 | { | ||
215 | int error; | ||
216 | |||
217 | root->root_kobj.ktype = &btrfs_root_ktype; | ||
218 | root->root_kobj.parent = &root->fs_info->super_kobj; | ||
219 | |||
220 | error = kobject_set_name(&root->root_kobj, "%s", root->name); | ||
221 | if (error) { | ||
222 | goto fail; | ||
223 | } | ||
224 | |||
225 | error = kobject_register(&root->root_kobj); | ||
226 | if (error) | ||
227 | goto fail; | ||
228 | |||
229 | return 0; | ||
230 | |||
231 | fail: | ||
232 | printk(KERN_ERR "btrfs: sysfs creation for root failed\n"); | ||
233 | return error; | ||
234 | } | ||
235 | |||
236 | void btrfs_sysfs_del_root(struct btrfs_root *root) | ||
237 | { | ||
238 | kobject_unregister(&root->root_kobj); | ||
239 | wait_for_completion(&root->kobj_unregister); | ||
240 | } | ||
241 | |||
242 | void btrfs_sysfs_del_super(struct btrfs_fs_info *fs) | ||
243 | { | ||
244 | kobject_unregister(&fs->super_kobj); | ||
245 | wait_for_completion(&fs->kobj_unregister); | ||
246 | } | ||
247 | |||
248 | int btrfs_init_sysfs() | ||
249 | { | ||
250 | kobj_set_kset_s(&btrfs_kset, fs_subsys); | ||
251 | return kset_register(&btrfs_kset); | ||
252 | } | ||
253 | |||
254 | void btrfs_exit_sysfs() | ||
255 | { | ||
256 | kset_unregister(&btrfs_kset); | ||
257 | } | ||
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 18abea802794..2b15daa3a9f2 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -236,6 +236,7 @@ static int wait_for_commit(struct btrfs_root *root, | |||
236 | struct dirty_root { | 236 | struct dirty_root { |
237 | struct list_head list; | 237 | struct list_head list; |
238 | struct btrfs_root *root; | 238 | struct btrfs_root *root; |
239 | struct btrfs_root *latest_root; | ||
239 | }; | 240 | }; |
240 | 241 | ||
241 | int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list) | 242 | int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list) |
@@ -278,6 +279,15 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
278 | btrfs_root_blocknr(&root->root_item)); | 279 | btrfs_root_blocknr(&root->root_item)); |
279 | brelse(root->commit_root); | 280 | brelse(root->commit_root); |
280 | root->commit_root = NULL; | 281 | root->commit_root = NULL; |
282 | |||
283 | /* make sure to update the root on disk | ||
284 | * so we get any updates to the block used | ||
285 | * counts | ||
286 | */ | ||
287 | err = btrfs_update_root(trans, | ||
288 | root->fs_info->tree_root, | ||
289 | &root->root_key, | ||
290 | &root->root_item); | ||
281 | continue; | 291 | continue; |
282 | } | 292 | } |
283 | dirty = kmalloc(sizeof(*dirty), GFP_NOFS); | 293 | dirty = kmalloc(sizeof(*dirty), GFP_NOFS); |
@@ -291,6 +301,7 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
291 | 301 | ||
292 | memcpy(dirty->root, root, sizeof(*root)); | 302 | memcpy(dirty->root, root, sizeof(*root)); |
293 | dirty->root->node = root->commit_root; | 303 | dirty->root->node = root->commit_root; |
304 | dirty->latest_root = root; | ||
294 | root->commit_root = NULL; | 305 | root->commit_root = NULL; |
295 | 306 | ||
296 | root->root_key.offset = root->fs_info->generation; | 307 | root->root_key.offset = root->fs_info->generation; |
@@ -384,20 +395,29 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, | |||
384 | { | 395 | { |
385 | struct dirty_root *dirty; | 396 | struct dirty_root *dirty; |
386 | struct btrfs_trans_handle *trans; | 397 | struct btrfs_trans_handle *trans; |
398 | u64 num_blocks; | ||
399 | u64 blocks_used; | ||
387 | int ret = 0; | 400 | int ret = 0; |
388 | int err; | 401 | int err; |
389 | 402 | ||
390 | while(!list_empty(list)) { | 403 | while(!list_empty(list)) { |
404 | struct btrfs_root *root; | ||
405 | |||
391 | mutex_lock(&tree_root->fs_info->fs_mutex); | 406 | mutex_lock(&tree_root->fs_info->fs_mutex); |
392 | dirty = list_entry(list->next, struct dirty_root, list); | 407 | dirty = list_entry(list->next, struct dirty_root, list); |
393 | list_del_init(&dirty->list); | 408 | list_del_init(&dirty->list); |
394 | 409 | ||
410 | num_blocks = btrfs_root_blocks_used(&dirty->root->root_item); | ||
411 | root = dirty->latest_root; | ||
412 | |||
395 | while(1) { | 413 | while(1) { |
396 | trans = btrfs_start_transaction(tree_root, 1); | 414 | trans = btrfs_start_transaction(tree_root, 1); |
415 | |||
397 | ret = btrfs_drop_snapshot(trans, dirty->root); | 416 | ret = btrfs_drop_snapshot(trans, dirty->root); |
398 | if (ret != -EAGAIN) { | 417 | if (ret != -EAGAIN) { |
399 | break; | 418 | break; |
400 | } | 419 | } |
420 | |||
401 | err = btrfs_update_root(trans, | 421 | err = btrfs_update_root(trans, |
402 | tree_root, | 422 | tree_root, |
403 | &dirty->root->root_key, | 423 | &dirty->root->root_key, |
@@ -414,9 +434,19 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, | |||
414 | mutex_lock(&tree_root->fs_info->fs_mutex); | 434 | mutex_lock(&tree_root->fs_info->fs_mutex); |
415 | } | 435 | } |
416 | BUG_ON(ret); | 436 | BUG_ON(ret); |
437 | |||
438 | num_blocks -= btrfs_root_blocks_used(&dirty->root->root_item); | ||
439 | blocks_used = btrfs_root_blocks_used(&root->root_item); | ||
440 | if (num_blocks) { | ||
441 | record_root_in_trans(root); | ||
442 | btrfs_set_root_blocks_used(&root->root_item, | ||
443 | blocks_used - num_blocks); | ||
444 | } | ||
417 | ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key); | 445 | ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key); |
418 | if (ret) | 446 | if (ret) { |
447 | BUG(); | ||
419 | break; | 448 | break; |
449 | } | ||
420 | ret = btrfs_end_transaction(trans, tree_root); | 450 | ret = btrfs_end_transaction(trans, tree_root); |
421 | BUG_ON(ret); | 451 | BUG_ON(ret); |
422 | 452 | ||
@@ -534,10 +564,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
534 | wake_up(&cur_trans->commit_wait); | 564 | wake_up(&cur_trans->commit_wait); |
535 | put_transaction(cur_trans); | 565 | put_transaction(cur_trans); |
536 | put_transaction(cur_trans); | 566 | put_transaction(cur_trans); |
567 | |||
537 | if (root->fs_info->closing) | 568 | if (root->fs_info->closing) |
538 | list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); | 569 | list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); |
539 | else | 570 | else |
540 | list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots); | 571 | list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots); |
572 | |||
541 | mutex_unlock(&root->fs_info->trans_mutex); | 573 | mutex_unlock(&root->fs_info->trans_mutex); |
542 | kmem_cache_free(btrfs_trans_handle_cachep, trans); | 574 | kmem_cache_free(btrfs_trans_handle_cachep, trans); |
543 | 575 | ||