diff options
author | Alexander Stein <alexander.stein@systec-electronic.com> | 2016-03-17 11:00:29 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2016-04-08 13:33:18 +0200 |
commit | a63059d753680ce249942e2e6c4eba56c4840542 (patch) | |
tree | 5d6d708d353e9f90968a9e945f6eda100279b2c5 /fs/ubifs/master.c | |
parent | 84abb49171ac2f7c7f52842a88ab7ebb31b015f6 (diff) | |
download | barebox-a63059d753680ce249942e2e6c4eba56c4840542.tar.gz barebox-a63059d753680ce249942e2e6c4eba56c4840542.tar.xz |
ubifs: update implementation from u-boot v2016.03
This updated code supports recovering from unclean unmounts when write
buffer size is larger than 8. Linux uses takes information into
consideration when checking for writes.
The following list shows the changes for each file done compared to
u-boot v2016.03 code.
Makefile
* Add gc.o, do not include header as in u-boot
budget.c:
* Replace __UBOOT__ with __BAREBOX__
debug.c:
* Replace __UBOOT__ with __BAREBOX__
* Remove #include <linux/compat.h>
* Replace current->pid with 0
debug.h
* Replace __UBOOT__ with __BAREBOX__
* Add "0 &&" to ubifs_assert condition check
U-Boot essentially disabled pr_crit output and dump_stack() is defined
to do { } while (0), so ubifs_assert does nothing despite condition.
gc.c:
* Replace __UBOOT__ with __BAREBOX__
io.c:
* Replace __UBOOT__ with __BAREBOX__
* Remove #include <linux/compat.h>
key.h:
* No changes
log.c:
* No changes
lprops.c:
* Replace __UBOOT__ with __BAREBOX__
lpt.c
* Replace __UBOOT__ with __BAREBOX__
* Remove #include <linux/compat.h>
* Remove #include <ubi_uboot.h>
lpt_commit.c
* Replace __UBOOT__ with __BAREBOX__
* Remove #include <linux/compat.h>
master.c
* Replace __UBOOT__ with __BAREBOX__
* Remove #include <linux/compat.h>
* Remove #include <ubi_uboot.h>
misc.h
* Replace __UBOOT__ with __BAREBOX__
* Add #ifndef __BAREBOX__ around unneeded ubifs_current_time
orphan.c
* No changes
recovery.c
* Replace __UBOOT__ with __BAREBOX__
replay.c
* Replace __UBOOT__ with __BAREBOX__
* Remove #include <linux/compat.h>
sb.c
* Replace __UBOOT__ with __BAREBOX__
* Remove #include <linux/compat.h>
* Remove #include <ubi_uboot.h>
* rp_uid and rp_gid are still uid_t, not kuid_t, so remove .val
scan.c
* Replace __UBOOT__ with __BAREBOX__
super.c:
* Replaced current->pid with 0
* Replaced __UBOOT__ with __BAREBOX__
* Removed #include <ubi_uboot.h>
* Removed #include <memalign.h>
* Added #include <init.h>
* Replaced malloc_cache_aligned with kzalloc
* Replaced I_LOCK with I_SYNC
* i_uid and i_gid are still uid_t, not kuid_t, so remove .val
* Replaced string "U-Boot" with "Barebox"
* Add #ifndef __BAREBOX__ around open_ubi, sb_test, sb_set, ubifs_mount,
kill_ubifs_super, ubifs_fs_type
* Do not call ubi_open_volume or ubi_close_volume in ubifs_fill_super
Those will already be handled in ubifs_probe
* Replaced uboot_ubifs_mount with new ubifs_get_super implementation using
existing functions alloc_super, alloc_ubifs_info
tnc.c
* Replace __UBOOT__ with __BAREBOX__
* Remove #include <linux/compat.h>
tnc_misc.c
* Replace __UBOOT__ with __BAREBOX__
ubifs-media.h
* Replace __UBOOT__ with __BAREBOX__
ubifs.c:
* Replaced __UBOOT__ with __BAREBOX__
* Adjusted header includes
* Removed DECLARE_GLOBAL_DATA_PTR
* Add static struct z_stream_s variable
* Add struct ubifs_priv delcaration
* Replaced zunzip with deflate_decompress call
* Add ifdef for disabling ZLIB and/or LZO support
* Replaced malloc_cache_aligned with kzalloc
* Added #ifndef __BAREBOX__ around filldir, ubifs_printdir,
ubifs_set_blk_dev, ubifs_ls, ubifs_exists, ubifs_size, do_readpage,
ubifs_read, ubifs_close, ubifs_load
* Make parameter filename const char* in ubifs_findfile
* Add UBIFS fs_driver_d implementation
* Add zlib_decomp_init, ubifs_init
ubifs.h:
* Replaced __UBOOT__ with __BAREBOX__
* Adjusted header includes
* Added old #define crc32
* Added helper around kmem*
* Added XATTR_LIST_MAX define
* Added #ifndef __BAREBOX__ around current_fs_time struct inode,
struct super_block, file_system_type, dentry and friends which barebox
already has
* Added #ifndef __BAREBOX__ around write_inode in super_operations to avoid
declaration of writeback_control
* Change rp_uid and rp_gid to uid_t and gui_t
* Added struct device_d to struct ubifs_info
* Added forward declaration of ubifs_get_super
linux/fs.h:
* Make struct inode's i_nlink a union containing a non-const int __i_nlink
while making i_nlink a const int
linux/fs.h:
* Add s_remove_count
linux/fs.h:
* Convert struct super_block.s_instances and
struct file_system_type.fs_supers to hlist_head
Signed-off-by: Alexander Stein <alexander.stein@systec-electronic.com>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'fs/ubifs/master.c')
-rw-r--r-- | fs/ubifs/master.c | 102 |
1 files changed, 76 insertions, 26 deletions
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c index 3f2926e870..40d9ab4f35 100644 --- a/fs/ubifs/master.c +++ b/fs/ubifs/master.c @@ -3,18 +3,7 @@ * * 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 + * SPDX-License-Identifier: GPL-2.0+ * * Authors: Artem Bityutskiy (Битюцкий Артём) * Adrian Hunter @@ -23,13 +12,17 @@ /* This file implements reading and writing the master node */ #include "ubifs.h" +#ifdef __BAREBOX__ +#include <linux/err.h> +#endif /** * scan_for_master - search the valid master node. * @c: UBIFS file-system description object * * This function scans the master node LEBs and search for the latest master - * node. Returns zero in case of success and a negative error code in case of + * node. Returns zero in case of success, %-EUCLEAN if there master area is + * corrupted and requires recovery, and a negative error code in case of * failure. */ static int scan_for_master(struct ubifs_info *c) @@ -40,7 +33,7 @@ static int scan_for_master(struct ubifs_info *c) lnum = UBIFS_MST_LNUM; - sleb = ubifs_scan(c, lnum, 0, c->sbuf); + sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1); if (IS_ERR(sleb)) return PTR_ERR(sleb); nodes_cnt = sleb->nodes_cnt; @@ -48,7 +41,7 @@ static int scan_for_master(struct ubifs_info *c) snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list); if (snod->type != UBIFS_MST_NODE) - goto out; + goto out_dump; memcpy(c->mst_node, snod->node, snod->len); offs = snod->offs; } @@ -56,7 +49,7 @@ static int scan_for_master(struct ubifs_info *c) lnum += 1; - sleb = ubifs_scan(c, lnum, 0, c->sbuf); + sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1); if (IS_ERR(sleb)) return PTR_ERR(sleb); if (sleb->nodes_cnt != nodes_cnt) @@ -65,7 +58,7 @@ static int scan_for_master(struct ubifs_info *c) goto out; snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list); if (snod->type != UBIFS_MST_NODE) - goto out; + goto out_dump; if (snod->offs != offs) goto out; if (memcmp((void *)c->mst_node + UBIFS_CH_SZ, @@ -78,6 +71,12 @@ static int scan_for_master(struct ubifs_info *c) out: ubifs_scan_destroy(sleb); + return -EUCLEAN; + +out_dump: + ubifs_err(c, "unexpected node type %d master LEB %d:%d", + snod->type, lnum, snod->offs); + ubifs_scan_destroy(sleb); return -EINVAL; } @@ -141,7 +140,7 @@ static int validate_master(const struct ubifs_info *c) } main_sz = (long long)c->main_lebs * c->leb_size; - if (c->old_idx_sz & 7 || c->old_idx_sz >= main_sz) { + if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) { err = 9; goto out; } @@ -211,7 +210,7 @@ static int validate_master(const struct ubifs_info *c) } if (c->lst.total_dead + c->lst.total_dark + - c->lst.total_used + c->old_idx_sz > main_sz) { + c->lst.total_used + c->bi.old_idx_sz > main_sz) { err = 21; goto out; } @@ -233,8 +232,8 @@ static int validate_master(const struct ubifs_info *c) return 0; out: - ubifs_err("bad master node at offset %d error %d", c->mst_offs, err); - dbg_dump_node(c, c->mst_node); + ubifs_err(c, "bad master node at offset %d error %d", c->mst_offs, err); + ubifs_dump_node(c, c->mst_node); return -EINVAL; } @@ -256,7 +255,8 @@ int ubifs_read_master(struct ubifs_info *c) err = scan_for_master(c); if (err) { - err = ubifs_recover_master_node(c); + if (err == -EUCLEAN) + err = ubifs_recover_master_node(c); if (err) /* * Note, we do not free 'c->mst_node' here because the @@ -278,7 +278,7 @@ int ubifs_read_master(struct ubifs_info *c) c->gc_lnum = le32_to_cpu(c->mst_node->gc_lnum); c->ihead_lnum = le32_to_cpu(c->mst_node->ihead_lnum); c->ihead_offs = le32_to_cpu(c->mst_node->ihead_offs); - c->old_idx_sz = le64_to_cpu(c->mst_node->index_size); + c->bi.old_idx_sz = le64_to_cpu(c->mst_node->index_size); c->lpt_lnum = le32_to_cpu(c->mst_node->lpt_lnum); c->lpt_offs = le32_to_cpu(c->mst_node->lpt_offs); c->nhead_lnum = le32_to_cpu(c->mst_node->nhead_lnum); @@ -297,7 +297,7 @@ int ubifs_read_master(struct ubifs_info *c) c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead); c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark); - c->calc_idx_sz = c->old_idx_sz; + c->calc_idx_sz = c->bi.old_idx_sz; if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS)) c->no_orphs = 1; @@ -308,8 +308,8 @@ int ubifs_read_master(struct ubifs_info *c) if (c->leb_cnt < old_leb_cnt || c->leb_cnt < UBIFS_MIN_LEB_CNT) { - ubifs_err("bad leb_cnt on master node"); - dbg_dump_node(c, c->mst_node); + ubifs_err(c, "bad leb_cnt on master node"); + ubifs_dump_node(c, c->mst_node); return -EINVAL; } @@ -335,7 +335,57 @@ int ubifs_read_master(struct ubifs_info *c) if (err) return err; +#ifndef __BAREBOX__ err = dbg_old_index_check_init(c, &c->zroot); +#endif + + return err; +} + +#ifndef __BAREBOX__ +/** + * ubifs_write_master - write master node. + * @c: UBIFS file-system description object + * + * This function writes the master node. Returns zero in case of success and a + * negative error code in case of failure. The master node is written twice to + * enable recovery. + */ +int ubifs_write_master(struct ubifs_info *c) +{ + int err, lnum, offs, len; + + ubifs_assert(!c->ro_media && !c->ro_mount); + if (c->ro_error) + return -EROFS; + + lnum = UBIFS_MST_LNUM; + offs = c->mst_offs + c->mst_node_alsz; + len = UBIFS_MST_NODE_SZ; + + if (offs + UBIFS_MST_NODE_SZ > c->leb_size) { + err = ubifs_leb_unmap(c, lnum); + if (err) + return err; + offs = 0; + } + + c->mst_offs = offs; + c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); + + err = ubifs_write_node(c, c->mst_node, len, lnum, offs); + if (err) + return err; + + lnum += 1; + + if (offs == 0) { + err = ubifs_leb_unmap(c, lnum); + if (err) + return err; + } + err = ubifs_write_node(c, c->mst_node, len, lnum, offs); return err; } +#endif |