Commit 58176a96 authored by Josef Bacik's avatar Josef Bacik Committed by David Woodhouse

Btrfs: Add per-root block accounting and sysfs entries

Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent b888db2b
...@@ -5,7 +5,7 @@ obj-m := btrfs.o ...@@ -5,7 +5,7 @@ obj-m := btrfs.o
btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ btrfs-y := super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
hash.o file-item.o inode-item.o inode-map.o disk-io.o \ hash.o file-item.o inode-item.o inode-map.o disk-io.o \
transaction.o bit-radix.o inode.o file.o tree-defrag.o \ transaction.o bit-radix.o inode.o file.o tree-defrag.o \
extent_map.o extent_map.o sysfs.o
#btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \ #btrfs-y := ctree.o disk-io.o radix-tree.o extent-tree.o print-tree.o \
# root-tree.o dir-item.o hash.o file-item.o inode-item.o \ # root-tree.o dir-item.o hash.o file-item.o inode-item.o \
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/completion.h>
#include "bit-radix.h" #include "bit-radix.h"
struct btrfs_trans_handle; struct btrfs_trans_handle;
...@@ -313,6 +314,8 @@ struct btrfs_fs_info { ...@@ -313,6 +314,8 @@ struct btrfs_fs_info {
struct list_head trans_list; struct list_head trans_list;
struct list_head dead_roots; struct list_head dead_roots;
struct delayed_work trans_work; struct delayed_work trans_work;
struct kobject super_kobj;
struct completion kobj_unregister;
int do_barriers; int do_barriers;
int closing; int closing;
}; };
...@@ -328,6 +331,8 @@ struct btrfs_root { ...@@ -328,6 +331,8 @@ struct btrfs_root {
struct btrfs_key root_key; struct btrfs_key root_key;
struct btrfs_fs_info *fs_info; struct btrfs_fs_info *fs_info;
struct inode *inode; struct inode *inode;
struct kobject root_kobj;
struct completion kobj_unregister;
u64 objectid; u64 objectid;
u64 last_trans; u64 last_trans;
u32 blocksize; u32 blocksize;
...@@ -338,6 +343,7 @@ struct btrfs_root { ...@@ -338,6 +343,7 @@ struct btrfs_root {
struct btrfs_key defrag_progress; struct btrfs_key defrag_progress;
int defrag_running; int defrag_running;
int defrag_level; int defrag_level;
char *name;
}; };
/* the lower bits in the key flags defines the item type */ /* 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,6 +820,28 @@ static inline void btrfs_set_root_flags(struct btrfs_root_item *item, u32 val)
item->flags = cpu_to_le32(val); item->flags = cpu_to_le32(val);
} }
static inline void btrfs_set_root_blocks_used(struct btrfs_root_item *item,
u64 val)
{
item->blocks_used = cpu_to_le64(val);
}
static inline u64 btrfs_root_blocks_used(struct btrfs_root_item *item)
{
return le64_to_cpu(item->blocks_used);
}
static inline void btrfs_set_root_block_limit(struct btrfs_root_item *item,
u64 val)
{
item->block_limit = cpu_to_le64(val);
}
static inline u64 btrfs_root_block_limit(struct btrfs_root_item *item)
{
return le64_to_cpu(item->block_limit);
}
static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s) static inline u64 btrfs_super_blocknr(struct btrfs_super_block *s)
{ {
return le64_to_cpu(s->blocknr); return le64_to_cpu(s->blocknr);
...@@ -1014,6 +1042,23 @@ static inline void btrfs_memmove(struct btrfs_root *root, ...@@ -1014,6 +1042,23 @@ static inline void btrfs_memmove(struct btrfs_root *root,
memmove(dst, src, nr); memmove(dst, src, nr);
} }
static inline int btrfs_set_root_name(struct btrfs_root *root,
const char *name, int len)
{
/* if we already have a name just free it */
if (root->name)
kfree(root->name);
root->name = kmalloc(len+1, GFP_KERNEL);
if (!root->name)
return -ENOMEM;
memcpy(root->name, name, len);
root->name[len] ='\0';
return 0;
}
/* helper function to cast into the data area of the leaf. */ /* helper function to cast into the data area of the leaf. */
#define btrfs_item_ptr(leaf, slot, type) \ #define btrfs_item_ptr(leaf, slot, type) \
((type *)(btrfs_leaf_data(leaf) + \ ((type *)(btrfs_leaf_data(leaf) + \
...@@ -1191,4 +1236,13 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -1191,4 +1236,13 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
/* tree-defrag.c */ /* tree-defrag.c */
int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
struct btrfs_root *root, int cache_only); struct btrfs_root *root, int cache_only);
/* sysfs.c */
int btrfs_init_sysfs(void);
void btrfs_exit_sysfs(void);
int btrfs_sysfs_add_super(struct btrfs_fs_info *fs);
int btrfs_sysfs_add_root(struct btrfs_root *root);
void btrfs_sysfs_del_root(struct btrfs_root *root);
void btrfs_sysfs_del_super(struct btrfs_fs_info *root);
#endif #endif
...@@ -294,9 +294,12 @@ static int __setup_root(int blocksize, ...@@ -294,9 +294,12 @@ static int __setup_root(int blocksize,
root->last_trans = 0; root->last_trans = 0;
root->highest_inode = 0; root->highest_inode = 0;
root->last_inode_alloc = 0; root->last_inode_alloc = 0;
root->name = NULL;
memset(&root->root_key, 0, sizeof(root->root_key)); memset(&root->root_key, 0, sizeof(root->root_key));
memset(&root->root_item, 0, sizeof(root->root_item)); memset(&root->root_item, 0, sizeof(root->root_item));
memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); memset(&root->defrag_progress, 0, sizeof(root->defrag_progress));
memset(&root->root_kobj, 0, sizeof(root->root_kobj));
init_completion(&root->kobj_unregister);
root->defrag_running = 0; root->defrag_running = 0;
root->defrag_level = 0; root->defrag_level = 0;
root->root_key.objectid = objectid; root->root_key.objectid = objectid;
...@@ -384,7 +387,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, ...@@ -384,7 +387,8 @@ struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
} }
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *location) struct btrfs_key *location,
const char *name, int namelen)
{ {
struct btrfs_root *root; struct btrfs_root *root;
int ret; int ret;
...@@ -405,6 +409,22 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, ...@@ -405,6 +409,22 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
kfree(root); kfree(root);
return ERR_PTR(ret); return ERR_PTR(ret);
} }
ret = btrfs_set_root_name(root, name, namelen);
if (ret) {
brelse(root->node);
kfree(root);
return ERR_PTR(ret);
}
ret = btrfs_sysfs_add_root(root);
if (ret) {
brelse(root->node);
kfree(root->name);
kfree(root);
return ERR_PTR(ret);
}
return root; return root;
} }
...@@ -433,6 +453,8 @@ struct btrfs_root *open_ctree(struct super_block *sb) ...@@ -433,6 +453,8 @@ struct btrfs_root *open_ctree(struct super_block *sb)
INIT_RADIX_TREE(&fs_info->block_group_data_radix, GFP_KERNEL); INIT_RADIX_TREE(&fs_info->block_group_data_radix, GFP_KERNEL);
INIT_LIST_HEAD(&fs_info->trans_list); INIT_LIST_HEAD(&fs_info->trans_list);
INIT_LIST_HEAD(&fs_info->dead_roots); INIT_LIST_HEAD(&fs_info->dead_roots);
memset(&fs_info->super_kobj, 0, sizeof(fs_info->super_kobj));
init_completion(&fs_info->kobj_unregister);
sb_set_blocksize(sb, 4096); sb_set_blocksize(sb, 4096);
fs_info->running_transaction = NULL; fs_info->running_transaction = NULL;
fs_info->last_trans_committed = 0; fs_info->last_trans_committed = 0;
...@@ -500,8 +522,10 @@ struct btrfs_root *open_ctree(struct super_block *sb) ...@@ -500,8 +522,10 @@ struct btrfs_root *open_ctree(struct super_block *sb)
fs_info->generation = btrfs_super_generation(disk_super) + 1; fs_info->generation = btrfs_super_generation(disk_super) + 1;
ret = btrfs_find_dead_roots(tree_root); ret = btrfs_find_dead_roots(tree_root);
if (ret) if (ret) {
mutex_unlock(&fs_info->fs_mutex);
goto fail_tree_root; goto fail_tree_root;
}
mutex_unlock(&fs_info->fs_mutex); mutex_unlock(&fs_info->fs_mutex);
return tree_root; return tree_root;
...@@ -553,12 +577,15 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root) ...@@ -553,12 +577,15 @@ int btrfs_free_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *root)
{ {
radix_tree_delete(&fs_info->fs_roots_radix, radix_tree_delete(&fs_info->fs_roots_radix,
(unsigned long)root->root_key.objectid); (unsigned long)root->root_key.objectid);
btrfs_sysfs_del_root(root);
if (root->inode) if (root->inode)
iput(root->inode); iput(root->inode);
if (root->node) if (root->node)
brelse(root->node); brelse(root->node);
if (root->commit_root) if (root->commit_root)
brelse(root->commit_root); brelse(root->commit_root);
if (root->name)
kfree(root->name);
kfree(root); kfree(root);
return 0; return 0;
} }
......
...@@ -66,7 +66,8 @@ struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr); ...@@ -66,7 +66,8 @@ struct buffer_head *btrfs_find_tree_block(struct btrfs_root *root, u64 blocknr);
int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len, int btrfs_csum_data(struct btrfs_root * root, char *data, size_t len,
char *result); char *result);
struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_read_fs_root(struct btrfs_fs_info *fs_info,
struct btrfs_key *location); struct btrfs_key *location,
const char *name, int namelen);
struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info, struct btrfs_root *btrfs_read_fs_root_no_radix(struct btrfs_fs_info *fs_info,
struct btrfs_key *location); struct btrfs_key *location);
u64 bh_blocknr(struct buffer_head *bh); u64 bh_blocknr(struct buffer_head *bh);
......
...@@ -858,16 +858,23 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root ...@@ -858,16 +858,23 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
btrfs_set_extent_refs(ei, refs); btrfs_set_extent_refs(ei, refs);
btrfs_mark_buffer_dirty(path->nodes[0]); btrfs_mark_buffer_dirty(path->nodes[0]);
if (refs == 0) { if (refs == 0) {
u64 super_blocks_used; u64 super_blocks_used, root_blocks_used;
if (pin) { if (pin) {
ret = pin_down_block(root, blocknr, 0); ret = pin_down_block(root, blocknr, 0);
BUG_ON(ret); BUG_ON(ret);
} }
/* block accounting for super block */
super_blocks_used = btrfs_super_blocks_used(&info->super_copy); super_blocks_used = btrfs_super_blocks_used(&info->super_copy);
btrfs_set_super_blocks_used(&info->super_copy, btrfs_set_super_blocks_used(&info->super_copy,
super_blocks_used - num_blocks); super_blocks_used - num_blocks);
/* block accounting for root item */
root_blocks_used = btrfs_root_blocks_used(&root->root_item);
btrfs_set_root_blocks_used(&root->root_item,
root_blocks_used - num_blocks);
ret = btrfs_del_item(trans, extent_root, path); ret = btrfs_del_item(trans, extent_root, path);
if (ret) { if (ret) {
return ret; return ret;
...@@ -1175,7 +1182,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, ...@@ -1175,7 +1182,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
{ {
int ret; int ret;
int pending_ret; int pending_ret;
u64 super_blocks_used; u64 super_blocks_used, root_blocks_used;
u64 search_start = 0; u64 search_start = 0;
struct btrfs_fs_info *info = root->fs_info; struct btrfs_fs_info *info = root->fs_info;
struct btrfs_root *extent_root = info->extent_root; struct btrfs_root *extent_root = info->extent_root;
...@@ -1193,10 +1200,16 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, ...@@ -1193,10 +1200,16 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
if (ret) if (ret)
return ret; return ret;
/* block accounting for super block */
super_blocks_used = btrfs_super_blocks_used(&info->super_copy); super_blocks_used = btrfs_super_blocks_used(&info->super_copy);
btrfs_set_super_blocks_used(&info->super_copy, super_blocks_used + btrfs_set_super_blocks_used(&info->super_copy, super_blocks_used +
num_blocks); num_blocks);
/* block accounting for root item */
root_blocks_used = btrfs_root_blocks_used(&root->root_item);
btrfs_set_root_blocks_used(&root->root_item, root_blocks_used +
num_blocks);
if (root == extent_root) { if (root == extent_root) {
BUG_ON(num_blocks != 1); BUG_ON(num_blocks != 1);
set_radix_bit(&root->fs_info->extent_ins_radix, ins->objectid); set_radix_bit(&root->fs_info->extent_ins_radix, ins->objectid);
......
...@@ -733,7 +733,8 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, ...@@ -733,7 +733,8 @@ static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry,
*/ */
static int fixup_tree_root_location(struct btrfs_root *root, static int fixup_tree_root_location(struct btrfs_root *root,
struct btrfs_key *location, struct btrfs_key *location,
struct btrfs_root **sub_root) struct btrfs_root **sub_root,
struct dentry *dentry)
{ {
struct btrfs_path *path; struct btrfs_path *path;
struct btrfs_root_item *ri; struct btrfs_root_item *ri;
...@@ -747,7 +748,9 @@ static int fixup_tree_root_location(struct btrfs_root *root, ...@@ -747,7 +748,9 @@ static int fixup_tree_root_location(struct btrfs_root *root,
BUG_ON(!path); BUG_ON(!path);
mutex_lock(&root->fs_info->fs_mutex); mutex_lock(&root->fs_info->fs_mutex);
*sub_root = btrfs_read_fs_root(root->fs_info, location); *sub_root = btrfs_read_fs_root(root->fs_info, location,
dentry->d_name.name,
dentry->d_name.len);
if (IS_ERR(*sub_root)) if (IS_ERR(*sub_root))
return PTR_ERR(*sub_root); return PTR_ERR(*sub_root);
...@@ -812,7 +815,8 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, ...@@ -812,7 +815,8 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(ret); return ERR_PTR(ret);
inode = NULL; inode = NULL;
if (location.objectid) { if (location.objectid) {
ret = fixup_tree_root_location(root, &location, &sub_root); ret = fixup_tree_root_location(root, &location, &sub_root,
dentry);
if (ret < 0) if (ret < 0)
return ERR_PTR(ret); return ERR_PTR(ret);
if (ret > 0) if (ret > 0)
...@@ -1829,6 +1833,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen) ...@@ -1829,6 +1833,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol)); btrfs_set_root_blocknr(&root_item, bh_blocknr(subvol));
btrfs_set_root_refs(&root_item, 1); btrfs_set_root_refs(&root_item, 1);
btrfs_set_root_blocks_used(&root_item, 0);
memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress)); memset(&root_item.drop_progress, 0, sizeof(root_item.drop_progress));
root_item.drop_level = 0; root_item.drop_level = 0;
brelse(subvol); brelse(subvol);
...@@ -1865,7 +1870,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen) ...@@ -1865,7 +1870,7 @@ static int create_subvol(struct btrfs_root *root, char *name, int namelen)
if (ret) if (ret)
goto fail_commit; goto fail_commit;
new_root = btrfs_read_fs_root(root->fs_info, &key); new_root = btrfs_read_fs_root(root->fs_info, &key, name, namelen);
BUG_ON(!new_root); BUG_ON(!new_root);
trans = btrfs_start_transaction(new_root, 1); trans = btrfs_start_transaction(new_root, 1);
......
...@@ -45,12 +45,14 @@ static struct super_operations btrfs_super_ops; ...@@ -45,12 +45,14 @@ static struct super_operations btrfs_super_ops;
static void btrfs_put_super (struct super_block * sb) static void btrfs_put_super (struct super_block * sb)
{ {
struct btrfs_root *root = btrfs_sb(sb); struct btrfs_root *root = btrfs_sb(sb);
struct btrfs_fs_info *fs = root->fs_info;
int ret; int ret;
ret = close_ctree(root); ret = close_ctree(root);
if (ret) { if (ret) {
printk("close ctree returns %d\n", ret); printk("close ctree returns %d\n", ret);
} }
btrfs_sysfs_del_super(fs);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
} }
...@@ -101,6 +103,12 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent) ...@@ -101,6 +103,12 @@ static int btrfs_fill_super(struct super_block * sb, void * data, int silent)
err = -ENOMEM; err = -ENOMEM;
goto fail_close; goto fail_close;
} }
/* this does the super kobj at the same time */
err = btrfs_sysfs_add_super(tree_root->fs_info);
if (err)
goto fail_close;
sb->s_root = root_dentry; sb->s_root = root_dentry;
btrfs_transaction_queue_work(tree_root, HZ * 30); btrfs_transaction_queue_work(tree_root, HZ * 30);
return 0; return 0;
...@@ -182,6 +190,11 @@ static struct super_operations btrfs_super_ops = { ...@@ -182,6 +190,11 @@ static struct super_operations btrfs_super_ops = {
static int __init init_btrfs_fs(void) static int __init init_btrfs_fs(void)
{ {
int err; int err;
err = btrfs_init_sysfs();
if (err)
return err;
btrfs_init_transaction_sys(); btrfs_init_transaction_sys();
err = btrfs_init_cachep(); err = btrfs_init_cachep();
if (err) if (err)
...@@ -196,6 +209,7 @@ static void __exit exit_btrfs_fs(void) ...@@ -196,6 +209,7 @@ static void __exit exit_btrfs_fs(void)
btrfs_destroy_cachep(); btrfs_destroy_cachep();
extent_map_exit(); extent_map_exit();
unregister_filesystem(&btrfs_fs_type); unregister_filesystem(&btrfs_fs_type);
btrfs_exit_sysfs();
} }
module_init(init_btrfs_fs) module_init(init_btrfs_fs)
......
...@@ -16,6 +16,242 @@ ...@@ -16,6 +16,242 @@
* Boston, MA 021110-1307, USA. * Boston, MA 021110-1307, USA.
*/ */
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/module.h>
#include <linux/kobject.h>
#include "ctree.h" #include "ctree.h"
#include "disk-io.h" #include "disk-io.h"
#include "transaction.h" #include "transaction.h"
static ssize_t root_blocks_used_show(struct btrfs_root *root, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)btrfs_root_blocks_used(&root->root_item));
}
static ssize_t root_block_limit_show(struct btrfs_root *root, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)btrfs_root_block_limit(&root->root_item));
}
static ssize_t super_blocks_used_show(struct btrfs_fs_info *fs, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)btrfs_super_blocks_used(fs->disk_super));
}
static ssize_t super_total_blocks_show(struct btrfs_fs_info *fs, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)btrfs_super_total_blocks(fs->disk_super));
}
static ssize_t super_blocksize_show(struct btrfs_fs_info *fs, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%llu\n",
(unsigned long long)btrfs_super_blocksize(fs->disk_super));
}
/* this is for root attrs (subvols/snapshots) */
struct btrfs_root_attr {
struct attribute attr;
ssize_t (*show)(struct btrfs_root *, char *);
ssize_t (*store)(struct btrfs_root *, const char *, size_t);
};
#define ROOT_ATTR(name, mode, show, store) \
static struct btrfs_root_attr btrfs_root_attr_##name = __ATTR(name, mode, show, store)
ROOT_ATTR(blocks_used, 0444, root_blocks_used_show, NULL);
ROOT_ATTR(block_limit, 0644, root_block_limit_show, NULL);
static struct attribute *btrfs_root_attrs[] = {
&btrfs_root_attr_blocks_used.attr,
&btrfs_root_attr_block_limit.attr,
NULL,
};
/* this is for super attrs (actual full fs) */
struct btrfs_super_attr {
struct attribute attr;
ssize_t (*show)(struct btrfs_fs_info *, char *);
ssize_t (*store)(struct btrfs_fs_info *, const char *, size_t);
};
#define SUPER_ATTR(name, mode, show, store) \
static struct btrfs_super_attr btrfs_super_attr_##name = __ATTR(name, mode, show, store)
SUPER_ATTR(blocks_used, 0444, super_blocks_used_show, NULL);
SUPER_ATTR(total_blocks, 0444, super_total_blocks_show, NULL);
SUPER_ATTR(blocksize, 0444, super_blocksize_show, NULL);
static struct attribute *btrfs_super_attrs[] = {
&btrfs_super_attr_blocks_used.attr,
&btrfs_super_attr_total_blocks.attr,
&btrfs_super_attr_blocksize.attr,
NULL,
};
static ssize_t btrfs_super_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info,
super_kobj);
struct btrfs_super_attr *a = container_of(attr,
struct btrfs_super_attr,
attr);
return a->show ? a->show(fs, buf) : 0;
}
static ssize_t btrfs_super_attr_store(struct kobject *kobj,
struct attribute *attr,
const char *buf, size_t len)
{
struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info,
super_kobj);
struct btrfs_super_attr *a = container_of(attr,
struct btrfs_super_attr,
attr);
return a->store ? a->store(fs, buf, len) : 0;
}
static ssize_t btrfs_root_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct btrfs_root *root = container_of(kobj, struct btrfs_root,
root_kobj);
struct btrfs_root_attr *a = container_of(attr,
struct btrfs_root_attr,
attr);
return a->show ? a->show(root, buf) : 0;
}
static ssize_t btrfs_root_attr_store(struct kobject *kobj,
struct attribute *attr,
const char *buf, size_t len)
{
struct btrfs_root *root = container_of(kobj, struct btrfs_root,
root_kobj);
struct btrfs_root_attr *a = container_of(attr,
struct btrfs_root_attr,
attr);
return a->store ? a->store(root, buf, len) : 0;
}
static void btrfs_super_release(struct kobject *kobj)
{
struct btrfs_fs_info *fs = container_of(kobj, struct btrfs_fs_info,
super_kobj);
complete(&fs->kobj_unregister);
}
static void btrfs_root_release(struct kobject *kobj)
{
struct btrfs_root *root = container_of(kobj, struct btrfs_root,
root_kobj);
complete(&root->kobj_unregister);
}
static struct sysfs_ops btrfs_super_attr_ops = {
.show = btrfs_super_attr_show,
.store = btrfs_super_attr_store,
};
static struct sysfs_ops btrfs_root_attr_ops = {
.show = btrfs_root_attr_show,
.store = btrfs_root_attr_store,
};
static struct kobj_type btrfs_root_ktype = {
.default_attrs = btrfs_root_attrs,
.sysfs_ops = &btrfs_root_attr_ops,
.release = btrfs_root_release,
};
static struct kobj_type btrfs_super_ktype = {
.default_attrs = btrfs_super_attrs,
.sysfs_ops = &btrfs_super_attr_ops,
.release = btrfs_super_release,
};
static struct kset btrfs_kset = {
.kobj = {.name = "btrfs"},
};
int btrfs_sysfs_add_super(struct btrfs_fs_info *fs)
{
int error;
fs->super_kobj.kset = &btrfs_kset;
fs->super_kobj.ktype = &btrfs_super_ktype;
error = kobject_set_name(&fs->super_kobj, "%s",
fs->sb->s_id);
if (error)
goto fail;
error = kobject_register(&fs->super_kobj);
if (error)
goto fail;
return 0;
fail:
printk(KERN_ERR "btrfs: sysfs creation for super failed\n");
return error;
}
int btrfs_sysfs_add_root(struct btrfs_root *root)
{
int error;
root->root_kobj.ktype = &btrfs_root_ktype;
root->root_kobj.parent = &root->fs_info->super_kobj;
error = kobject_set_name(&root->root_kobj, "%s", root->name);
if (error) {
goto fail;
}
error = kobject_register(&root->root_kobj);
if (error)
goto fail;
return 0;
fail:
printk(KERN_ERR "btrfs: sysfs creation for root failed\n");
return error;
}
void btrfs_sysfs_del_root(struct btrfs_root *root)
{
kobject_unregister(&root->root_kobj);
wait_for_completion(&root->kobj_unregister);
}
void btrfs_sysfs_del_super(struct btrfs_fs_info *fs)
{
kobject_unregister(&fs->super_kobj);
wait_for_completion(&fs->kobj_unregister);
}
int btrfs_init_sysfs()
{
kobj_set_kset_s(&btrfs_kset, fs_subsys);
return kset_register(&btrfs_kset);
}
void btrfs_exit_sysfs()
{
kset_unregister(&btrfs_kset);
}
...@@ -236,6 +236,7 @@ static int wait_for_commit(struct btrfs_root *root, ...@@ -236,6 +236,7 @@ static int wait_for_commit(struct btrfs_root *root,
struct dirty_root { struct dirty_root {
struct list_head list; struct list_head list;
struct btrfs_root *root; struct btrfs_root *root;
struct btrfs_root *latest_root;
}; };
int btrfs_add_dead_root(struct btrfs_root *root, struct list_head *dead_list) 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,6 +279,15 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans,
btrfs_root_blocknr(&root->root_item)); btrfs_root_blocknr(&root->root_item));
brelse(root->commit_root); brelse(root->commit_root);
root->commit_root = NULL; root->commit_root = NULL;
/* make sure to update the root on disk
* so we get any updates to the block used
* counts
*/
err = btrfs_update_root(trans,
root->fs_info->tree_root,
&root->root_key,
&root->root_item);
continue; continue;
} }
dirty = kmalloc(sizeof(*dirty), GFP_NOFS); dirty = kmalloc(sizeof(*dirty), GFP_NOFS);
...@@ -291,6 +301,7 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans, ...@@ -291,6 +301,7 @@ static int add_dirty_roots(struct btrfs_trans_handle *trans,
memcpy(dirty->root, root, sizeof(*root)); memcpy(dirty->root, root, sizeof(*root));
dirty->root->node = root->commit_root; dirty->root->node = root->commit_root;
dirty->latest_root = root;
root->commit_root = NULL; root->commit_root = NULL;
root->root_key.offset = root->fs_info->generation; root->root_key.offset = root->fs_info->generation;
...@@ -384,20 +395,29 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, ...@@ -384,20 +395,29 @@ static int drop_dirty_roots(struct btrfs_root *tree_root,
{ {
struct dirty_root *dirty; struct dirty_root *dirty;
struct btrfs_trans_handle *trans; struct btrfs_trans_handle *trans;
u64 num_blocks;
u64 blocks_used;
int ret = 0; int ret = 0;
int err; int err;
while(!list_empty(list)) { while(!list_empty(list)) {
struct btrfs_root *root;
mutex_lock(&tree_root->fs_info->fs_mutex); mutex_lock(&tree_root->fs_info->fs_mutex);
dirty = list_entry(list->next, struct dirty_root, list); dirty = list_entry(list->next, struct dirty_root, list);
list_del_init(&dirty->list); list_del_init(&dirty->list);
num_blocks = btrfs_root_blocks_used(&dirty->root->root_item);
root = dirty->latest_root;
while(1) { while(1) {
trans = btrfs_start_transaction(tree_root, 1); trans = btrfs_start_transaction(tree_root, 1);
ret = btrfs_drop_snapshot(trans, dirty->root); ret = btrfs_drop_snapshot(trans, dirty->root);
if (ret != -EAGAIN) { if (ret != -EAGAIN) {
break; break;
} }
err = btrfs_update_root(trans, err = btrfs_update_root(trans,
tree_root, tree_root,
&dirty->root->root_key, &dirty->root->root_key,
...@@ -414,9 +434,19 @@ static int drop_dirty_roots(struct btrfs_root *tree_root, ...@@ -414,9 +434,19 @@ static int drop_dirty_roots(struct btrfs_root *tree_root,
mutex_lock(&tree_root->fs_info->fs_mutex); mutex_lock(&tree_root->fs_info->fs_mutex);
} }
BUG_ON(ret); BUG_ON(ret);
num_blocks -= btrfs_root_blocks_used(&dirty->root->root_item);
blocks_used = btrfs_root_blocks_used(&root->root_item);
if (num_blocks) {
record_root_in_trans(root);
btrfs_set_root_blocks_used(&root->root_item,
blocks_used - num_blocks);
}
ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key); ret = btrfs_del_root(trans, tree_root, &dirty->root->root_key);
if (ret) if (ret) {
BUG();
break; break;
}
ret = btrfs_end_transaction(trans, tree_root); ret = btrfs_end_transaction(trans, tree_root);
BUG_ON(ret); BUG_ON(ret);
...@@ -534,10 +564,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, ...@@ -534,10 +564,12 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
wake_up(&cur_trans->commit_wait); wake_up(&cur_trans->commit_wait);
put_transaction(cur_trans); put_transaction(cur_trans);
put_transaction(cur_trans); put_transaction(cur_trans);
if (root->fs_info->closing) if (root->fs_info->closing)
list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots); list_splice_init(&root->fs_info->dead_roots, &dirty_fs_roots);
else else
list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots); list_splice_init(&dirty_fs_roots, &root->fs_info->dead_roots);
mutex_unlock(&root->fs_info->trans_mutex); mutex_unlock(&root->fs_info->trans_mutex);
kmem_cache_free(btrfs_trans_handle_cachep, trans); kmem_cache_free(btrfs_trans_handle_cachep, trans);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment