[U-Boot] [PATCH v2] Enable journal replay for UBIFS
Heiko Schocher
hs at denx.de
Tue Jan 20 08:41:45 CET 2015
Hello Anton,
Am 19.01.2015 14:48, schrieb Anton Habegger:
> During mount_ubifs the ubifs_replay_journal was disabled. This patch
> enables it again and fix some unrecoverable UBIFS volumes.
>
> The following patch enables the error handling for ubifs_replay_journal as well.
> Please see discussion "Unreadable UBIFS partition after power cuts".
>
>
> Signed-off-by: Anton Habegger <anton.habegger at delta-es.com>
> ---
> fs/ubifs/Makefile | 2 +-
> fs/ubifs/gc.c | 987 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> fs/ubifs/replay.c | 8 +-
> fs/ubifs/super.c | 8 +-
> fs/ubifs/tnc.c | 7 +-
> 5 files changed, 997 insertions(+), 15 deletions(-)
> create mode 100644 fs/ubifs/gc.c
Thanks!
> diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
> index 8c8c6ac..5efb349 100644
> --- a/fs/ubifs/Makefile
> +++ b/fs/ubifs/Makefile
> @@ -12,4 +12,4 @@
> obj-y := ubifs.o io.o super.o sb.o master.o lpt.o
> obj-y += lpt_commit.o scan.o lprops.o
> obj-y += tnc.o tnc_misc.o debug.o crc16.o budget.o
> -obj-y += log.o orphan.o recovery.o replay.o
> +obj-y += log.o orphan.o recovery.o replay.o gc.o
Hmm.... do we really need this in u-boot? Ah, the most functions
are unneeded ... ok.
> diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
> new file mode 100644
> index 0000000..159ee67
> --- /dev/null
> +++ b/fs/ubifs/gc.c
> @@ -0,0 +1,987 @@
> +/*
> + * This file is part of UBIFS.
> + *
> + * Copyright (C) 2006-2008 Nokia Corporation.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program; if not, write to the Free Software Foundation, Inc., 51
> + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + * Authors: Adrian Hunter
> + * Artem Bityutskiy (Битюцкий Артём)
> + */
> +
> +/*
> + * This file implements garbage collection. The procedure for garbage
> collection
> + * is different depending on whether a LEB as an index LEB (contains index
> + * nodes) or not. For non-index LEBs, garbage collection finds a LEB which
> + * contains a lot of dirty space (obsolete nodes), and copies the non-obsolete
> + * nodes to the journal, at which point the garbage-collected LEB is free to be
> + * reused. For index LEBs, garbage collection marks the non-obsolete
> index nodes
> + * dirty in the TNC, and after the next commit, the garbage-collected LEB is
> + * to be reused. Garbage collection will cause the number of dirty index nodes
> + * to grow, however sufficient space is reserved for the index to ensure the
> + * commit will never run out of space.
> + *
> + * Notes about dead watermark. At current UBIFS implementation we assume that
> + * LEBs which have less than @c->dead_wm bytes of free + dirty space are full
> + * and not worth garbage-collecting. The dead watermark is one min. I/O unit
> + * size, or min. UBIFS node size, depending on what is greater. Indeed, UBIFS
> + * Garbage Collector has to synchronize the GC head's write buffer before
> + * returning, so this is about wasting one min. I/O unit. However, UBIFS GC can
> + * actually reclaim even very small pieces of dirty space by garbage collecting
> + * enough dirty LEBs, but we do not bother doing this at this implementation.
> + *
> + * Notes about dark watermark. The results of GC work depends on how big are
> + * the UBIFS nodes GC deals with. Large nodes make GC waste more space. Indeed,
> + * if GC move data from LEB A to LEB B and nodes in LEB A are large, GC would
> + * have to waste large pieces of free space at the end of LEB B, because nodes
> + * from LEB A would not fit. And the worst situation is when all nodes are of
> + * maximum size. So dark watermark is the amount of free + dirty space in LEB
> + * which are guaranteed to be reclaimable. If LEB has less space, the GC might
> + * be unable to reclaim it. So, LEBs with free + dirty greater than dark
> + * watermark are "good" LEBs from GC's point of few. The other LEBs are not so
> + * good, and GC takes extra care when moving them.
> + */
> +#ifndef __UBOOT__
> +#include <linux/slab.h>
> +#include <linux/pagemap.h>
> +#include <linux/list_sort.h>
> +#endif
> +#include "ubifs.h"
> +
> +#ifndef __UBOOT__
> +/*
> + * GC may need to move more than one LEB to make progress. The below constants
> + * define "soft" and "hard" limits on the number of LEBs the garbage collector
> + * may move.
> + */
> +#define SOFT_LEBS_LIMIT 4
> +#define HARD_LEBS_LIMIT 32
> +
> +/**
> + * switch_gc_head - switch the garbage collection journal head.
> + * @c: UBIFS file-system description object
> + * @buf: buffer to write
> + * @len: length of the buffer to write
> + * @lnum: LEB number written is returned here
> + * @offs: offset written is returned here
> + *
> + * This function switch the GC head to the next LEB which is reserved in
> + * @c->gc_lnum. Returns %0 in case of success, %-EAGAIN if commit is required,
> + * and other negative error code in case of failures.
> + */
> +static int switch_gc_head(struct ubifs_info *c)
> +{
> + int err, gc_lnum = c->gc_lnum;
> + struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
> +
> + ubifs_assert(gc_lnum != -1);
Hmm.. something seems wrong with your mailer ... your patch is malformed.
Could you fix this please?
[...]
> diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
> index 7268b37..75b92ac 100644
> --- a/fs/ubifs/replay.c
> +++ b/fs/ubifs/replay.c
[...]
> @@ -1050,7 +1047,11 @@ int ubifs_replay_journal(struct ubifs_info *c)
> * depend on it. This means we have to initialize it to make sure
> * budgeting works properly.
> */
> +#ifndef __UBOOT__
> c->bi.uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
> +#else
> + c->bi.uncommitted_idx = c->dirty_zn_cnt;
> +#endif
please introduce atomic_long_read() as mentioned to your other EMail.
> c->bi.uncommitted_idx *= c->max_idx_node_sz;
>
> ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
> @@ -1063,4 +1064,3 @@ out:
> c->replaying = 0;
> return err;
> }
> -#endif
> diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
> index 01d449a..10f8fff 100644
> --- a/fs/ubifs/super.c
> +++ b/fs/ubifs/super.c
> @@ -1049,7 +1049,6 @@ static void free_orphans(struct ubifs_info *c)
> c->orph_buf = NULL;
> }
>
> -#ifndef __UBOOT__
> /**
> * free_buds - free per-bud objects.
> * @c: UBIFS file-system description object
> @@ -1061,7 +1060,6 @@ static void free_buds(struct ubifs_info *c)
> rbtree_postorder_for_each_entry_safe(bud, n, &c->buds, rb)
> kfree(bud);
> }
> -#endif
>
> /**
> * check_volume_empty - check if the UBI volume is empty.
> @@ -1242,6 +1240,7 @@ static int ubifs_parse_options(struct ubifs_info
> *c, char *options,
>
> return 0;
> }
> +#endif
>
> /**
> * destroy_journal - destroy journal data structures.
> @@ -1272,7 +1271,6 @@ static void destroy_journal(struct ubifs_info *c)
> ubifs_tnc_close(c);
> free_buds(c);
> }
> -#endif
>
> /**
> * bu_init - initialize bulk-read information.
> @@ -1502,11 +1500,9 @@ static int mount_ubifs(struct ubifs_info *c)
> if (err)
> goto out_lpt;
>
> -#ifndef __UBOOT__
> err = ubifs_replay_journal(c);
> if (err)
> goto out_journal;
> -#endif
>
> /* Calculate 'min_idx_lebs' after journal replay */
> c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
> @@ -1678,10 +1674,8 @@ out_infos:
> spin_unlock(&ubifs_infos_lock);
> out_orphans:
> free_orphans(c);
> -#ifndef __UBOOT__
> out_journal:
> destroy_journal(c);
> -#endif
> out_lpt:
> ubifs_lpt_free(c, 0);
> out_master:
> diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
> index 95cae54..b6737db 100644
> --- a/fs/ubifs/tnc.c
> +++ b/fs/ubifs/tnc.c
> @@ -2827,7 +2827,6 @@ out_unlock:
> return ERR_PTR(err);
> }
>
> -#ifndef __UBOOT__
> /**
> * tnc_destroy_cnext - destroy left-over obsolete znodes from a failed commit.
> * @c: UBIFS file-system description object
> @@ -2850,7 +2849,6 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
> kfree(znode);
> } while (cnext && cnext != c->cnext);
> }
> -
> /**
> * ubifs_tnc_close - close TNC subsystem and free all related resources.
> * @c: UBIFS file-system description object
> @@ -2859,17 +2857,20 @@ void ubifs_tnc_close(struct ubifs_info *c)
> {
> tnc_destroy_cnext(c);
> if (c->zroot.znode) {
> +#ifndef __UBOOT__
> long n;
> +#endif
>
> ubifs_destroy_tnc_subtree(c->zroot.znode);
> +#ifndef __UBOOT__
> n = atomic_long_read(&c->clean_zn_cnt);
> atomic_long_sub(n, &ubifs_clean_zn_cnt);
> +#endif
> }
> kfree(c->gap_lebs);
> kfree(c->ilebs);
> destroy_old_idx(c);
> }
> -#endif
>
> /**
> * left_znode - get the znode to the left.
>
bye,
Heiko
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
More information about the U-Boot
mailing list