aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ioctl.c26
-rw-r--r--fs/btrfs/ioctl.h14
-rw-r--r--fs/btrfs/volumes.c34
-rw-r--r--fs/btrfs/volumes.h3
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
3049static 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
3049static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) 3071static 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
288struct 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
4677int 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);
291void btrfs_dev_stat_print_on_error(struct btrfs_device *device); 291void btrfs_dev_stat_print_on_error(struct btrfs_device *device);
292void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index); 292void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index);
293int btrfs_get_dev_stats(struct btrfs_root *root,
294 struct btrfs_ioctl_get_dev_stats *stats,
295 int reset_after_read);
293 296
294static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, 297static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
295 int index) 298 int index)