From patchwork Wed Aug 3 19:06:44 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shaun Tancheff X-Patchwork-Id: 9262043 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 D2A926048B for ; Wed, 3 Aug 2016 19:08:08 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C56B427B2F for ; Wed, 3 Aug 2016 19:08:08 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B97122823D; Wed, 3 Aug 2016 19:08:08 +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=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D1ADF27B2F for ; Wed, 3 Aug 2016 19:08:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758141AbcHCTHg (ORCPT ); Wed, 3 Aug 2016 15:07:36 -0400 Received: from smtp78.mediacombb.net ([68.66.77.78]:42947 "EHLO dsmdc-mail-smtp.mcomdc.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1758123AbcHCTHe (ORCPT ); Wed, 3 Aug 2016 15:07:34 -0400 Received: from helios ([173.23.249.37]) by njtocomv03.mcomdc.com with bizsmtp id Sj7W1t00c0p9T5H01j7WN1; Wed, 03 Aug 2016 15:07:32 -0400 X-Originating-IP: 173.23.249.37 X-Authenticated-User: shaun@helios.aeonazure.com X-COS-Tag: onnet X-Outbound-Route: TO X-Authenticated-Sender: shaun@helios.aeonazure.com X-Authority-Analysis: v=2.1 cv=J5gk7WXS c=1 sm=1 tr=0 a=ZifPZbLpJbm8c8CM908FCQ==:117 a=ZifPZbLpJbm8c8CM908FCQ==:17 a=L9H7d07YOLsA:10 a=9cW_t1CCXrUA:10 a=s5jvgZ67dGcA:10 a=7z1cN_iqozsA:10 a=3go8odswAAAA:8 a=AxtaQxPqAAAA:8 a=QyXUC8HyAAAA:8 a=CbDCq_QkAAAA:8 a=20KFwNOVAAAA:8 a=MvuuwTCpAAAA:8 a=pGLkceISAAAA:8 a=DfNHnWVPAAAA:8 a=A_BEMvoUZvdGPz-WifoA:9 a=WCphLhRDQySbTNkkd-8K:22 a=YCQbF-f_5M6lIxUQxg0O:22 a=avl4LiGQNoF5OB0DmCJ7:22 a=1qrBK16LubpBFNPVNq2M:22 a=e_O65bzb51kRm2y5VmPK:22 a=dVHiktpip_riXrfdqayU:22 a=6kGIvZw6iX1k4Y-7sg4_:22 a=rjTVMONInIDnV1a_A2c_:22 X-Authenticated-Sender: shaun@helios.aeonazure.com Received: from shaun by helios with local (Exim 4.87) (envelope-from ) id 1bV1Vq-0001I7-1w; Wed, 03 Aug 2016 14:07:30 -0500 From: Shaun Tancheff To: linux-block@vger.kernel.org, linux-scsi@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Shaun Tancheff , Jens Axboe , Jens Axboe , Christoph Hellwig , "James E . J . Bottomley" , "Martin K . Petersen" , Josh Bingaman , Shaun Tancheff , Hannes Reinecke , Damien Le Moal , Dan Williams , Sagi Grimberg , Mike Christie , Toshi Kani , Kent Overstreet , Ming Lei Subject: [PATCH 1/2] bio/zbc support for zone cache Date: Wed, 3 Aug 2016 14:06:44 -0500 Message-Id: <1470251205-4916-2-git-send-email-shaun@tancheff.com> X-Mailer: git-send-email 2.8.1 In-Reply-To: <1470251205-4916-1-git-send-email-shaun@tancheff.com> References: <1470251205-4916-1-git-send-email-shaun@tancheff.com> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Zone actions (Open/Close/Reset) update zone cache on success. Add helpers for - Zone actions to update zone cache - Zone report to translate cache to ZBC format structs Update blkreport to pull from zone cache instead of querying media. Added open explicit and closed states for zone cache Signed-off-by: Shaun Tancheff Cc: Hannes Reinecke Cc: Damien Le Moal Cc: Dan Williams Cc: Sagi Grimberg Cc: Mike Christie Cc: Toshi Kani Cc: Kent Overstreet Cc: Ming Lei --- block/blk-lib.c | 3 +- block/blk-zoned.c | 190 +++++++++++++++++++++++++++++++++++++++++++++++++ block/ioctl.c | 39 +++++++--- include/linux/blkdev.h | 14 +++- 4 files changed, 234 insertions(+), 12 deletions(-) diff --git a/block/blk-lib.c b/block/blk-lib.c index 6dcdcbf..92898ec 100644 --- a/block/blk-lib.c +++ b/block/blk-lib.c @@ -6,7 +6,6 @@ #include #include #include -#include #include "blk.h" @@ -358,6 +357,8 @@ int blkdev_issue_zone_action(struct block_device *bdev, unsigned int op, bio_set_op_attrs(bio, op, op_flags); ret = submit_bio_wait(bio); bio_put(bio); + if (ret == 0) + update_zone_state(bdev, sector, op); return ret; } EXPORT_SYMBOL(blkdev_issue_zone_action); diff --git a/block/blk-zoned.c b/block/blk-zoned.c index 975e863..799676b 100644 --- a/block/blk-zoned.c +++ b/block/blk-zoned.c @@ -68,3 +68,193 @@ void blk_drop_zones(struct request_queue *q) q->zones = RB_ROOT; } EXPORT_SYMBOL_GPL(blk_drop_zones); + +static void __set_zone_state(struct blk_zone *zone, int op) +{ + if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) + return; + + switch (op) { + case REQ_OP_ZONE_OPEN: + zone->state = BLK_ZONE_OPEN_EXPLICIT; + break; + case REQ_OP_ZONE_CLOSE: + zone->state = BLK_ZONE_CLOSED; + break; + case REQ_OP_ZONE_RESET: + zone->wp = zone->start; + break; + default: + WARN_ONCE(1, "%s: invalid op code: %u\n", __func__, op); + } +} + +void update_zone_state(struct block_device *bdev, sector_t lba, unsigned int op) +{ + struct request_queue *q = bdev_get_queue(bdev); + struct blk_zone *zone = NULL; + + if (lba == ~0ul) { + struct rb_node *node; + + for (node = rb_first(&q->zones); node; node = rb_next(node)) { + zone = rb_entry(node, struct blk_zone, node); + __set_zone_state(zone, op); + } + return; + } + zone = blk_lookup_zone(q, lba); + if (zone) + __set_zone_state(zone, op); +} +EXPORT_SYMBOL_GPL(update_zone_state); + +void bzrpt_fill(struct block_device *bdev, struct bdev_zone_report *bzrpt, + size_t sz, sector_t lba, u8 opt) +{ + u64 clen = ~0ul; + struct blk_zone *zone = NULL; + struct rb_node *node = NULL; + struct request_queue *q = bdev_get_queue(bdev); + u32 max_entries = (sz - sizeof(struct bdev_zone_report)) + / sizeof(struct bdev_zone_descriptor); + u32 entry; + int len_diffs = 0; + int type_diffs = 0; + u8 ctype; + u8 same = 0; + + zone = blk_lookup_zone(q, lba); + if (zone) + node = &zone->node; + + for (entry = 0; + entry < max_entries && node; + entry++, node = rb_next(node)) { + u64 wp; + u8 cond = 0; + u8 flgs = 0; + + zone = rb_entry(node, struct blk_zone, node); + if (blk_zone_is_cmr(zone)) + wp = zone->start + zone->len; + else + wp = zone->wp; + + bzrpt->descriptors[entry].lba_start = cpu_to_be64(zone->start); + bzrpt->descriptors[entry].length = cpu_to_be64(zone->len); + bzrpt->descriptors[entry].type = zone->type; + bzrpt->descriptors[entry].lba_wptr = cpu_to_be64(wp); + + switch (zone->state) { + case BLK_ZONE_NO_WP: + cond = ZCOND_CONVENTIONAL; + break; + case BLK_ZONE_OPEN: + cond = ZCOND_ZC2_OPEN_IMPLICIT; + break; + case BLK_ZONE_OPEN_EXPLICIT: + cond = ZCOND_ZC3_OPEN_EXPLICIT; + break; + case BLK_ZONE_CLOSED: + cond = ZCOND_ZC4_CLOSED; + break; + case BLK_ZONE_READONLY: + cond = ZCOND_ZC6_READ_ONLY; + break; + case BLK_ZONE_OFFLINE: + cond = ZCOND_ZC7_OFFLINE; + break; + default: + cond = 5; /* not mapable */ + break; + } + if (zone->type == BLK_ZONE_TYPE_CONVENTIONAL) + flgs |= 0x02; + if (zone->wp == zone->start) + flgs |= 0x01; /* flag as reset */ + bzrpt->descriptors[entry].flags = cond << 4 | flgs; + bzrpt->descriptor_count = cpu_to_be32(entry+1); + + switch (opt & 0x3f) { + case ZOPT_RESET: + case ZOPT_ZC1_EMPTY: + if (zone->wp != zone->start) + continue; + break; + case ZOPT_ZC5_FULL: + if (zone->wp >= (zone->start + zone->len)) + continue; + break; + case ZOPT_ZC2_OPEN_IMPLICIT: + if (zone->state != BLK_ZONE_OPEN) + continue; + break; + case ZOPT_ZC3_OPEN_EXPLICIT: + if (zone->state != BLK_ZONE_OPEN_EXPLICIT) + continue; + break; + case ZOPT_ZC4_CLOSED: + if (zone->state != BLK_ZONE_CLOSED) + continue; + break; + case ZOPT_NON_SEQ: + case ZOPT_NON_WP_ZONES: + if (zone->state == BLK_ZONE_NO_WP) + continue; + break; + case ZOPT_ZC6_READ_ONLY: + if (zone->state == BLK_ZONE_READONLY) + continue; + break; + case ZOPT_ZC7_OFFLINE: + if (zone->state == BLK_ZONE_OFFLINE) + continue; + break; + default: + break; + } + /* if same code only applies to returned zones */ + if (opt & ZOPT_PARTIAL_FLAG) { + if (clen != ~0ul) { + clen = zone->len; + ctype = zone->type; + } + if (zone->len != clen) + len_diffs++; + if (zone->type != ctype) + type_diffs++; + ctype = zone->type; + } + } + + /* if same code only applies to all zones */ + if (!(opt & ZOPT_PARTIAL_FLAG)) { + for (node = rb_first(&q->zones); node; node = rb_next(node)) { + zone = rb_entry(node, struct blk_zone, node); + if (clen != ~0ul) { + clen = zone->len; + ctype = zone->type; + } + if (zone->len != clen) + len_diffs++; + if (zone->type != ctype) + type_diffs++; + ctype = zone->type; + } + } + + if (len_diffs == 0) { + if (type_diffs == 0) + same = ZS_ALL_SAME; + else + same = ZS_SAME_LEN_DIFF_TYPES; + } else if (len_diffs == 1 && type_diffs == 0) { + same = ZS_LAST_DIFFERS; + } else { + same = ZS_ALL_DIFFERENT; + } + bzrpt->same_field = same; + bzrpt->maximum_lba = i_size_read(bdev->bd_inode); +} +EXPORT_SYMBOL_GPL(bzrpt_fill); diff --git a/block/ioctl.c b/block/ioctl.c index a2a6c2c..44c8cb7 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -7,7 +7,6 @@ #include #include #include -#include #include #include @@ -201,11 +200,13 @@ static int blk_zoned_report_ioctl(struct block_device *bdev, fmode_t mode, int error = -EFAULT; gfp_t gfp = GFP_KERNEL | GFP_DMA; struct bdev_zone_report_io *zone_iodata = NULL; + struct bdev_zone_report *bzrpt = NULL; int order = 0; struct page *pgs = NULL; u32 alloc_size = PAGE_SIZE; unsigned long op_flags = 0; - u8 opt = 0; + sector_t lba = 0ul; + u8 opt; if (!(mode & FMODE_READ)) return -EBADF; @@ -219,6 +220,30 @@ static int blk_zoned_report_ioctl(struct block_device *bdev, fmode_t mode, error = -EFAULT; goto report_zones_out; } + + lba = zone_iodata->data.in.zone_locator_lba; + opt = zone_iodata->data.in.report_option; + +#ifdef CONFIG_BLK_DEV_ZONED + if (zone_iodata->data.in.return_page_count > alloc_size) { + alloc_size = zone_iodata->data.in.return_page_count; + bzrpt = kzalloc(alloc_size, GFP_KERNEL); + if (bzrpt) { + free_page((unsigned long)zone_iodata); + zone_iodata = (void *)bzrpt; + } else { + /* Result requires DMA capable memory */ + pr_err("Not enough memory available for request.\n"); + error = -ENOMEM; + goto report_zones_out; + } + } + (void)op_flags; + bzrpt_fill(bdev, &zone_iodata->data.out, alloc_size, lba, opt); + error = 0; + if (copy_to_user(parg, zone_iodata, alloc_size)) + error = -EFAULT; +#else if (zone_iodata->data.in.return_page_count > alloc_size) { int npages; @@ -234,7 +259,6 @@ static int blk_zoned_report_ioctl(struct block_device *bdev, fmode_t mode, } order = ilog2(npages); memset(mem, 0, alloc_size); - memcpy(mem, zone_iodata, sizeof(*zone_iodata)); free_page((unsigned long)zone_iodata); zone_iodata = mem; } else { @@ -244,21 +268,20 @@ static int blk_zoned_report_ioctl(struct block_device *bdev, fmode_t mode, goto report_zones_out; } } - opt = zone_iodata->data.in.report_option; - error = blkdev_issue_zone_report(bdev, op_flags, - zone_iodata->data.in.zone_locator_lba, opt, + error = blkdev_issue_zone_report(bdev, op_flags, lba, opt, pgs ? pgs : virt_to_page(zone_iodata), alloc_size, GFP_KERNEL); - if (error) goto report_zones_out; - if (copy_to_user(parg, zone_iodata, alloc_size)) error = -EFAULT; +#endif report_zones_out: if (pgs) __free_pages(pgs, order); + else if (bzrpt) + kfree(bzrpt); else if (zone_iodata) free_page((unsigned long)zone_iodata); return error; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 9b2f5e8..c1b4e2f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -24,6 +24,7 @@ #include #include #include +#include struct module; struct scsi_ioctl_command; @@ -275,6 +276,8 @@ enum blk_zone_state { BLK_ZONE_UNKNOWN, BLK_ZONE_NO_WP, BLK_ZONE_OPEN, + BLK_ZONE_OPEN_EXPLICIT, + BLK_ZONE_CLOSED, BLK_ZONE_READONLY, BLK_ZONE_OFFLINE, BLK_ZONE_BUSY, @@ -291,9 +294,9 @@ struct blk_zone { void *private_data; }; -#define blk_zone_is_smr(z) ((z)->type == BLK_ZONE_TYPE_SEQWRITE_REQ || \ - (z)->type == BLK_ZONE_TYPE_SEQWRITE_PREF) - +#define blk_zone_is_seq_req(z) ((z)->type == BLK_ZONE_TYPE_SEQWRITE_REQ) +#define blk_zone_is_seq_pref(z) ((z)->type == BLK_ZONE_TYPE_SEQWRITE_PREF) +#define blk_zone_is_smr(z) (blk_zone_is_seq_req(z) || blk_zone_is_seq_pref(z)) #define blk_zone_is_cmr(z) ((z)->type == BLK_ZONE_TYPE_CONVENTIONAL) #define blk_zone_is_full(z) ((z)->wp == (z)->start + (z)->len) #define blk_zone_is_empty(z) ((z)->wp == (z)->start) @@ -302,8 +305,13 @@ extern struct blk_zone *blk_lookup_zone(struct request_queue *, sector_t); extern struct blk_zone *blk_insert_zone(struct request_queue *, struct blk_zone *); extern void blk_drop_zones(struct request_queue *); +extern void update_zone_state(struct block_device *, sector_t, unsigned int); +extern void bzrpt_fill(struct block_device *, struct bdev_zone_report *, size_t, + sector_t, u8); #else static inline void blk_drop_zones(struct request_queue *q) { }; +static inline void update_zone_state(struct block_device *bdev, + sector_t lba, unsigned int op) {} #endif struct queue_limits {