Introduces devid readmirror property, which directs all read IO to a device.
For example: btrfs property set <mnt> readmirror devid<n> As of now readmirror by devid supports only raid1s. Raid10 support has to leverage device grouping feature to facilitate the setting of readmirror by device set. Signed-off-by: Anand Jain <anand.j...@oracle.com> --- fs/btrfs/props.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++--- fs/btrfs/volumes.c | 16 ++++++++++++++++ fs/btrfs/volumes.h | 3 +++ 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c index 776cdf099f93..a17c5a69bcb3 100644 --- a/fs/btrfs/props.c +++ b/fs/btrfs/props.c @@ -338,8 +338,28 @@ static int prop_readmirror_validate(struct inode *inode, const char *value, if (!len) return 0; - if (!strncmp("pid", value, 3)) + if (!strncmp("pid", value, 3)) { return 0; + } else if (!strncmp("devid", value, 5)) { + u64 devid; + char *value_dup; + + if (len <= 5) + return -EINVAL; + + value_dup = kstrndup(value, len, GFP_KERNEL); + if (!value_dup) + return -ENOMEM; + if (kstrtoull(value_dup + 5, 10, &devid)) { + kfree(value_dup); + return -EINVAL; + } + kfree(value_dup); + + if (btrfs_find_device(root->fs_info->fs_devices, devid, + NULL, NULL, false)) + return 0; + } return -EINVAL; } @@ -349,10 +369,33 @@ static int prop_readmirror_apply(struct inode *inode, const char *value, { struct btrfs_fs_devices *fs_devices = btrfs_sb(inode->i_sb)->fs_devices; - if (!value) + if (!value) { fs_devices->readmirror_policy = BTRFS_READMIRROR_DEFAULT; - else if (!strncmp("pid", value, 3)) + } else if (!strncmp("pid", value, 3)) { fs_devices->readmirror_policy = BTRFS_READMIRROR_PID; + } else if (!strncmp("devid", value, 5)) { + u64 devid; + char *value_dup; + struct btrfs_device *device; + struct btrfs_root *root = BTRFS_I(inode)->root; + + value_dup = kstrndup(value, len, GFP_KERNEL); + if (!value_dup) + return -ENOMEM; + if (kstrtoull(value_dup + 5, 10, &devid)) { + kfree(value_dup); + return -EINVAL; + } + kfree(value_dup); + + fs_devices->readmirror_policy = BTRFS_READMIRROR_DEVID; + device = btrfs_find_device(root->fs_info->fs_devices, devid, + NULL, NULL, false); + if (!device) + return -ENODEV; + + device->type = BTRFS_DEVICE_TYPE_READ_OPTIMIZED; + } return 0; } diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index e5072d46e181..d3b7427d6d96 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -5553,6 +5553,7 @@ static int find_live_mirror(struct btrfs_fs_info *fs_info, int preferred_mirror; int tolerance; struct btrfs_device *srcdev; + bool found = false; ASSERT((map->type & (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10))); @@ -5563,6 +5564,21 @@ static int find_live_mirror(struct btrfs_fs_info *fs_info, num_stripes = map->num_stripes; switch(fs_info->fs_devices->readmirror_policy) { + case BTRFS_READMIRROR_DEVID: + /* skip raid10 for now */ + if (map->type & BTRFS_BLOCK_GROUP_RAID1) { + for (i = first; i < first + num_stripes; i++) { + if (map->stripes[i].dev->type == + BTRFS_DEVICE_TYPE_READ_OPTIMIZED) { + preferred_mirror = i; + found = true; + break; + } + } + if (found) + break; + } + /* fall through */ case BTRFS_READMIRROR_PID: /* fall through */ case BTRFS_READMIRROR_DEFAULT: diff --git a/fs/btrfs/volumes.h b/fs/btrfs/volumes.h index 27dce9242b55..9c2e64548a11 100644 --- a/fs/btrfs/volumes.h +++ b/fs/btrfs/volumes.h @@ -208,9 +208,12 @@ struct btrfs_device { BTRFS_DEVICE_GETSET_FUNCS(disk_total_bytes); BTRFS_DEVICE_GETSET_FUNCS(bytes_used); +#define BTRFS_DEVICE_TYPE_READ_OPTIMIZED 1ULL + enum btrfs_readmirror_policy { BTRFS_READMIRROR_DEFAULT, BTRFS_READMIRROR_PID, + BTRFS_READMIRROR_DEVID, }; struct btrfs_fs_devices { -- 1.8.3.1