diff options
-rw-r--r-- | fs/btrfs/ioctl.c | 26 | ||||
-rw-r--r-- | fs/btrfs/ioctl.h | 14 | ||||
-rw-r--r-- | fs/btrfs/volumes.c | 34 | ||||
-rw-r--r-- | fs/btrfs/volumes.h | 3 |
4 files changed, 77 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 15baf9456300..0f8c354c4c76 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -3046,6 +3046,28 @@ static long btrfs_ioctl_scrub_progress(struct btrfs_root *root, | |||
3046 | return ret; | 3046 | return ret; |
3047 | } | 3047 | } |
3048 | 3048 | ||
3049 | static long btrfs_ioctl_get_dev_stats(struct btrfs_root *root, | ||
3050 | void __user *arg, int reset_after_read) | ||
3051 | { | ||
3052 | struct btrfs_ioctl_get_dev_stats *sa; | ||
3053 | int ret; | ||
3054 | |||
3055 | if (reset_after_read && !capable(CAP_SYS_ADMIN)) | ||
3056 | return -EPERM; | ||
3057 | |||
3058 | sa = memdup_user(arg, sizeof(*sa)); | ||
3059 | if (IS_ERR(sa)) | ||
3060 | return PTR_ERR(sa); | ||
3061 | |||
3062 | ret = btrfs_get_dev_stats(root, sa, reset_after_read); | ||
3063 | |||
3064 | if (copy_to_user(arg, sa, sizeof(*sa))) | ||
3065 | ret = -EFAULT; | ||
3066 | |||
3067 | kfree(sa); | ||
3068 | return ret; | ||
3069 | } | ||
3070 | |||
3049 | static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) | 3071 | static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) |
3050 | { | 3072 | { |
3051 | int ret = 0; | 3073 | int ret = 0; |
@@ -3434,6 +3456,10 @@ long btrfs_ioctl(struct file *file, unsigned int | |||
3434 | return btrfs_ioctl_balance_ctl(root, arg); | 3456 | return btrfs_ioctl_balance_ctl(root, arg); |
3435 | case BTRFS_IOC_BALANCE_PROGRESS: | 3457 | case BTRFS_IOC_BALANCE_PROGRESS: |
3436 | return btrfs_ioctl_balance_progress(root, argp); | 3458 | return btrfs_ioctl_balance_progress(root, argp); |
3459 | case BTRFS_IOC_GET_DEV_STATS: | ||
3460 | return btrfs_ioctl_get_dev_stats(root, argp, 0); | ||
3461 | case BTRFS_IOC_GET_AND_RESET_DEV_STATS: | ||
3462 | return btrfs_ioctl_get_dev_stats(root, argp, 1); | ||
3437 | } | 3463 | } |
3438 | 3464 | ||
3439 | return -ENOTTY; | 3465 | return -ENOTTY; |
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h index 5bf05e28b829..497c530724cf 100644 --- a/fs/btrfs/ioctl.h +++ b/fs/btrfs/ioctl.h | |||
@@ -285,6 +285,16 @@ enum btrfs_dev_stat_values { | |||
285 | BTRFS_DEV_STAT_VALUES_MAX | 285 | BTRFS_DEV_STAT_VALUES_MAX |
286 | }; | 286 | }; |
287 | 287 | ||
288 | struct btrfs_ioctl_get_dev_stats { | ||
289 | __u64 devid; /* in */ | ||
290 | __u64 nr_items; /* in/out */ | ||
291 | |||
292 | /* out values: */ | ||
293 | __u64 values[BTRFS_DEV_STAT_VALUES_MAX]; | ||
294 | |||
295 | __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */ | ||
296 | }; | ||
297 | |||
288 | #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ | 298 | #define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ |
289 | struct btrfs_ioctl_vol_args) | 299 | struct btrfs_ioctl_vol_args) |
290 | #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ | 300 | #define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ |
@@ -349,5 +359,9 @@ enum btrfs_dev_stat_values { | |||
349 | struct btrfs_ioctl_ino_path_args) | 359 | struct btrfs_ioctl_ino_path_args) |
350 | #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ | 360 | #define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ |
351 | struct btrfs_ioctl_ino_path_args) | 361 | struct btrfs_ioctl_ino_path_args) |
362 | #define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \ | ||
363 | struct btrfs_ioctl_get_dev_stats) | ||
364 | #define BTRFS_IOC_GET_AND_RESET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \ | ||
365 | struct btrfs_ioctl_get_dev_stats) | ||
352 | 366 | ||
353 | #endif | 367 | #endif |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 2915521f44ee..a112b758822e 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
@@ -4673,3 +4673,37 @@ void btrfs_dev_stat_print_on_error(struct btrfs_device *dev) | |||
4673 | btrfs_dev_stat_read(dev, | 4673 | btrfs_dev_stat_read(dev, |
4674 | BTRFS_DEV_STAT_GENERATION_ERRS)); | 4674 | BTRFS_DEV_STAT_GENERATION_ERRS)); |
4675 | } | 4675 | } |
4676 | |||
4677 | int btrfs_get_dev_stats(struct btrfs_root *root, | ||
4678 | struct btrfs_ioctl_get_dev_stats *stats, | ||
4679 | int reset_after_read) | ||
4680 | { | ||
4681 | struct btrfs_device *dev; | ||
4682 | struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; | ||
4683 | int i; | ||
4684 | |||
4685 | mutex_lock(&fs_devices->device_list_mutex); | ||
4686 | dev = btrfs_find_device(root, stats->devid, NULL, NULL); | ||
4687 | mutex_unlock(&fs_devices->device_list_mutex); | ||
4688 | |||
4689 | if (!dev) { | ||
4690 | printk(KERN_WARNING | ||
4691 | "btrfs: get dev_stats failed, device not found\n"); | ||
4692 | return -ENODEV; | ||
4693 | } else if (reset_after_read) { | ||
4694 | for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) { | ||
4695 | if (stats->nr_items > i) | ||
4696 | stats->values[i] = | ||
4697 | btrfs_dev_stat_read_and_reset(dev, i); | ||
4698 | else | ||
4699 | btrfs_dev_stat_reset(dev, i); | ||
4700 | } | ||
4701 | } else { | ||
4702 | for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) | ||
4703 | if (stats->nr_items > i) | ||
4704 | stats->values[i] = btrfs_dev_stat_read(dev, i); | ||
4705 | } | ||
4706 | if (stats->nr_items > BTRFS_DEV_STAT_VALUES_MAX) | ||
4707 | stats->nr_items = BTRFS_DEV_STAT_VALUES_MAX; | ||
4708 | return 0; | ||
4709 | } | ||
diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 193b2835e6ae..6798f8674b13 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h | |||
@@ -290,6 +290,9 @@ struct btrfs_device *btrfs_find_device_for_logical(struct btrfs_root *root, | |||
290 | u64 logical, int mirror_num); | 290 | u64 logical, int mirror_num); |
291 | void btrfs_dev_stat_print_on_error(struct btrfs_device *device); | 291 | void btrfs_dev_stat_print_on_error(struct btrfs_device *device); |
292 | void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index); | 292 | void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index); |
293 | int btrfs_get_dev_stats(struct btrfs_root *root, | ||
294 | struct btrfs_ioctl_get_dev_stats *stats, | ||
295 | int reset_after_read); | ||
293 | 296 | ||
294 | static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, | 297 | static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, |
295 | int index) | 298 | int index) |