Skip to content

Commit

Permalink
Btrfs: add ioctl to get and reset the device stats
Browse files Browse the repository at this point in the history
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: Stefan Behrens <sbehrens@giantdisaster.de>
  • Loading branch information
Stefan Behrens authored and Josef Bacik committed May 30, 2012
1 parent 442a4f6 commit c11d2c2
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 0 deletions.
26 changes: 26 additions & 0 deletions fs/btrfs/ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
14 changes: 14 additions & 0 deletions fs/btrfs/ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand Down Expand Up @@ -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 changes: 34 additions & 0 deletions fs/btrfs/volumes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 3 additions & 0 deletions fs/btrfs/volumes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit c11d2c2

Please sign in to comment.