From patchwork Tue May 3 06:43:35 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Matthew L. Creech" X-Patchwork-Id: 93744 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 E81901007DD for ; Tue, 3 May 2011 16:45:30 +1000 (EST) Received: from canuck.infradead.org ([2001:4978:20e::1]) by bombadil.infradead.org with esmtps (Exim 4.72 #1 (Red Hat Linux)) id 1QH9Kh-0007sl-KE; Tue, 03 May 2011 06:43:43 +0000 Received: from localhost ([127.0.0.1] helo=canuck.infradead.org) by canuck.infradead.org with esmtp (Exim 4.72 #1 (Red Hat Linux)) id 1QH9Kg-00057T-1W; Tue, 03 May 2011 06:43:42 +0000 Received: from mail-vx0-f177.google.com ([209.85.220.177]) by canuck.infradead.org with esmtps (Exim 4.72 #1 (Red Hat Linux)) id 1QH9Kc-000579-6J for linux-mtd@lists.infradead.org; Tue, 03 May 2011 06:43:39 +0000 Received: by vxd2 with SMTP id 2so5937802vxd.36 for ; Mon, 02 May 2011 23:43:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:in-reply-to:references:date :message-id:subject:from:to:cc:content-type; bh=NizG+/pOitQsfCblSVlFYiRa1kwL+ADRZUNBb0n0LdY=; b=g0LS3B2KTva1vr3lg+TnuqD8j+6yI2EbdrKiJFu9wfD+YZI4uFzeMSNjSKO+Pkx8mP T9ySE7PQMFFo3Qx/3w/Q4sOrRxXG678X7k9kzxP6TLYstsJrT/iz3MunIhQlrwryipfF Oze7SIES3ERTEZy3ocIKMgVxKaK2V4A6G1pzc= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; b=g76zwzWHSB9hWwbopcQfsgu7iwAbnPB3JRkcZRsDVbYctroLStHaeYoi1U6ndkV1NW 7uPr80eFyZAvZ4Aqa6DQOnQrQPstRS5u7OthM7YHM+XyIcwnGz1uGWrJlji21V/SDifJ FsElUWrZaYm4IoUo/Neu5Mr/u+jWRZ+txs12k= MIME-Version: 1.0 Received: by 10.52.0.67 with SMTP id 3mr1256980vdc.261.1304405015842; Mon, 02 May 2011 23:43:35 -0700 (PDT) Received: by 10.52.182.70 with HTTP; Mon, 2 May 2011 23:43:35 -0700 (PDT) In-Reply-To: <1303804811.2778.37.camel@localhost> References: <1303804811.2778.37.camel@localhost> Date: Tue, 3 May 2011 02:43:35 -0400 Message-ID: Subject: Re: Programming ubinized images From: "Matthew L. Creech" To: dedekind1@gmail.com X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110503_024338_354049_BD8E5EA1 X-CRM114-Status: GOOD ( 31.65 ) X-Spam-Score: -0.8 (/) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (-0.8 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [209.85.220.177 listed in list.dnswl.org] 0.0 FREEMAIL_FROM Sender email is freemail (mlcreech[at]gmail.com) -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 0.0 RFC_ABUSE_POST Both abuse and postmaster missing on sender domain 0.0 T_TO_NO_BRKTS_FREEMAIL T_TO_NO_BRKTS_FREEMAIL Cc: bengardiner@nanometrics.ca, 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 On Tue, Apr 26, 2011 at 4:00 AM, Artem Bityutskiy wrote: > > We could teach the UBIFS tools and the kernel to deal with these things. > It is possible to do with a special flag in the UBIFS superblock which > would say - this FS has been just flashed, do not use space in > half-filled eraseblocks! Then probably we could go through these > half-filled eraseblocks and fix them up, and then remove that flag. > Hi Artem, could you take a look at this patch when you get a chance? My method for finding & cleaning the in-use LEBs is hacky: I just loop through all the LEBs in the FS, look up each one in the LPT, and "recover" anything not flagged as empty. I *think* that should result in LEBs that have trailing empty space (SCANNED_EMPTY_SPACE) being re-mapped to a new PEB (via fix_unclean_leb()), which would clean up the empty pages. So far I haven't gotten that condition to trigger with a real UBIFS image, so I'm not sure if it works correctly yet. I may be way off on the wrong track though, so I just wanted to see if you think this seems like a reasonable way of doing it. Thanks! diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c index f7515bd..fc2c48b 100644 --- a/fs/ubifs/debug.c +++ b/fs/ubifs/debug.c @@ -316,6 +316,8 @@ void dbg_dump_node(const struct ubifs_info *c, const void *node) printk(KERN_DEBUG "\tflags %#x\n", sup_flags); printk(KERN_DEBUG "\t big_lpt %u\n", !!(sup_flags & UBIFS_FLG_BIGLPT)); + printk(KERN_DEBUG "\t leb_fixup %u\n", + !!(sup_flags & UBIFS_FLG_LEB_FIXUP)); printk(KERN_DEBUG "\tmin_io_size %u\n", le32_to_cpu(sup->min_io_size)); printk(KERN_DEBUG "\tleb_size %u\n", diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c index bf31b47..1977ed2 100644 --- a/fs/ubifs/sb.c +++ b/fs/ubifs/sb.c @@ -80,7 +80,8 @@ static int create_default_filesystem(struct ubifs_info *c) struct ubifs_cs_node *cs; union ubifs_key key; int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first; - int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0; + int lpt_lebs, lpt_first, orph_lebs, big_lpt, leb_fixup, ino_waste; + int sup_flags = 0; int min_leb_cnt = UBIFS_MIN_LEB_CNT; long long tmp64, main_bytes; __le64 tmp_le64; @@ -155,6 +156,7 @@ static int create_default_filesystem(struct ubifs_info *c) lpt_first + lpt_lebs - 1); main_first = c->leb_cnt - main_lebs; + leb_fixup = 0; /* Normally no need to fixup a fresh [empty] FS */ /* Create default superblock */ tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size); @@ -165,6 +167,8 @@ static int create_default_filesystem(struct ubifs_info *c) tmp64 = (long long)max_buds * c->leb_size; if (big_lpt) sup_flags |= UBIFS_FLG_BIGLPT; + if (leb_fixup) + sup_flags |= UBIFS_FLG_LEB_FIXUP; sup->ch.node_type = UBIFS_SB_NODE; sup->key_hash = UBIFS_KEY_HASH_R5; @@ -616,6 +620,7 @@ int ubifs_read_superblock(struct ubifs_info *c) c->vfs_sb->s_time_gran = le32_to_cpu(sup->time_gran); memcpy(&c->uuid, &sup->uuid, 16); c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT); + c->leb_fixup = !!(sup_flags & UBIFS_FLG_LEB_FIXUP); /* Automatically increase file system size to the maximum size */ c->old_leb_cnt = c->leb_cnt; diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 1f049ae..8345517 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -1153,6 +1153,78 @@ static int check_free_space(struct ubifs_info *c) } /** + * ubifs_mount_fixup_lebs - erase empty pages on first mount (for NAND) + * @c: UBIFS file-system description object + * + * This function fixes up LEBs on first mount, if the appropriate flag was set + * when the FS was created. Each LEB with trailing "empty" (all-0xff) pages + * is re-written, to make sure the empty space is actually erased. This is + * necessary for some NAND chips, since the 0xff data may have been programmed + * like real data (generating a non-0xff ECC), causing future writes to the + * not-really-erased pages to behave badly. + */ +static int ubifs_mount_fixup_lebs(struct ubifs_info *c) +{ + int lnum, err = 0; + int sup_flags = 0; + struct ubifs_sb_node *sup; + struct ubifs_scan_leb *sleb; + + ubifs_assert(c->leb_fixup); + ubifs_assert(!c->ro_mount); + + ubifs_msg("LEB fixup needed"); + + ubifs_get_lprops(c); + + /* + * Try and "recover" any currently-mapped LEB, which will truly erase + * any empty pages (they might currently exist as real 0xff data). + */ + for (lnum = 2; lnum <= c->leb_cnt; lnum++) { + lprops=ubifs_lpt_lookup(c, lnum); + if (IS_ERR(lprops)) { + err = PTR_ERR(lprops); + return err; + } + + if (!(lprops->flags & LPROPS_EMPTY)) { + sleb = ubifs_recover_leb(c, lnum, 0, c->sbuf, 0); + if (IS_ERR(sleb)) { + err = PTR_ERR(sleb); + return err; + } + ubifs_scan_destroy(sleb); + } + } + + ubifs_release_lprops(c); + + sup = ubifs_read_sb_node(c); + if (IS_ERR(sup)) { + err = PTR_ERR(sup); + goto out; + } + + /* LEB fixup is no longer required */ + c->leb_fixup = 0; + + /* Set new flags, omitting LEB fixup */ + sup_flags = 0; + if (c->big_lpt) + sup_flags |= UBIFS_FLG_BIGLPT; + sup->flags = cpu_to_le32(sup_flags); + + err = ubifs_write_sb_node(c, sup); + if (err) + goto out; + + ubifs_msg("LEB fixup complete"); +out: + return err; +} + +/** * mount_ubifs - mount UBIFS file-system. * @c: UBIFS file-system description object * @@ -1396,6 +1468,12 @@ static int mount_ubifs(struct ubifs_info *c) } else ubifs_assert(c->lst.taken_empty_lebs > 0); + if (!c->ro_mount && c->leb_fixup) { + err = ubifs_mount_fixup_lebs(c); + if (err) + goto out_infos; + } + err = dbg_check_filesystem(c); if (err) goto out_infos; @@ -1684,7 +1762,16 @@ static int ubifs_remount_rw(struct ubifs_info *c) * because, for example, the old index size was imprecise. */ err = dbg_check_space_info(c); + if (err) + goto out; } + + if (c->leb_fixup) { + err = ubifs_mount_fixup_lebs(c); + if (err) + goto out; + } + mutex_unlock(&c->umount_mutex); return err; diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h index b922f03..dfffa5a 100644 --- a/fs/ubifs/ubifs-media.h +++ b/fs/ubifs/ubifs-media.h @@ -408,9 +408,11 @@ enum { * Superblock flags. * * UBIFS_FLG_BIGLPT: if "big" LPT model is used if set + * UBIFS_FLG_LEB_FIXUP: first-mount "fixup" of empty pages in LEBs needed */ enum { UBIFS_FLG_BIGLPT = 0x02, + UBIFS_FLG_LEB_FIXUP = 0x04, }; /** diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 26a7ebe..c3d5544 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1254,6 +1254,7 @@ struct ubifs_info { wait_queue_head_t cmt_wq; unsigned int big_lpt:1; + unsigned int leb_fixup:1; unsigned int no_chk_data_crc:1; unsigned int bulk_read:1; unsigned int default_compr:2;