Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c11d2c23 authored by Stefan Behrens's avatar Stefan Behrens Committed by Josef Bacik
Browse files

Btrfs: add ioctl to get and reset the device stats



An ioctl interface is added to get the device statistic counters.
A second ioctl is added to atomically get and reset these counters.

Signed-off-by: default avatarStefan Behrens <sbehrens@giantdisaster.de>
parent 442a4f63
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -3046,6 +3046,28 @@ static long btrfs_ioctl_scrub_progress(struct btrfs_root *root,
	return ret;
}

static long btrfs_ioctl_get_dev_stats(struct btrfs_root *root,
				      void __user *arg, int reset_after_read)
{
	struct btrfs_ioctl_get_dev_stats *sa;
	int ret;

	if (reset_after_read && !capable(CAP_SYS_ADMIN))
		return -EPERM;

	sa = memdup_user(arg, sizeof(*sa));
	if (IS_ERR(sa))
		return PTR_ERR(sa);

	ret = btrfs_get_dev_stats(root, sa, reset_after_read);

	if (copy_to_user(arg, sa, sizeof(*sa)))
		ret = -EFAULT;

	kfree(sa);
	return ret;
}

static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg)
{
	int ret = 0;
@@ -3434,6 +3456,10 @@ long btrfs_ioctl(struct file *file, unsigned int
		return btrfs_ioctl_balance_ctl(root, arg);
	case BTRFS_IOC_BALANCE_PROGRESS:
		return btrfs_ioctl_balance_progress(root, argp);
	case BTRFS_IOC_GET_DEV_STATS:
		return btrfs_ioctl_get_dev_stats(root, argp, 0);
	case BTRFS_IOC_GET_AND_RESET_DEV_STATS:
		return btrfs_ioctl_get_dev_stats(root, argp, 1);
	}

	return -ENOTTY;
+14 −0
Original line number Diff line number Diff line
@@ -285,6 +285,16 @@ enum btrfs_dev_stat_values {
	BTRFS_DEV_STAT_VALUES_MAX
};

struct btrfs_ioctl_get_dev_stats {
	__u64 devid;				/* in */
	__u64 nr_items;				/* in/out */

	/* out values: */
	__u64 values[BTRFS_DEV_STAT_VALUES_MAX];

	__u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */
};

#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \
				   struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \
@@ -349,5 +359,9 @@ enum btrfs_dev_stat_values {
					struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \
					struct btrfs_ioctl_ino_path_args)
#define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \
				      struct btrfs_ioctl_get_dev_stats)
#define BTRFS_IOC_GET_AND_RESET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 53, \
					struct btrfs_ioctl_get_dev_stats)

#endif
+34 −0
Original line number Diff line number Diff line
@@ -4673,3 +4673,37 @@ void btrfs_dev_stat_print_on_error(struct btrfs_device *dev)
			   btrfs_dev_stat_read(dev,
					       BTRFS_DEV_STAT_GENERATION_ERRS));
}

int btrfs_get_dev_stats(struct btrfs_root *root,
			struct btrfs_ioctl_get_dev_stats *stats,
			int reset_after_read)
{
	struct btrfs_device *dev;
	struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices;
	int i;

	mutex_lock(&fs_devices->device_list_mutex);
	dev = btrfs_find_device(root, stats->devid, NULL, NULL);
	mutex_unlock(&fs_devices->device_list_mutex);

	if (!dev) {
		printk(KERN_WARNING
		       "btrfs: get dev_stats failed, device not found\n");
		return -ENODEV;
	} else if (reset_after_read) {
		for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) {
			if (stats->nr_items > i)
				stats->values[i] =
					btrfs_dev_stat_read_and_reset(dev, i);
			else
				btrfs_dev_stat_reset(dev, i);
		}
	} else {
		for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++)
			if (stats->nr_items > i)
				stats->values[i] = btrfs_dev_stat_read(dev, i);
	}
	if (stats->nr_items > BTRFS_DEV_STAT_VALUES_MAX)
		stats->nr_items = BTRFS_DEV_STAT_VALUES_MAX;
	return 0;
}
+3 −0
Original line number Diff line number Diff line
@@ -290,6 +290,9 @@ struct btrfs_device *btrfs_find_device_for_logical(struct btrfs_root *root,
						   u64 logical, int mirror_num);
void btrfs_dev_stat_print_on_error(struct btrfs_device *device);
void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index);
int btrfs_get_dev_stats(struct btrfs_root *root,
			struct btrfs_ioctl_get_dev_stats *stats,
			int reset_after_read);

static inline void btrfs_dev_stat_inc(struct btrfs_device *dev,
				      int index)