From patchwork Fri Nov 20 16:37:44 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?J=C3=B6rn_Engel?= X-Patchwork-Id: 38932 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from bombadil.infradead.org (bombadil.infradead.org [18.85.46.34]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 18062B6F1A for ; Sat, 21 Nov 2009 03:40:30 +1100 (EST) Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1NBWUm-0000tM-SU; Fri, 20 Nov 2009 16:38:04 +0000 Received: from lazybastard.de ([212.112.238.170] helo=longford.logfs.org) by bombadil.infradead.org with esmtps (Exim 4.69 #1 (Red Hat Linux)) id 1NBWUf-0000r9-Hq for linux-mtd@lists.infradead.org; Fri, 20 Nov 2009 16:38:02 +0000 Received: from joern by longford.logfs.org with local (Exim 4.63) (envelope-from ) id 1NBWUV-0003Bd-Tv; Fri, 20 Nov 2009 17:37:48 +0100 Date: Fri, 20 Nov 2009 17:37:44 +0100 From: =?utf-8?B?SsO2cm4=?= Engel To: David Woodhouse Subject: [PATCH] fio infrastructure Message-ID: <20091120163744.GB1716@logfs.org> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.13 (2006-08-11) X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20091120_113757_891906_E4BCF96D X-CRM114-Status: GOOD ( 21.38 ) X-Spam-Score: 0.0 (/) X-Spam-Report: SpamAssassin version 3.2.5 on bombadil.infradead.org summary: Content analysis details: (0.0 points) pts rule name description ---- ---------------------- -------------------------------------------------- _SUMMARY_ Cc: linux-mtd@lists.infradead.org X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org I really wish I could have tested this with working hardware, but the gods are against that idea. So here is a patch anyway. Main idea is to have three asynchonous operations for read, write and erase. The old erase method already has an asynchronous interface, so arguably I could have reused that. But for consistency and because no existing driver actually worked asynchronously, I decided to add a new method for erase as well. Each operation works on the smallest possible entity - either a page or a block. If and when hardware arrives that performs better when using larger operations, we can still change that. The wait_multiple_* code is can be used to send off a lot of IO at once and wait for it all to finish. Comments? Jörn diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 467a4f1..04ac1a0 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -44,6 +44,31 @@ EXPORT_SYMBOL_GPL(mtd_table); static LIST_HEAD(mtd_notifiers); +void wait_multiple_init(struct wait_multiple *wm_data, int count) +{ + kref_set(&wm_data->refcount, count); + init_completion(&wm_data->complete); + wm_data->err = 0; +} + +void wait_multiple_release(struct kref *kref) +{ + struct wait_multiple *wm_data; + + wm_data = container_of(kref, struct wait_multiple, refcount); + complete(&wm_data->complete); +} + +void wait_multiple_complete(struct fio *fio) +{ + struct wait_multiple *wm_data = fio->fi_private; + + if (fio->fi_err && !wm_data->err) + wm_data->err = fio->fi_err; + kref_put(&wm_data->refcount, wait_multiple_release); + free_fio(fio); +} + #if defined(CONFIG_MTD_CHAR) || defined(CONFIG_MTD_CHAR_MODULE) #define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2) #else diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 0f32a9b..3f0a65e 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -48,6 +48,52 @@ struct erase_info { struct erase_info *next; }; +enum fio_type { + FIO_READ_OOB = 1, + FIO_READ = 2, + FIO_WRITE = 3, + FIO_ERASE = 4, +}; + +/* + * A fio does one thing and does it well - asynchronously and out of order. + * One thing means a single small operation, a page read, a page write or a + * block erase. + */ +struct fio; +typedef void (fio_end_io_t) (struct fio *fio); +struct fio { + struct list_head fi_list; + enum fio_type fi_type; + struct mtd_info *fi_mtd; + u64 fi_ofs; + void *fi_private; + fio_end_io_t *fi_end_io; + int fi_err; + struct kref fi_refcount; + struct page *fi_page; +}; + +static inline struct fio *alloc_fio(gfp_t gfp_mask) +{ + return kzalloc(sizeof(struct fio), gfp_mask); +} + +static inline void free_fio(struct fio *fio) +{ + kfree(fio); +} + +struct wait_multiple { + struct completion complete; + struct kref refcount; + int err; +}; + +void wait_multiple_init(struct wait_multiple *wm_data, int count); +void wait_multiple_release(struct kref *kref); +void wait_multiple_complete(struct fio *fio); + struct mtd_erase_region_info { uint64_t offset; /* At which this region starts, from the beginning of the MTD */ uint32_t erasesize; /* For this region */ @@ -181,6 +227,11 @@ struct mtd_info { int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); + void (*fio_read)(struct fio *fio); + void (*fio_write)(struct fio *fio); + /* XXX Caller has to check for bad blocks manually. */ + void (*fio_erase)(struct fio *fio); + /* In blackbox flight recorder like scenarios we want to make successful writes in interrupt context. panic_write() is only intended to be called when its known the kernel is about to panic and we need the