From patchwork Fri Apr 29 14:14:04 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Artem Bityutskiy X-Patchwork-Id: 93430 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 00010B6FD7 for ; Sat, 30 Apr 2011 00:12:55 +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 1QFoPW-0004xT-N8; Fri, 29 Apr 2011 14:11:10 +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 1QFoPU-0002NF-4g; Fri, 29 Apr 2011 14:11:08 +0000 Received: from smtp.nokia.com ([147.243.1.48] helo=mgw-sa02.nokia.com) by canuck.infradead.org with esmtps (Exim 4.72 #1 (Red Hat Linux)) id 1QFoPP-0002Mf-LG for linux-mtd@lists.infradead.org; Fri, 29 Apr 2011 14:11:04 +0000 Received: from nokia.com (localhost [127.0.0.1]) by mgw-sa02.nokia.com (Switch-3.4.4/Switch-3.4.3) with ESMTP id p3TEB1FS008163 for ; Fri, 29 Apr 2011 17:11:01 +0300 Received: from eru.research.nokia.com ([[172.21.24.121]]) by mgw-sa02.nokia.com with ESMTP id p3TEAISm007126 ; Fri, 29 Apr 2011 17:10:37 +0300 From: Artem Bityutskiy To: MTD list Subject: [PATCH 1/2] UBIFS: split ubifs_rcvry_gc_commit Date: Fri, 29 Apr 2011 17:14:04 +0300 Message-Id: <1304086445-5595-1-git-send-email-dedekind1@gmail.com> X-Mailer: git-send-email 1.7.2.3 X-Nokia-AV: Clean X-CRM114-Version: 20090807-BlameThorstenAndJenny ( TRE 0.7.6 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20110429_101104_032620_F4D358CE X-CRM114-Status: GOOD ( 20.31 ) X-Spam-Score: 3.4 (+++) X-Spam-Report: SpamAssassin version 3.3.1 on canuck.infradead.org summary: Content analysis details: (3.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 FREEMAIL_FROM Sender email is freemail (dedekind1[at]gmail.com) 0.0 DKIM_ADSP_CUSTOM_MED No valid author signature, adsp_override is CUSTOM_MED 2.2 FREEMAIL_ENVFROM_END_DIGIT Envelope-from freemail username ends in digit (dedekind1[at]gmail.com) -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, low trust [147.243.1.48 listed in list.dnswl.org] 0.0 RFC_ABUSE_POST Both abuse and postmaster missing on sender domain 1.2 NML_ADSP_CUSTOM_MED ADSP custom_med hit, and not from a mailing list Cc: Adrian Hunter 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: , MIME-Version: 1.0 Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Artem Bityutskiy Split the 'ubifs_rcvry_gc_commit()' function and introduce a 'grab_empty_leb()' heler. This cleans 'ubifs_rcvry_gc_commit()' a little and makes it a bit less of spagetti. Also, add a commentary which explains why it is crucial to first search for an empty LEB and then run commit. Signed-off-by: Artem Bityutskiy --- fs/ubifs/recovery.c | 77 +++++++++++++++++++++++++++++++++------------------ 1 files changed, 50 insertions(+), 27 deletions(-) diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c index 3d2598d..11776ae 100644 --- a/fs/ubifs/recovery.c +++ b/fs/ubifs/recovery.c @@ -1070,6 +1070,53 @@ int ubifs_clean_lebs(const struct ubifs_info *c, void *sbuf) } /** + * grab_empty_leb - grab an empty LEB to use as GC LEB and run commit. + * @c: UBIFS file-system description object + * + * This is a helper function for 'ubifs_rcvry_gc_commit()' which grabs an empty + * LEB to be used as GC LEB (@c->gc_lnum), and then runs the commit. Returns + * zero in case of success and a negative error code in case of failure. + */ +static int grab_empty_leb(struct ubifs_info *c) +{ + int lnum, err; + + /* + * Note, it is very important to first search for an empty LEB and then + * run the commit, not vice-versa. The reason is that there might be + * only one empty LEB at the moment, the one which has been the + * @c->gc_lnum just before the power cut happened. During the regular + * UBIFS operation (not now) @c->gc_lnum is marked as "taken", so no + * one but GC can grab it. But at this moment this single empty LEB is + * not marked as taken, so if we run commit - what happens? Right, the + * commit will grab it and write the index there. Remember that the + * index always expands as long as there is free space, and it only + * starts consolidating when we run out of space. + * + * IOW, if we run commit now, we might not be able to find a free LEB + * after this. + */ + lnum = ubifs_find_free_leb_for_idx(c); + if (lnum < 0) { + dbg_err("could not find an empty LEB"); + dbg_dump_lprops(c); + dbg_dump_budg(c, &c->bi); + return lnum; + } + + /* Reset the index flag */ + err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0, + LPROPS_INDEX, 0); + if (err) + return err; + + c->gc_lnum = lnum; + dbg_rcvry("found empty LEB %d, run commit", lnum); + + return ubifs_run_commit(c); +} + +/** * ubifs_rcvry_gc_commit - recover the GC LEB number and run the commit. * @c: UBIFS file-system description object * @@ -1096,7 +1143,7 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c) c->gc_lnum = -1; if (wbuf->lnum == -1) { dbg_rcvry("no GC head LEB"); - goto find_free; + return grab_empty_leb(c); } /* * See whether the used space in the dirtiest LEB fits in the GC head @@ -1104,7 +1151,7 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c) */ if (wbuf->offs == c->leb_size) { dbg_rcvry("no room in GC head LEB"); - goto find_free; + return grab_empty_leb(c); } err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2); if (err) { @@ -1121,7 +1168,7 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c) */ if (err == -ENOSPC) { dbg_rcvry("could not find a dirty LEB"); - goto find_free; + return grab_empty_leb(c); } return err; } @@ -1167,30 +1214,6 @@ int ubifs_rcvry_gc_commit(struct ubifs_info *c) return err; dbg_rcvry("allocated LEB %d for GC", lnum); return 0; - -find_free: - /* - * There is no GC head LEB or the free space in the GC head LEB is too - * small, or there are not dirty LEBs. Allocate gc_lnum by calling - * 'ubifs_find_free_leb_for_idx()' so GC is not run. - */ - lnum = ubifs_find_free_leb_for_idx(c); - if (lnum < 0) { - dbg_err("could not find an empty LEB"); - dbg_dump_lprops(c); - dbg_dump_budg(c, &c->bi); - return lnum; - } - /* And reset the index flag */ - err = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0, - LPROPS_INDEX, 0); - if (err) - return err; - c->gc_lnum = lnum; - dbg_rcvry("allocated LEB %d for GC", lnum); - /* Run the commit */ - dbg_rcvry("committing"); - return ubifs_run_commit(c); } /**