From patchwork Mon Dec 18 18:08:51 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Heinz Mauelshagen X-Patchwork-Id: 10121445 X-Patchwork-Delegate: snitzer@redhat.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4FF2C603B5 for ; Mon, 18 Dec 2017 18:09:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 49382288E2 for ; Mon, 18 Dec 2017 18:09:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 3D9B528B27; Mon, 18 Dec 2017 18:09:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 964CC288E2 for ; Mon, 18 Dec 2017 18:09:03 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4D1B961473; Mon, 18 Dec 2017 18:09:02 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 5B2BC69286; Mon, 18 Dec 2017 18:09:01 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 6DDEC4BB79; Mon, 18 Dec 2017 18:09:00 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id vBII8w6p023283 for ; Mon, 18 Dec 2017 13:08:58 -0500 Received: by smtp.corp.redhat.com (Postfix) id C9ED284D2B; Mon, 18 Dec 2017 18:08:58 +0000 (UTC) Delivered-To: dm-devel@redhat.com Received: from redhat.com.com (unknown [10.40.205.187]) by smtp.corp.redhat.com (Postfix) with ESMTP id A83D184D25; Mon, 18 Dec 2017 18:08:56 +0000 (UTC) From: Heinz Mauelshagen To: heinzm@redhat.com, dm-devel@redhat.com Date: Mon, 18 Dec 2017 19:08:51 +0100 Message-Id: <02ebee64c38f09a0709f66aa2489adc78ba547a7.1513618685.git.heinzm@redhat.com> In-Reply-To: References: In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-loop: dm-devel@redhat.com Cc: scott.bauer@intel.com Subject: [dm-devel] [PATCH v4 1/2] dm unstriped: the target X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Mon, 18 Dec 2017 18:09:02 +0000 (UTC) X-Virus-Scanned: ClamAV using ClamSMTP Signed-off-by: Heinz Mauelshagen --- drivers/md/Kconfig | 11 +++ drivers/md/Makefile | 1 + drivers/md/dm-unstripe.c | 233 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 drivers/md/dm-unstripe.c diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index 83b9362be09c..7f8099f53ad6 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -269,6 +269,17 @@ config DM_BIO_PRISON source "drivers/md/persistent-data/Kconfig" +config DM_UNSTRIPED + tristate "Transpose IO to individual drives on a raid device" + depends on BLK_DEV_DM + ---help--- + Enable this feature if you with to unstripe I/O on a RAID 0 + device to the respective drive. If your hardware has physical + RAID 0 this module can unstripe the I/O to respective controllers + on the stripes. + + If unsure say N. + config DM_CRYPT tristate "Crypt target support" depends on BLK_DEV_DM diff --git a/drivers/md/Makefile b/drivers/md/Makefile index f701bb211783..63255f3ebd97 100644 --- a/drivers/md/Makefile +++ b/drivers/md/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_BCACHE) += bcache/ obj-$(CONFIG_BLK_DEV_MD) += md-mod.o obj-$(CONFIG_BLK_DEV_DM) += dm-mod.o obj-$(CONFIG_BLK_DEV_DM_BUILTIN) += dm-builtin.o +obj-$(CONFIG_DM_UNSTRIPED) += dm-unstripe.o obj-$(CONFIG_DM_BUFIO) += dm-bufio.o obj-$(CONFIG_DM_BIO_PRISON) += dm-bio-prison.o obj-$(CONFIG_DM_CRYPT) += dm-crypt.o diff --git a/drivers/md/dm-unstripe.c b/drivers/md/dm-unstripe.c new file mode 100644 index 000000000000..a590e1544dcf --- /dev/null +++ b/drivers/md/dm-unstripe.c @@ -0,0 +1,233 @@ +/* + * Copyright © 2017 Intel Corporation + * + * Authors: + * Scott Bauer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include "dm.h" +#include +#include +#include +#include +#include +#include +#include + +struct unstripe { + struct dm_dev *ddisk; + sector_t chunk_sectors; + sector_t stripe_sectors; + sector_t cur_drive_chunk_sectors; + unsigned int chunk_size; + u8 chunk_shift; + u8 cur_drive; + u8 total_drives; +}; + +#define DM_MSG_PREFIX "dm-unstriped" + +static void unstripe_dtr(struct dm_target *ti) +{ + struct unstripe *ut = ti->private; + + if (ut->ddisk) + dm_put_device(ti, ut->ddisk); + kfree(ut); +} + +/* + * Construct an "unstriped" mapping: + * + * Args: + * <#total_devs> + * + * device path of the raid0 device to unstripe (e.g. /dev/nvme0) + * index starting at 0 of device to extract + * <#total_devs> number of total, extractable devices + */ +static int unstripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + int r = -EINVAL; + sector_t sectors; + struct unstripe *ut; + + if (argc != 4) { + ti->error = "Invalid numver of arguments!"; + return -EINVAL; + } + + /* FIXME: interesting to allow multi-segment mappings for some testing? */ + if (ti->begin) { + ti->error = "Non-zero target begin!"; + return -EINVAL; + } + + ut = kzalloc(sizeof(*ut), GFP_KERNEL); + if (!ut) { + ti->error = "Failed to allocate space for target!"; + return -ENOMEM; + } + + if (sscanf(argv[1], "%hhu", &ut->cur_drive) != 1 || + sscanf(argv[2], "%hhu", &ut->total_drives) != 1 || + sscanf(argv[3], "%u", &ut->chunk_size) != 1) { + ti->error = "Error parsing drive/chunk arguments!"; + goto err; + } + + if (!ut->total_drives || (ut->cur_drive > ut->total_drives && ut->total_drives > 1)) { + ti->error = "Please provide drive between [0,total_devices]"; + goto err; + } + + if (ut->chunk_size && !is_power_of_2(ut->chunk_size)) { + ti->error = "Non power of 2 chunk size!"; + goto err; + } + + r = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &ut->ddisk); + if (r) { + ti->error = "dm-unstripe dev lookup failure!"; + goto err; + } + + /* FIXME: uspace should provide proper chunk size! */ + /* Given chunk sectors or max hw sectors if 0 */ + ut->chunk_sectors = ut->chunk_size ?: queue_max_hw_sectors(bdev_get_queue(ut->ddisk->bdev)); + ut->cur_drive_chunk_sectors = ut->cur_drive * ut->chunk_sectors; + ut->stripe_sectors = (ut->total_drives - 1) * ut->chunk_sectors; + ut->chunk_shift = fls(ut->chunk_sectors) - 1; + + /* Check uspace provided proper device length divisible by total drives */ + sectors = i_size_read(ut->ddisk->bdev->bd_inode) >> SECTOR_SHIFT; + if (do_div(sectors, ut->total_drives)) { + ti->error = "Device length not divisible by total number of drives!"; + goto err; + } + + /* Check uspace provided proper target length! */ + if (sectors != ti->len) { + ti->error = "Drive length not equal to target length!"; + goto err; + } + + /* Check uspace provided proper drive length divisible by chunk size */ + if (do_div(sectors, ut->chunk_sectors)) { + ti->error = "Drive length not divisible by chunk size"; + goto err; + } + + r = dm_set_target_max_io_len(ti, ut->chunk_sectors); + if (r) { + ti->error = "Failed to set max io len!"; + goto err; + } + + ti->private = ut; + return 0; +err: + unstripe_dtr(ti); + return r; +} + +static sector_t map_to_core(struct dm_target *ti, struct bio *bio) +{ + struct unstripe *ut = ti->private; + sector_t sec = bio->bi_iter.bi_sector; + + /* Account for what drive we're operating on */ + sec += ut->cur_drive_chunk_sectors; + + /* Shift us up to the right "row" on the drive*/ + sec += ut->stripe_sectors * (sec >> ut->chunk_shift); + return sec; +} + +static int unstripe_map(struct dm_target *ti, struct bio *bio) +{ + struct unstripe *ut = ti->private; + + bio_set_dev(bio, ut->ddisk->bdev); + bio->bi_iter.bi_sector = map_to_core(ti, bio); + return DM_MAPIO_REMAPPED; +} + +static void unstripe_status(struct dm_target *ti, status_type_t type, + unsigned int status_flags, char *result, unsigned int maxlen) +{ + struct unstripe *ut = ti->private; + unsigned int sz = 0; + + switch (type) { + case STATUSTYPE_INFO: + break; + + case STATUSTYPE_TABLE: + DMEMIT("%s %hhu %hhu %u", + ut->ddisk->name, ut->cur_drive, ut->total_drives, ut->chunk_size); + } +} + +static void unstripe_iohints(struct dm_target *ti, + struct queue_limits *limits) +{ + struct unstripe *ut = ti->private; + struct queue_limits *lim = &bdev_get_queue(ut->ddisk->bdev)->limits; + + blk_limits_io_min(limits, lim->io_min); + blk_limits_io_opt(limits, lim->io_opt); + limits->chunk_sectors = ut->chunk_sectors; +} + +static int unstripe_iterate(struct dm_target *ti, iterate_devices_callout_fn fn, + void *data) +{ + struct unstripe *ut = ti->private; + + return fn(ti, ut->ddisk, 0, ti->len, data); +} + +static struct target_type unstripe_target = { + .name = "unstriped", + .version = {1, 0, 0}, + .module = THIS_MODULE, + .ctr = unstripe_ctr, + .dtr = unstripe_dtr, + .map = unstripe_map, + .status = unstripe_status, + .iterate_devices = unstripe_iterate, + .io_hints = unstripe_iohints, +}; + +static int __init dm_unstripe_init(void) +{ + int r = dm_register_target(&unstripe_target); + + if (r < 0) + DMERR("register failed %d", r); + + return r; +} + +static void __exit dm_unstripe_exit(void) +{ + dm_unregister_target(&unstripe_target); +} + +module_init(dm_unstripe_init); +module_exit(dm_unstripe_exit); + +MODULE_DESCRIPTION(DM_NAME " DM unstripe"); +MODULE_ALIAS("dm-unstripe"); +MODULE_AUTHOR("Scott Bauer "); +MODULE_LICENSE("GPL");