diff options
author | Stefan Behrens <sbehrens@giantdisaster.de> | 2012-05-25 10:06:10 -0400 |
---|---|---|
committer | Josef Bacik <josef@redhat.com> | 2012-05-30 10:23:41 -0400 |
commit | 733f4fbbc1083aa343da739f46ee839705d6cfe3 (patch) | |
tree | 0c6dab9e8610eb9b4ccd9a6453caa1588583b1b8 /fs/btrfs/volumes.c | |
parent | c11d2c236cc260b36ef644700fbe99bcc7e7da33 (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/volumes.c')
-rw-r--r-- | fs/btrfs/volumes.c | 176 |
1 files changed, 176 insertions, 0 deletions
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); |
42 | static int btrfs_relocate_sys_chunks(struct btrfs_root *root); | 42 | static int btrfs_relocate_sys_chunks(struct btrfs_root *root); |
43 | static void __btrfs_reset_dev_stats(struct btrfs_device *dev); | ||
44 | static void btrfs_dev_stat_print_on_load(struct btrfs_device *device); | ||
43 | 45 | ||
44 | static DEFINE_MUTEX(uuid_mutex); | 46 | static DEFINE_MUTEX(uuid_mutex); |
45 | static LIST_HEAD(fs_uuids); | 47 | static 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 | ||
4660 | static 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 | |||
4668 | int 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 | |||
4726 | out: | ||
4727 | btrfs_free_path(path); | ||
4728 | return ret < 0 ? ret : 0; | ||
4729 | } | ||
4730 | |||
4731 | static 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 | |||
4786 | out: | ||
4787 | btrfs_free_path(path); | ||
4788 | return ret; | ||
4789 | } | ||
4790 | |||
4791 | /* | ||
4792 | * called from commit_transaction. Writes all changed device stats to disk. | ||
4793 | */ | ||
4794 | int 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 | |||
4657 | void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index) | 4816 | void 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 | ||
4663 | void btrfs_dev_stat_print_on_error(struct btrfs_device *dev) | 4822 | void 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 | ||
4838 | static 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 | |||
4677 | int btrfs_get_dev_stats(struct btrfs_root *root, | 4849 | int 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) |