From patchwork Wed Jul 15 11:52:35 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tobias Diedrich X-Patchwork-Id: 29807 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 bilbo.ozlabs.org (Postfix) with ESMTPS id 6E467B7088 for ; Wed, 15 Jul 2009 21:58:31 +1000 (EST) Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.69 #1 (Red Hat Linux)) id 1MR32T-0006hC-6m; Wed, 15 Jul 2009 11:52:45 +0000 Received: from mx.tdiedrich.de ([2001:6f8:1132::2]) by bombadil.infradead.org with esmtps (Exim 4.69 #1 (Red Hat Linux)) id 1MR32N-0006fA-G2 for linux-mtd@lists.infradead.org; Wed, 15 Jul 2009 11:52:43 +0000 Received: from nukunuku.yamamaya.is-a-geek.org (nukunuku-vpn [192.168.8.240]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client CN "nukunuku.yamamaya.is-a-geek.org", Issuer "Tobias Diedrich CA" (verified OK)) by mx.tdiedrich.de (Postfix) with ESMTPS id 579CE500D7; Wed, 15 Jul 2009 13:52:36 +0200 (CEST) Received: by nukunuku.yamamaya.is-a-geek.org (Postfix, from userid 1000) id 7E1C4C8056; Wed, 15 Jul 2009 13:52:35 +0200 (CEST) Date: Wed, 15 Jul 2009 13:52:35 +0200 From: Tobias Diedrich To: linux-kernel@vger.kernel.org Subject: block2mtd and ubi are initialized too early when compiled in on 2.6.31-rc2 Message-ID: <20090715115235.GA21888@yamamaya.is-a-geek.org> Mail-Followup-To: Tobias Diedrich , linux-kernel@vger.kernel.org, linux-mtd@lists.infradead.org MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) X-Spam-Score: -0.1 (/) Cc: linux-mtd@lists.infradead.org X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.11 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 On 2.6.31-rc2 the block2mtd drivers module_init is called before any block devices have been registered. Also ubi is initialized pretty early and fails completely if an mtd specified on the command line could not be found. IMO ubi should at least complete initialization so that attaching the mtd later with ubiattach would still work. I'm working around this two hacky patches that create a kernel thread and retry every second for 20 seconds when the first try doesn't work. (Obviously this means rootdelay=$somenumber is needed) I tried using the async infrastructure, but apparently async_synchronize_full is called somewhere between registering the async probe thread and the target USB device being registered by the USB subsystem, which halts boot until my 20 second timeout, and the USB stick is only detected afterwards. FWIW I want to use a erasesize aware FS on my USB stick (whose builtin FTL has abysmal write performance if writes are less than the erasesize) and also be able to use this as my root fs. So my setup is usb_storage->block2mtd->ubi->ubifs Index: linux-2.6.31-rc2/drivers/mtd/devices/block2mtd.c =================================================================== --- linux-2.6.31-rc2.orig/drivers/mtd/devices/block2mtd.c 2009-07-11 22:22:34.318636261 +0200 +++ linux-2.6.31-rc2/drivers/mtd/devices/block2mtd.c 2009-07-12 00:05:45.937512203 +0200 @@ -17,6 +17,8 @@ #include #include #include +#include +#include #define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args) #define INFO(fmt, args...) printk(KERN_INFO "block2mtd: " fmt "\n" , ## args) @@ -373,8 +375,30 @@ static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */ #endif +struct block2mtd_setupasync_params { + char *name; + int erase_size; +}; + +static int block2mtd_setupasync(void *p) +{ + struct block2mtd_setupasync_params *params = p; + int i; + + printk(KERN_WARNING "block2mtd: spawned kernel thread for async waiting on '%s'\n", params->name); + for (i=0; i<20; i++) { + msleep(1000); + + if (add_device(params->name, params->erase_size) != NULL) + break; + } + kfree(params->name); + kfree(params); + + return 0; +} -static int block2mtd_setup2(const char *val) +static int block2mtd_setup2(const char *val, int async) { char buf[80 + 12]; /* 80 for device, 12 for erase size */ char *str = buf; @@ -382,6 +406,7 @@ char *name; size_t erase_size = PAGE_SIZE; int i, ret; + struct block2mtd_setupasync_params *params; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) parse_err("parameter too long"); @@ -409,16 +434,32 @@ } } - add_device(name, erase_size); + if (add_device(name, erase_size) != NULL) + return 0; + + params = kzalloc(sizeof(struct block2mtd_setupasync_params), GFP_KERNEL); + if (!params) + return 0; + + params->name = kmalloc(strlen(name)+1, GFP_KERNEL); + params->erase_size = erase_size; + if (!params->name) { + kfree(params); + return 0; + } + + memcpy(params->name, name, strlen(name)+1); + + if (async) + kthread_run(block2mtd_setupasync, params, "block2mtd/setupasync"); return 0; } - static int block2mtd_setup(const char *val, struct kernel_param *kp) { #ifdef MODULE - return block2mtd_setup2(val); + return block2mtd_setup2(val, 0); #else /* If more parameters are later passed in via /sys/module/block2mtd/parameters/block2mtd @@ -426,7 +467,7 @@ we can parse the argument now. */ if (block2mtd_init_called) - return block2mtd_setup2(val); + return block2mtd_setup2(val, 0); /* During early boot stage, we only save the parameters here. We must parse them later: if the param passed @@ -451,7 +492,7 @@ #ifndef MODULE if (strlen(block2mtd_paramline)) - ret = block2mtd_setup2(block2mtd_paramline); + ret = block2mtd_setup2(block2mtd_paramline, 1); block2mtd_init_called = 1; #endif Index: linux-2.6.31-rc2/drivers/mtd/ubi/build.c =================================================================== --- linux-2.6.31-rc2.orig/drivers/mtd/ubi/build.c 2009-07-11 23:18:58.839398443 +0200 +++ linux-2.6.31-rc2/drivers/mtd/ubi/build.c 2009-07-12 00:04:28.721126461 +0200 @@ -42,6 +42,7 @@ #include #include #include +#include #include "ubi.h" /* Maximum length of the 'mtd=' parameter */ @@ -1136,6 +1137,40 @@ return mtd; } +static int ubi_init_attach_mtd(void *data) +{ + struct mtd_dev_param *p = data; + struct mtd_info *mtd; + int err; + int retries = 200; + + printk(KERN_WARNING "ubi_init_attach_mtd(%s): waiting async for device to appear\n", p->name); + do { + mtd = open_mtd_device(p->name); + if (IS_ERR(mtd)) { + if (retries-- > 0) { + msleep(100); + continue; + } + err = PTR_ERR(mtd); + ubi_err("cannot attach mtd %s: %d\n", p->name, err); + return 0; + } + break; + } while (1); + + mutex_lock(&ubi_devices_mutex); + err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, + p->vid_hdr_offs); + mutex_unlock(&ubi_devices_mutex); + if (err < 0) { + put_mtd_device(mtd); + ubi_err("cannot attach mtd%d: %d", mtd->index, err); + } + + return 0; +} + static int __init ubi_init(void) { int err, i, k; @@ -1176,28 +1211,8 @@ goto out_dev_unreg; /* Attach MTD devices */ - for (i = 0; i < mtd_devs; i++) { - struct mtd_dev_param *p = &mtd_dev_param[i]; - struct mtd_info *mtd; - - cond_resched(); - - mtd = open_mtd_device(p->name); - if (IS_ERR(mtd)) { - err = PTR_ERR(mtd); - goto out_detach; - } - - mutex_lock(&ubi_devices_mutex); - err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, - p->vid_hdr_offs); - mutex_unlock(&ubi_devices_mutex); - if (err < 0) { - put_mtd_device(mtd); - ubi_err("cannot attach mtd%d", mtd->index); - goto out_detach; - } - } + for (i = 0; i < mtd_devs; i++) + kthread_run(ubi_init_attach_mtd, &mtd_dev_param[i], "ubi/mtdprobe%d", i); return 0;