aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorStefan Behrens <sbehrens@giantdisaster.de>2012-05-25 10:06:10 -0400
committerJosef Bacik <josef@redhat.com>2012-05-30 10:23:41 -0400
commit733f4fbbc1083aa343da739f46ee839705d6cfe3 (patch)
tree0c6dab9e8610eb9b4ccd9a6453caa1588583b1b8 /fs/btrfs
parentc11d2c236cc260b36ef644700fbe99bcc7e7da33 (diff)
Btrfs: read device stats on mount, write modified ones during commit
The device statistics are written into the device tree with each transaction commit. Only modified statistics are written. When a filesystem is mounted, the device statistics for each involved device are read from the device tree and used to initialize the counters. Signed-off-by: Stefan Behrens <sbehrens@giantdisaster.de>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/ctree.h38
-rw-r--r--fs/btrfs/disk-io.c7
-rw-r--r--fs/btrfs/print-tree.c3
-rw-r--r--fs/btrfs/transaction.c4
-rw-r--r--fs/btrfs/volumes.c176
-rw-r--r--fs/btrfs/volumes.h4
6 files changed, 232 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index aad2600718a3..e176f8c551f7 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -823,6 +823,14 @@ struct btrfs_csum_item {
823 u8 csum; 823 u8 csum;
824} __attribute__ ((__packed__)); 824} __attribute__ ((__packed__));
825 825
826struct btrfs_dev_stats_item {
827 /*
828 * grow this item struct at the end for future enhancements and keep
829 * the existing values unchanged
830 */
831 __le64 values[BTRFS_DEV_STAT_VALUES_MAX];
832} __attribute__ ((__packed__));
833
826/* different types of block groups (and chunks) */ 834/* different types of block groups (and chunks) */
827#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0) 835#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0)
828#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1) 836#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1)
@@ -1508,6 +1516,12 @@ struct btrfs_ioctl_defrag_range_args {
1508#define BTRFS_BALANCE_ITEM_KEY 248 1516#define BTRFS_BALANCE_ITEM_KEY 248
1509 1517
1510/* 1518/*
1519 * Persistantly stores the io stats in the device tree.
1520 * One key for all stats, (0, BTRFS_DEV_STATS_KEY, devid).
1521 */
1522#define BTRFS_DEV_STATS_KEY 249
1523
1524/*
1511 * string items are for debugging. They just store a short string of 1525 * string items are for debugging. They just store a short string of
1512 * data in the FS 1526 * data in the FS
1513 */ 1527 */
@@ -2415,6 +2429,30 @@ static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
2415 return btrfs_item_size(eb, e) - offset; 2429 return btrfs_item_size(eb, e) - offset;
2416} 2430}
2417 2431
2432/* btrfs_dev_stats_item */
2433static inline u64 btrfs_dev_stats_value(struct extent_buffer *eb,
2434 struct btrfs_dev_stats_item *ptr,
2435 int index)
2436{
2437 u64 val;
2438
2439 read_extent_buffer(eb, &val,
2440 offsetof(struct btrfs_dev_stats_item, values) +
2441 ((unsigned long)ptr) + (index * sizeof(u64)),
2442 sizeof(val));
2443 return val;
2444}
2445
2446static inline void btrfs_set_dev_stats_value(struct extent_buffer *eb,
2447 struct btrfs_dev_stats_item *ptr,
2448 int index, u64 val)
2449{
2450 write_extent_buffer(eb, &val,
2451 offsetof(struct btrfs_dev_stats_item, values) +
2452 ((unsigned long)ptr) + (index * sizeof(u64)),
2453 sizeof(val));
2454}
2455
2418static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb) 2456static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb)
2419{ 2457{
2420 return sb->s_fs_info; 2458 return sb->s_fs_info;
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 46d474e74aa4..b0d49e21b0b1 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -2354,6 +2354,13 @@ retry_root_backup:
2354 fs_info->generation = generation; 2354 fs_info->generation = generation;
2355 fs_info->last_trans_committed = generation; 2355 fs_info->last_trans_committed = generation;
2356 2356
2357 ret = btrfs_init_dev_stats(fs_info);
2358 if (ret) {
2359 printk(KERN_ERR "btrfs: failed to init dev_stats: %d\n",
2360 ret);
2361 goto fail_block_groups;
2362 }
2363
2357 ret = btrfs_init_space_info(fs_info); 2364 ret = btrfs_init_space_info(fs_info);
2358 if (ret) { 2365 if (ret) {
2359 printk(KERN_ERR "Failed to initial space info: %d\n", ret); 2366 printk(KERN_ERR "Failed to initial space info: %d\n", ret);
diff --git a/fs/btrfs/print-tree.c b/fs/btrfs/print-tree.c
index f38e452486b8..5e23684887eb 100644
--- a/fs/btrfs/print-tree.c
+++ b/fs/btrfs/print-tree.c
@@ -294,6 +294,9 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
294 btrfs_dev_extent_chunk_offset(l, dev_extent), 294 btrfs_dev_extent_chunk_offset(l, dev_extent),
295 (unsigned long long) 295 (unsigned long long)
296 btrfs_dev_extent_length(l, dev_extent)); 296 btrfs_dev_extent_length(l, dev_extent));
297 case BTRFS_DEV_STATS_KEY:
298 printk(KERN_INFO "\t\tdevice stats\n");
299 break;
297 }; 300 };
298 } 301 }
299} 302}
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 36422254ef67..82b03afcbd92 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -28,6 +28,7 @@
28#include "locking.h" 28#include "locking.h"
29#include "tree-log.h" 29#include "tree-log.h"
30#include "inode-map.h" 30#include "inode-map.h"
31#include "volumes.h"
31 32
32#define BTRFS_ROOT_TRANS_TAG 0 33#define BTRFS_ROOT_TRANS_TAG 0
33 34
@@ -758,6 +759,9 @@ static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans,
758 if (ret) 759 if (ret)
759 return ret; 760 return ret;
760 761
762 ret = btrfs_run_dev_stats(trans, root->fs_info);
763 BUG_ON(ret);
764
761 while (!list_empty(&fs_info->dirty_cowonly_roots)) { 765 while (!list_empty(&fs_info->dirty_cowonly_roots)) {
762 next = fs_info->dirty_cowonly_roots.next; 766 next = fs_info->dirty_cowonly_roots.next;
763 list_del_init(next); 767 list_del_init(next);
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index a112b758822e..7782020996fe 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -40,6 +40,8 @@ static int init_first_rw_device(struct btrfs_trans_handle *trans,
40 struct btrfs_root *root, 40 struct btrfs_root *root,
41 struct btrfs_device *device); 41 struct btrfs_device *device);
42static int btrfs_relocate_sys_chunks(struct btrfs_root *root); 42static int btrfs_relocate_sys_chunks(struct btrfs_root *root);
43static void __btrfs_reset_dev_stats(struct btrfs_device *dev);
44static void btrfs_dev_stat_print_on_load(struct btrfs_device *device);
43 45
44static DEFINE_MUTEX(uuid_mutex); 46static DEFINE_MUTEX(uuid_mutex);
45static LIST_HEAD(fs_uuids); 47static LIST_HEAD(fs_uuids);
@@ -362,6 +364,7 @@ static noinline int device_list_add(const char *path,
362 return -ENOMEM; 364 return -ENOMEM;
363 } 365 }
364 device->devid = devid; 366 device->devid = devid;
367 device->dev_stats_valid = 0;
365 device->work.func = pending_bios_fn; 368 device->work.func = pending_bios_fn;
366 memcpy(device->uuid, disk_super->dev_item.uuid, 369 memcpy(device->uuid, disk_super->dev_item.uuid,
367 BTRFS_UUID_SIZE); 370 BTRFS_UUID_SIZE);
@@ -4654,6 +4657,162 @@ error:
4654 return ret; 4657 return ret;
4655} 4658}
4656 4659
4660static void __btrfs_reset_dev_stats(struct btrfs_device *dev)
4661{
4662 int i;
4663
4664 for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++)
4665 btrfs_dev_stat_reset(dev, i);
4666}
4667
4668int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info)
4669{
4670 struct btrfs_key key;
4671 struct btrfs_key found_key;
4672 struct btrfs_root *dev_root = fs_info->dev_root;
4673 struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
4674 struct extent_buffer *eb;
4675 int slot;
4676 int ret = 0;
4677 struct btrfs_device *device;
4678 struct btrfs_path *path = NULL;
4679 int i;
4680
4681 path = btrfs_alloc_path();
4682 if (!path) {
4683 ret = -ENOMEM;
4684 goto out;
4685 }
4686
4687 mutex_lock(&fs_devices->device_list_mutex);
4688 list_for_each_entry(device, &fs_devices->devices, dev_list) {
4689 int item_size;
4690 struct btrfs_dev_stats_item *ptr;
4691
4692 key.objectid = 0;
4693 key.type = BTRFS_DEV_STATS_KEY;
4694 key.offset = device->devid;
4695 ret = btrfs_search_slot(NULL, dev_root, &key, path, 0, 0);
4696 if (ret) {
4697 printk(KERN_WARNING "btrfs: no dev_stats entry found for device %s (devid %llu) (OK on first mount after mkfs)\n",
4698 device->name, (unsigned long long)device->devid);
4699 __btrfs_reset_dev_stats(device);
4700 device->dev_stats_valid = 1;
4701 btrfs_release_path(path);
4702 continue;
4703 }
4704 slot = path->slots[0];
4705 eb = path->nodes[0];
4706 btrfs_item_key_to_cpu(eb, &found_key, slot);
4707 item_size = btrfs_item_size_nr(eb, slot);
4708
4709 ptr = btrfs_item_ptr(eb, slot,
4710 struct btrfs_dev_stats_item);
4711
4712 for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) {
4713 if (item_size >= (1 + i) * sizeof(__le64))
4714 btrfs_dev_stat_set(device, i,
4715 btrfs_dev_stats_value(eb, ptr, i));
4716 else
4717 btrfs_dev_stat_reset(device, i);
4718 }
4719
4720 device->dev_stats_valid = 1;
4721 btrfs_dev_stat_print_on_load(device);
4722 btrfs_release_path(path);
4723 }
4724 mutex_unlock(&fs_devices->device_list_mutex);
4725
4726out:
4727 btrfs_free_path(path);
4728 return ret < 0 ? ret : 0;
4729}
4730
4731static int update_dev_stat_item(struct btrfs_trans_handle *trans,
4732 struct btrfs_root *dev_root,
4733 struct btrfs_device *device)
4734{
4735 struct btrfs_path *path;
4736 struct btrfs_key key;
4737 struct extent_buffer *eb;
4738 struct btrfs_dev_stats_item *ptr;
4739 int ret;
4740 int i;
4741
4742 key.objectid = 0;
4743 key.type = BTRFS_DEV_STATS_KEY;
4744 key.offset = device->devid;
4745
4746 path = btrfs_alloc_path();
4747 BUG_ON(!path);
4748 ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1);
4749 if (ret < 0) {
4750 printk(KERN_WARNING "btrfs: error %d while searching for dev_stats item for device %s!\n",
4751 ret, device->name);
4752 goto out;
4753 }
4754
4755 if (ret == 0 &&
4756 btrfs_item_size_nr(path->nodes[0], path->slots[0]) < sizeof(*ptr)) {
4757 /* need to delete old one and insert a new one */
4758 ret = btrfs_del_item(trans, dev_root, path);
4759 if (ret != 0) {
4760 printk(KERN_WARNING "btrfs: delete too small dev_stats item for device %s failed %d!\n",
4761 device->name, ret);
4762 goto out;
4763 }
4764 ret = 1;
4765 }
4766
4767 if (ret == 1) {
4768 /* need to insert a new item */
4769 btrfs_release_path(path);
4770 ret = btrfs_insert_empty_item(trans, dev_root, path,
4771 &key, sizeof(*ptr));
4772 if (ret < 0) {
4773 printk(KERN_WARNING "btrfs: insert dev_stats item for device %s failed %d!\n",
4774 device->name, ret);
4775 goto out;
4776 }
4777 }
4778
4779 eb = path->nodes[0];
4780 ptr = btrfs_item_ptr(eb, path->slots[0], struct btrfs_dev_stats_item);
4781 for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++)
4782 btrfs_set_dev_stats_value(eb, ptr, i,
4783 btrfs_dev_stat_read(device, i));
4784 btrfs_mark_buffer_dirty(eb);
4785
4786out:
4787 btrfs_free_path(path);
4788 return ret;
4789}
4790
4791/*
4792 * called from commit_transaction. Writes all changed device stats to disk.
4793 */
4794int btrfs_run_dev_stats(struct btrfs_trans_handle *trans,
4795 struct btrfs_fs_info *fs_info)
4796{
4797 struct btrfs_root *dev_root = fs_info->dev_root;
4798 struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
4799 struct btrfs_device *device;
4800 int ret = 0;
4801
4802 mutex_lock(&fs_devices->device_list_mutex);
4803 list_for_each_entry(device, &fs_devices->devices, dev_list) {
4804 if (!device->dev_stats_valid || !device->dev_stats_dirty)
4805 continue;
4806
4807 ret = update_dev_stat_item(trans, dev_root, device);
4808 if (!ret)
4809 device->dev_stats_dirty = 0;
4810 }
4811 mutex_unlock(&fs_devices->device_list_mutex);
4812
4813 return ret;
4814}
4815
4657void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index) 4816void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index)
4658{ 4817{
4659 btrfs_dev_stat_inc(dev, index); 4818 btrfs_dev_stat_inc(dev, index);
@@ -4662,6 +4821,8 @@ void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index)
4662 4821
4663void btrfs_dev_stat_print_on_error(struct btrfs_device *dev) 4822void btrfs_dev_stat_print_on_error(struct btrfs_device *dev)
4664{ 4823{
4824 if (!dev->dev_stats_valid)
4825 return;
4665 printk_ratelimited(KERN_ERR 4826 printk_ratelimited(KERN_ERR
4666 "btrfs: bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n", 4827 "btrfs: bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n",
4667 dev->name, 4828 dev->name,
@@ -4674,6 +4835,17 @@ void btrfs_dev_stat_print_on_error(struct btrfs_device *dev)
4674 BTRFS_DEV_STAT_GENERATION_ERRS)); 4835 BTRFS_DEV_STAT_GENERATION_ERRS));
4675} 4836}
4676 4837
4838static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev)
4839{
4840 printk(KERN_INFO "btrfs: bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n",
4841 dev->name,
4842 btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS),
4843 btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS),
4844 btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_FLUSH_ERRS),
4845 btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS),
4846 btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_GENERATION_ERRS));
4847}
4848
4677int btrfs_get_dev_stats(struct btrfs_root *root, 4849int btrfs_get_dev_stats(struct btrfs_root *root,
4678 struct btrfs_ioctl_get_dev_stats *stats, 4850 struct btrfs_ioctl_get_dev_stats *stats,
4679 int reset_after_read) 4851 int reset_after_read)
@@ -4690,6 +4862,10 @@ int btrfs_get_dev_stats(struct btrfs_root *root,
4690 printk(KERN_WARNING 4862 printk(KERN_WARNING
4691 "btrfs: get dev_stats failed, device not found\n"); 4863 "btrfs: get dev_stats failed, device not found\n");
4692 return -ENODEV; 4864 return -ENODEV;
4865 } else if (!dev->dev_stats_valid) {
4866 printk(KERN_WARNING
4867 "btrfs: get dev_stats failed, not yet valid\n");
4868 return -ENODEV;
4693 } else if (reset_after_read) { 4869 } else if (reset_after_read) {
4694 for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) { 4870 for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) {
4695 if (stats->nr_items > i) 4871 if (stats->nr_items > i)
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h
index 6798f8674b13..3406a88ca83e 100644
--- a/fs/btrfs/volumes.h
+++ b/fs/btrfs/volumes.h
@@ -109,6 +109,7 @@ struct btrfs_device {
109 109
110 /* disk I/O failure stats. For detailed description refer to 110 /* disk I/O failure stats. For detailed description refer to
111 * enum btrfs_dev_stat_values in ioctl.h */ 111 * enum btrfs_dev_stat_values in ioctl.h */
112 int dev_stats_valid;
112 int dev_stats_dirty; /* counters need to be written to disk */ 113 int dev_stats_dirty; /* counters need to be written to disk */
113 atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX]; 114 atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX];
114}; 115};
@@ -293,6 +294,9 @@ void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index);
293int btrfs_get_dev_stats(struct btrfs_root *root, 294int btrfs_get_dev_stats(struct btrfs_root *root,
294 struct btrfs_ioctl_get_dev_stats *stats, 295 struct btrfs_ioctl_get_dev_stats *stats,
295 int reset_after_read); 296 int reset_after_read);
297int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info);
298int btrfs_run_dev_stats(struct btrfs_trans_handle *trans,
299 struct btrfs_fs_info *fs_info);
296 300
297static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, 301static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
298 int index) 302 int index)