From patchwork Sat Feb 11 04:35:05 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brian Norris X-Patchwork-Id: 140766 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from merlin.infradead.org (unknown [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id BCF72B6F99 for ; Sat, 11 Feb 2012 15:36:29 +1100 (EST) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Rw4fb-0002Aa-35; Sat, 11 Feb 2012 04:34:43 +0000 Received: from mail-pw0-f49.google.com ([209.85.160.49]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1Rw4fX-0002AM-VX for linux-mtd@lists.infradead.org; Sat, 11 Feb 2012 04:34:40 +0000 Received: by pbcun1 with SMTP id un1so2071742pbc.36 for ; Fri, 10 Feb 2012 20:34:38 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; bh=2jZaAbsEmEJvqXWSF18HqP1x9nWfioGM/l+8ehcYLy4=; b=rNp09RM/Yp+TohS5nNfUWFW5XrNnh9OCReXnlJSeh6RTeq9REfF9QYBe5qBVmruDmT 3lpcmqslZEQnG+OOhhM4pPbpM9Yh7T6YbfztQJq+iBSaMs+ioqXS0ZeYBU+vsVp4vYQw RVJcv6unW6MAKhJsRYJSbpwZzlya9c1IHOtXs= Received: by 10.68.222.133 with SMTP id qm5mr22611043pbc.78.1328934878273; Fri, 10 Feb 2012 20:34:38 -0800 (PST) Received: from localhost.localdomain (5520-maca-inet1-outside.broadcom.com. [216.31.211.11]) by mx.google.com with ESMTPS id i10sm18835579pbg.10.2012.02.10.20.34.35 (version=TLSv1/SSLv3 cipher=OTHER); Fri, 10 Feb 2012 20:34:36 -0800 (PST) From: Brian Norris To: Artem Bityutskiy Subject: [PATCH] libmtd: fix mtd_write() issues for large data-only writes Date: Fri, 10 Feb 2012 20:35:05 -0800 Message-Id: <1328934905-27007-1-git-send-email-computersforpeace@gmail.com> X-Mailer: git-send-email 1.7.5.4 X-Spam-Note: CRM114 invocation failed X-Spam-Score: -2.7 (--) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-2.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.160.49 listed in list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is commonly abused enduser mail provider (computersforpeace[at]gmail.com) -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature Cc: Brian Norris , linux-mtd@lists.infradead.org X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org ioctl(MEMWRITE) is implemented with memdup_user(), and so it allocates kernel memory in contiguous regions. This limits its usefulness for large amounts of data, since contiguous kernel memory can become scarce. I have experienced "out of memory" problems with ubiformat, for instance, which writes in eraseblock-sized regions: ... ubiformat: flashing eraseblock 12 -- 72 % complete ubiformat: page allocation failure. order:8, mode:0xd0 Call Trace: [<8043fa7c>] dump_stack+0x8/0x34 [<8008c940>] __alloc_pages_nodemask+0x408/0x618 [<800bd748>] cache_alloc_refill+0x400/0x730 [<800bdbbc>] __kmalloc+0x144/0x154 [<8009cae4>] memdup_user+0x24/0x94 [<802d04e4>] mtd_ioctl+0xba8/0xbd0 [<802d0544>] mtd_unlocked_ioctl+0x38/0x5c [<800d43c0>] do_vfs_ioctl+0xa4/0x6e4 [<800d4a44>] sys_ioctl+0x44/0xa0 [<8000f95c>] stack_done+0x20/0x40 ... libmtd: error!: MEMWRITE ioctl failed for eraseblock 12 (mtd0) error 12 (Cannot allocate memory) ubiformat: error!: cannot write eraseblock 12 error 12 (Cannot allocate memory) This error can be mitigated for now by only using ioctl(MEMWRITE) when we need to write OOB data, since we can only do this in small transactions anyway. Then, data-only transactions (like those originating from ubiformat) can be carried out with write() calls. This issue can also be solved within the kernel ioctl(), but either way, this patch is still useful, since write() is more straightforward (and efficient?) than ioctl() for data-only writes. Signed-off-by: Brian Norris --- lib/libmtd.c | 28 ++++++++++++++-------------- 1 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/libmtd.c b/lib/libmtd.c index fb4586c..c4836df 100644 --- a/lib/libmtd.c +++ b/lib/libmtd.c @@ -1147,21 +1147,21 @@ int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb, /* Calculate seek address */ seek = (off_t)eb * mtd->eb_size + offs; - ops.start = seek; - ops.len = len; - ops.ooblen = ooblen; - ops.usr_data = (uint64_t)(unsigned long)data; - ops.usr_oob = (uint64_t)(unsigned long)oob; - ops.mode = mode; - - ret = ioctl(fd, MEMWRITE, &ops); - if (ret == 0) - return 0; - else if (errno != ENOTTY && errno != EOPNOTSUPP) - return mtd_ioctl_error(mtd, eb, "MEMWRITE"); - - /* Fall back to old methods if necessary */ if (oob) { + ops.start = seek; + ops.len = len; + ops.ooblen = ooblen; + ops.usr_data = (uint64_t)(unsigned long)data; + ops.usr_oob = (uint64_t)(unsigned long)oob; + ops.mode = mode; + + ret = ioctl(fd, MEMWRITE, &ops); + if (ret == 0) + return 0; + else if (errno != ENOTTY && errno != EOPNOTSUPP) + return mtd_ioctl_error(mtd, eb, "MEMWRITE"); + + /* Fall back to old OOB ioctl() if necessary */ if (mode == MTD_OPS_AUTO_OOB) if (legacy_auto_oob_layout(mtd, fd, ooblen, oob)) return -1;