* [PATCH 10/14] fs: ubifs: remove not needed code
2018-10-02 14:03 [PATCH 00/14] UBIFS update Sascha Hauer
` (8 preceding siblings ...)
2018-10-02 14:03 ` [PATCH 09/14] fs: implement clear_nlink and set_nlink Sascha Hauer
@ 2018-10-02 14:03 ` Sascha Hauer
2018-10-02 14:04 ` [PATCH 11/14] compiler: Update to v4.19-rc6 Sascha Hauer
` (4 subsequent siblings)
14 siblings, 0 replies; 18+ messages in thread
From: Sascha Hauer @ 2018-10-02 14:03 UTC (permalink / raw)
To: Barebox List
This patch aggressively removes stuff that we do not need in a readonly
implementation:
- write buffering support
- lpt/ltab code
- garbage collector
- everything under #ifndef __BAREBOX__
This decreases the binary size by about 5k on ARM, but the main reason
for doing this is the idea that things that are not there don't need to
be synced with upstream ubifs code.
The __BAREBOX__ ifdeffery makes the code very hard to read and is a
maintenance burden by itself, so it is removed here aswell.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/ubifs/Makefile | 8 +-
fs/ubifs/budget.c | 729 ------------
fs/ubifs/debug.c | 2533 ----------------------------------------
fs/ubifs/debug.h | 66 --
fs/ubifs/gc.c | 976 ----------------
fs/ubifs/io.c | 806 -------------
fs/ubifs/log.c | 649 ----------
fs/ubifs/lprops.c | 1313 ---------------------
fs/ubifs/lpt.c | 2282 ------------------------------------
fs/ubifs/lpt_commit.c | 2022 --------------------------------
fs/ubifs/master.c | 52 -
fs/ubifs/misc.h | 41 +-
fs/ubifs/orphan.c | 946 ---------------
fs/ubifs/recovery.c | 490 --------
fs/ubifs/replay.c | 151 +--
fs/ubifs/sb.c | 473 --------
fs/ubifs/scan.c | 2 -
fs/ubifs/super.c | 1428 +---------------------
fs/ubifs/tnc.c | 1140 +-----------------
fs/ubifs/tnc_misc.c | 16 +-
fs/ubifs/ubifs-media.h | 12 -
fs/ubifs/ubifs.c | 14 -
fs/ubifs/ubifs.h | 71 +-
23 files changed, 14 insertions(+), 16206 deletions(-)
delete mode 100644 fs/ubifs/budget.c
delete mode 100644 fs/ubifs/gc.c
delete mode 100644 fs/ubifs/lprops.c
delete mode 100644 fs/ubifs/lpt.c
delete mode 100644 fs/ubifs/orphan.c
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index 44ef1b561c..b8f47e77f2 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -1,4 +1,4 @@
-obj-y += ubifs.o io.o super.o sb.o master.o lpt.o
-obj-y += lpt_commit.o scan.o lprops.o dir.o
-obj-y += tnc.o tnc_misc.o debug.o crc16.o budget.o
-obj-y += log.o orphan.o recovery.o replay.o gc.o
+obj-y += ubifs.o io.o super.o sb.o master.o
+obj-y += lpt_commit.o scan.o dir.o
+obj-y += tnc.o tnc_misc.o debug.o crc16.o
+obj-y += log.o recovery.o replay.o
diff --git a/fs/ubifs/budget.c b/fs/ubifs/budget.c
deleted file mode 100644
index b160ec63a2..0000000000
--- a/fs/ubifs/budget.c
+++ /dev/null
@@ -1,729 +0,0 @@
-/*
- * This file is part of UBIFS.
- *
- * Copyright (C) 2006-2008 Nokia Corporation.
- *
- * SPDX-License-Identifier: GPL-2.0+
- *
- * Authors: Adrian Hunter
- * Artem Bityutskiy (Битюцкий Артём)
- */
-
-/*
- * This file implements the budgeting sub-system which is responsible for UBIFS
- * space management.
- *
- * Factors such as compression, wasted space at the ends of LEBs, space in other
- * journal heads, the effect of updates on the index, and so on, make it
- * impossible to accurately predict the amount of space needed. Consequently
- * approximations are used.
- */
-
-#include "ubifs.h"
-#ifndef __BAREBOX__
-#include <linux/writeback.h>
-#else
-#include <linux/err.h>
-#endif
-#include <linux/math64.h>
-
-/*
- * When pessimistic budget calculations say that there is no enough space,
- * UBIFS starts writing back dirty inodes and pages, doing garbage collection,
- * or committing. The below constant defines maximum number of times UBIFS
- * repeats the operations.
- */
-#define MAX_MKSPC_RETRIES 3
-
-/*
- * The below constant defines amount of dirty pages which should be written
- * back at when trying to shrink the liability.
- */
-#define NR_TO_WRITE 16
-
-#ifndef __BAREBOX__
-/**
- * shrink_liability - write-back some dirty pages/inodes.
- * @c: UBIFS file-system description object
- * @nr_to_write: how many dirty pages to write-back
- *
- * This function shrinks UBIFS liability by means of writing back some amount
- * of dirty inodes and their pages.
- *
- * Note, this function synchronizes even VFS inodes which are locked
- * (@i_mutex) by the caller of the budgeting function, because write-back does
- * not touch @i_mutex.
- */
-static void shrink_liability(struct ubifs_info *c, int nr_to_write)
-{
- down_read(&c->vfs_sb->s_umount);
- writeback_inodes_sb(c->vfs_sb, WB_REASON_FS_FREE_SPACE);
- up_read(&c->vfs_sb->s_umount);
-}
-
-/**
- * run_gc - run garbage collector.
- * @c: UBIFS file-system description object
- *
- * This function runs garbage collector to make some more free space. Returns
- * zero if a free LEB has been produced, %-EAGAIN if commit is required, and a
- * negative error code in case of failure.
- */
-static int run_gc(struct ubifs_info *c)
-{
- int err, lnum;
-
- /* Make some free space by garbage-collecting dirty space */
- down_read(&c->commit_sem);
- lnum = ubifs_garbage_collect(c, 1);
- up_read(&c->commit_sem);
- if (lnum < 0)
- return lnum;
-
- /* GC freed one LEB, return it to lprops */
- dbg_budg("GC freed LEB %d", lnum);
- err = ubifs_return_leb(c, lnum);
- if (err)
- return err;
- return 0;
-}
-
-/**
- * get_liability - calculate current liability.
- * @c: UBIFS file-system description object
- *
- * This function calculates and returns current UBIFS liability, i.e. the
- * amount of bytes UBIFS has "promised" to write to the media.
- */
-static long long get_liability(struct ubifs_info *c)
-{
- long long liab;
-
- spin_lock(&c->space_lock);
- liab = c->bi.idx_growth + c->bi.data_growth + c->bi.dd_growth;
- spin_unlock(&c->space_lock);
- return liab;
-}
-
-/**
- * make_free_space - make more free space on the file-system.
- * @c: UBIFS file-system description object
- *
- * This function is called when an operation cannot be budgeted because there
- * is supposedly no free space. But in most cases there is some free space:
- * o budgeting is pessimistic, so it always budgets more than it is actually
- * needed, so shrinking the liability is one way to make free space - the
- * cached data will take less space then it was budgeted for;
- * o GC may turn some dark space into free space (budgeting treats dark space
- * as not available);
- * o commit may free some LEB, i.e., turn freeable LEBs into free LEBs.
- *
- * So this function tries to do the above. Returns %-EAGAIN if some free space
- * was presumably made and the caller has to re-try budgeting the operation.
- * Returns %-ENOSPC if it couldn't do more free space, and other negative error
- * codes on failures.
- */
-static int make_free_space(struct ubifs_info *c)
-{
- int err, retries = 0;
- long long liab1, liab2;
-
- do {
- liab1 = get_liability(c);
- /*
- * We probably have some dirty pages or inodes (liability), try
- * to write them back.
- */
- dbg_budg("liability %lld, run write-back", liab1);
- shrink_liability(c, NR_TO_WRITE);
-
- liab2 = get_liability(c);
- if (liab2 < liab1)
- return -EAGAIN;
-
- dbg_budg("new liability %lld (not shrunk)", liab2);
-
- /* Liability did not shrink again, try GC */
- dbg_budg("Run GC");
- err = run_gc(c);
- if (!err)
- return -EAGAIN;
-
- if (err != -EAGAIN && err != -ENOSPC)
- /* Some real error happened */
- return err;
-
- dbg_budg("Run commit (retries %d)", retries);
- err = ubifs_run_commit(c);
- if (err)
- return err;
- } while (retries++ < MAX_MKSPC_RETRIES);
-
- return -ENOSPC;
-}
-#endif
-
-/**
- * ubifs_calc_min_idx_lebs - calculate amount of LEBs for the index.
- * @c: UBIFS file-system description object
- *
- * This function calculates and returns the number of LEBs which should be kept
- * for index usage.
- */
-int ubifs_calc_min_idx_lebs(struct ubifs_info *c)
-{
- int idx_lebs;
- long long idx_size;
-
- idx_size = c->bi.old_idx_sz + c->bi.idx_growth + c->bi.uncommitted_idx;
- /* And make sure we have thrice the index size of space reserved */
- idx_size += idx_size << 1;
- /*
- * We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes'
- * pair, nor similarly the two variables for the new index size, so we
- * have to do this costly 64-bit division on fast-path.
- */
- idx_lebs = div_u64(idx_size + c->idx_leb_size - 1, c->idx_leb_size);
- /*
- * The index head is not available for the in-the-gaps method, so add an
- * extra LEB to compensate.
- */
- idx_lebs += 1;
- if (idx_lebs < MIN_INDEX_LEBS)
- idx_lebs = MIN_INDEX_LEBS;
- return idx_lebs;
-}
-
-#ifndef __BAREBOX__
-/**
- * ubifs_calc_available - calculate available FS space.
- * @c: UBIFS file-system description object
- * @min_idx_lebs: minimum number of LEBs reserved for the index
- *
- * This function calculates and returns amount of FS space available for use.
- */
-long long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs)
-{
- int subtract_lebs;
- long long available;
-
- available = c->main_bytes - c->lst.total_used;
-
- /*
- * Now 'available' contains theoretically available flash space
- * assuming there is no index, so we have to subtract the space which
- * is reserved for the index.
- */
- subtract_lebs = min_idx_lebs;
-
- /* Take into account that GC reserves one LEB for its own needs */
- subtract_lebs += 1;
-
- /*
- * The GC journal head LEB is not really accessible. And since
- * different write types go to different heads, we may count only on
- * one head's space.
- */
- subtract_lebs += c->jhead_cnt - 1;
-
- /* We also reserve one LEB for deletions, which bypass budgeting */
- subtract_lebs += 1;
-
- available -= (long long)subtract_lebs * c->leb_size;
-
- /* Subtract the dead space which is not available for use */
- available -= c->lst.total_dead;
-
- /*
- * Subtract dark space, which might or might not be usable - it depends
- * on the data which we have on the media and which will be written. If
- * this is a lot of uncompressed or not-compressible data, the dark
- * space cannot be used.
- */
- available -= c->lst.total_dark;
-
- /*
- * However, there is more dark space. The index may be bigger than
- * @min_idx_lebs. Those extra LEBs are assumed to be available, but
- * their dark space is not included in total_dark, so it is subtracted
- * here.
- */
- if (c->lst.idx_lebs > min_idx_lebs) {
- subtract_lebs = c->lst.idx_lebs - min_idx_lebs;
- available -= subtract_lebs * c->dark_wm;
- }
-
- /* The calculations are rough and may end up with a negative number */
- return available > 0 ? available : 0;
-}
-
-/**
- * can_use_rp - check whether the user is allowed to use reserved pool.
- * @c: UBIFS file-system description object
- *
- * UBIFS has so-called "reserved pool" which is flash space reserved
- * for the superuser and for uses whose UID/GID is recorded in UBIFS superblock.
- * This function checks whether current user is allowed to use reserved pool.
- * Returns %1 current user is allowed to use reserved pool and %0 otherwise.
- */
-static int can_use_rp(struct ubifs_info *c)
-{
- if (uid_eq(current_fsuid(), c->rp_uid) || capable(CAP_SYS_RESOURCE) ||
- (!gid_eq(c->rp_gid, GLOBAL_ROOT_GID) && in_group_p(c->rp_gid)))
- return 1;
- return 0;
-}
-
-/**
- * do_budget_space - reserve flash space for index and data growth.
- * @c: UBIFS file-system description object
- *
- * This function makes sure UBIFS has enough free LEBs for index growth and
- * data.
- *
- * When budgeting index space, UBIFS reserves thrice as many LEBs as the index
- * would take if it was consolidated and written to the flash. This guarantees
- * that the "in-the-gaps" commit method always succeeds and UBIFS will always
- * be able to commit dirty index. So this function basically adds amount of
- * budgeted index space to the size of the current index, multiplies this by 3,
- * and makes sure this does not exceed the amount of free LEBs.
- *
- * Notes about @c->bi.min_idx_lebs and @c->lst.idx_lebs variables:
- * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might
- * be large, because UBIFS does not do any index consolidation as long as
- * there is free space. IOW, the index may take a lot of LEBs, but the LEBs
- * will contain a lot of dirt.
- * o @c->bi.min_idx_lebs is the number of LEBS the index presumably takes. IOW,
- * the index may be consolidated to take up to @c->bi.min_idx_lebs LEBs.
- *
- * This function returns zero in case of success, and %-ENOSPC in case of
- * failure.
- */
-static int do_budget_space(struct ubifs_info *c)
-{
- long long outstanding, available;
- int lebs, rsvd_idx_lebs, min_idx_lebs;
-
- /* First budget index space */
- min_idx_lebs = ubifs_calc_min_idx_lebs(c);
-
- /* Now 'min_idx_lebs' contains number of LEBs to reserve */
- if (min_idx_lebs > c->lst.idx_lebs)
- rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs;
- else
- rsvd_idx_lebs = 0;
-
- /*
- * The number of LEBs that are available to be used by the index is:
- *
- * @c->lst.empty_lebs + @c->freeable_cnt + @c->idx_gc_cnt -
- * @c->lst.taken_empty_lebs
- *
- * @c->lst.empty_lebs are available because they are empty.
- * @c->freeable_cnt are available because they contain only free and
- * dirty space, @c->idx_gc_cnt are available because they are index
- * LEBs that have been garbage collected and are awaiting the commit
- * before they can be used. And the in-the-gaps method will grab these
- * if it needs them. @c->lst.taken_empty_lebs are empty LEBs that have
- * already been allocated for some purpose.
- *
- * Note, @c->idx_gc_cnt is included to both @c->lst.empty_lebs (because
- * these LEBs are empty) and to @c->lst.taken_empty_lebs (because they
- * are taken until after the commit).
- *
- * Note, @c->lst.taken_empty_lebs may temporarily be higher by one
- * because of the way we serialize LEB allocations and budgeting. See a
- * comment in 'ubifs_find_free_space()'.
- */
- lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
- c->lst.taken_empty_lebs;
- if (unlikely(rsvd_idx_lebs > lebs)) {
- dbg_budg("out of indexing space: min_idx_lebs %d (old %d), rsvd_idx_lebs %d",
- min_idx_lebs, c->bi.min_idx_lebs, rsvd_idx_lebs);
- return -ENOSPC;
- }
-
- available = ubifs_calc_available(c, min_idx_lebs);
- outstanding = c->bi.data_growth + c->bi.dd_growth;
-
- if (unlikely(available < outstanding)) {
- dbg_budg("out of data space: available %lld, outstanding %lld",
- available, outstanding);
- return -ENOSPC;
- }
-
- if (available - outstanding <= c->rp_size && !can_use_rp(c))
- return -ENOSPC;
-
- c->bi.min_idx_lebs = min_idx_lebs;
- return 0;
-}
-
-/**
- * calc_idx_growth - calculate approximate index growth from budgeting request.
- * @c: UBIFS file-system description object
- * @req: budgeting request
- *
- * For now we assume each new node adds one znode. But this is rather poor
- * approximation, though.
- */
-static int calc_idx_growth(const struct ubifs_info *c,
- const struct ubifs_budget_req *req)
-{
- int znodes;
-
- znodes = req->new_ino + (req->new_page << UBIFS_BLOCKS_PER_PAGE_SHIFT) +
- req->new_dent;
- return znodes * c->max_idx_node_sz;
-}
-
-/**
- * calc_data_growth - calculate approximate amount of new data from budgeting
- * request.
- * @c: UBIFS file-system description object
- * @req: budgeting request
- */
-static int calc_data_growth(const struct ubifs_info *c,
- const struct ubifs_budget_req *req)
-{
- int data_growth;
-
- data_growth = req->new_ino ? c->bi.inode_budget : 0;
- if (req->new_page)
- data_growth += c->bi.page_budget;
- if (req->new_dent)
- data_growth += c->bi.dent_budget;
- data_growth += req->new_ino_d;
- return data_growth;
-}
-
-/**
- * calc_dd_growth - calculate approximate amount of data which makes other data
- * dirty from budgeting request.
- * @c: UBIFS file-system description object
- * @req: budgeting request
- */
-static int calc_dd_growth(const struct ubifs_info *c,
- const struct ubifs_budget_req *req)
-{
- int dd_growth;
-
- dd_growth = req->dirtied_page ? c->bi.page_budget : 0;
-
- if (req->dirtied_ino)
- dd_growth += c->bi.inode_budget << (req->dirtied_ino - 1);
- if (req->mod_dent)
- dd_growth += c->bi.dent_budget;
- dd_growth += req->dirtied_ino_d;
- return dd_growth;
-}
-
-/**
- * ubifs_budget_space - ensure there is enough space to complete an operation.
- * @c: UBIFS file-system description object
- * @req: budget request
- *
- * This function allocates budget for an operation. It uses pessimistic
- * approximation of how much flash space the operation needs. The goal of this
- * function is to make sure UBIFS always has flash space to flush all dirty
- * pages, dirty inodes, and dirty znodes (liability). This function may force
- * commit, garbage-collection or write-back. Returns zero in case of success,
- * %-ENOSPC if there is no free space and other negative error codes in case of
- * failures.
- */
-int ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req)
-{
- int err, idx_growth, data_growth, dd_growth, retried = 0;
-
- ubifs_assert(req->new_page <= 1);
- ubifs_assert(req->dirtied_page <= 1);
- ubifs_assert(req->new_dent <= 1);
- ubifs_assert(req->mod_dent <= 1);
- ubifs_assert(req->new_ino <= 1);
- ubifs_assert(req->new_ino_d <= UBIFS_MAX_INO_DATA);
- ubifs_assert(req->dirtied_ino <= 4);
- ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4);
- ubifs_assert(!(req->new_ino_d & 7));
- ubifs_assert(!(req->dirtied_ino_d & 7));
-
- data_growth = calc_data_growth(c, req);
- dd_growth = calc_dd_growth(c, req);
- if (!data_growth && !dd_growth)
- return 0;
- idx_growth = calc_idx_growth(c, req);
-
-again:
- spin_lock(&c->space_lock);
- ubifs_assert(c->bi.idx_growth >= 0);
- ubifs_assert(c->bi.data_growth >= 0);
- ubifs_assert(c->bi.dd_growth >= 0);
-
- if (unlikely(c->bi.nospace) && (c->bi.nospace_rp || !can_use_rp(c))) {
- dbg_budg("no space");
- spin_unlock(&c->space_lock);
- return -ENOSPC;
- }
-
- c->bi.idx_growth += idx_growth;
- c->bi.data_growth += data_growth;
- c->bi.dd_growth += dd_growth;
-
- err = do_budget_space(c);
- if (likely(!err)) {
- req->idx_growth = idx_growth;
- req->data_growth = data_growth;
- req->dd_growth = dd_growth;
- spin_unlock(&c->space_lock);
- return 0;
- }
-
- /* Restore the old values */
- c->bi.idx_growth -= idx_growth;
- c->bi.data_growth -= data_growth;
- c->bi.dd_growth -= dd_growth;
- spin_unlock(&c->space_lock);
-
- if (req->fast) {
- dbg_budg("no space for fast budgeting");
- return err;
- }
-
- err = make_free_space(c);
- cond_resched();
- if (err == -EAGAIN) {
- dbg_budg("try again");
- goto again;
- } else if (err == -ENOSPC) {
- if (!retried) {
- retried = 1;
- dbg_budg("-ENOSPC, but anyway try once again");
- goto again;
- }
- dbg_budg("FS is full, -ENOSPC");
- c->bi.nospace = 1;
- if (can_use_rp(c) || c->rp_size == 0)
- c->bi.nospace_rp = 1;
- smp_wmb();
- } else
- ubifs_err(c, "cannot budget space, error %d", err);
- return err;
-}
-
-/**
- * ubifs_release_budget - release budgeted free space.
- * @c: UBIFS file-system description object
- * @req: budget request
- *
- * This function releases the space budgeted by 'ubifs_budget_space()'. Note,
- * since the index changes (which were budgeted for in @req->idx_growth) will
- * only be written to the media on commit, this function moves the index budget
- * from @c->bi.idx_growth to @c->bi.uncommitted_idx. The latter will be zeroed
- * by the commit operation.
- */
-void ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req)
-{
- ubifs_assert(req->new_page <= 1);
- ubifs_assert(req->dirtied_page <= 1);
- ubifs_assert(req->new_dent <= 1);
- ubifs_assert(req->mod_dent <= 1);
- ubifs_assert(req->new_ino <= 1);
- ubifs_assert(req->new_ino_d <= UBIFS_MAX_INO_DATA);
- ubifs_assert(req->dirtied_ino <= 4);
- ubifs_assert(req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4);
- ubifs_assert(!(req->new_ino_d & 7));
- ubifs_assert(!(req->dirtied_ino_d & 7));
- if (!req->recalculate) {
- ubifs_assert(req->idx_growth >= 0);
- ubifs_assert(req->data_growth >= 0);
- ubifs_assert(req->dd_growth >= 0);
- }
-
- if (req->recalculate) {
- req->data_growth = calc_data_growth(c, req);
- req->dd_growth = calc_dd_growth(c, req);
- req->idx_growth = calc_idx_growth(c, req);
- }
-
- if (!req->data_growth && !req->dd_growth)
- return;
-
- c->bi.nospace = c->bi.nospace_rp = 0;
- smp_wmb();
-
- spin_lock(&c->space_lock);
- c->bi.idx_growth -= req->idx_growth;
- c->bi.uncommitted_idx += req->idx_growth;
- c->bi.data_growth -= req->data_growth;
- c->bi.dd_growth -= req->dd_growth;
- c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
-
- ubifs_assert(c->bi.idx_growth >= 0);
- ubifs_assert(c->bi.data_growth >= 0);
- ubifs_assert(c->bi.dd_growth >= 0);
- ubifs_assert(c->bi.min_idx_lebs < c->main_lebs);
- ubifs_assert(!(c->bi.idx_growth & 7));
- ubifs_assert(!(c->bi.data_growth & 7));
- ubifs_assert(!(c->bi.dd_growth & 7));
- spin_unlock(&c->space_lock);
-}
-
-/**
- * ubifs_convert_page_budget - convert budget of a new page.
- * @c: UBIFS file-system description object
- *
- * This function converts budget which was allocated for a new page of data to
- * the budget of changing an existing page of data. The latter is smaller than
- * the former, so this function only does simple re-calculation and does not
- * involve any write-back.
- */
-void ubifs_convert_page_budget(struct ubifs_info *c)
-{
- spin_lock(&c->space_lock);
- /* Release the index growth reservation */
- c->bi.idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT;
- /* Release the data growth reservation */
- c->bi.data_growth -= c->bi.page_budget;
- /* Increase the dirty data growth reservation instead */
- c->bi.dd_growth += c->bi.page_budget;
- /* And re-calculate the indexing space reservation */
- c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
- spin_unlock(&c->space_lock);
-}
-
-/**
- * ubifs_release_dirty_inode_budget - release dirty inode budget.
- * @c: UBIFS file-system description object
- * @ui: UBIFS inode to release the budget for
- *
- * This function releases budget corresponding to a dirty inode. It is usually
- * called when after the inode has been written to the media and marked as
- * clean. It also causes the "no space" flags to be cleared.
- */
-void ubifs_release_dirty_inode_budget(struct ubifs_info *c,
- struct ubifs_inode *ui)
-{
- struct ubifs_budget_req req;
-
- memset(&req, 0, sizeof(struct ubifs_budget_req));
- /* The "no space" flags will be cleared because dd_growth is > 0 */
- req.dd_growth = c->bi.inode_budget + ALIGN(ui->data_len, 8);
- ubifs_release_budget(c, &req);
-}
-#endif
-
-/**
- * ubifs_reported_space - calculate reported free space.
- * @c: the UBIFS file-system description object
- * @free: amount of free space
- *
- * This function calculates amount of free space which will be reported to
- * user-space. User-space application tend to expect that if the file-system
- * (e.g., via the 'statfs()' call) reports that it has N bytes available, they
- * are able to write a file of size N. UBIFS attaches node headers to each data
- * node and it has to write indexing nodes as well. This introduces additional
- * overhead, and UBIFS has to report slightly less free space to meet the above
- * expectations.
- *
- * This function assumes free space is made up of uncompressed data nodes and
- * full index nodes (one per data node, tripled because we always allow enough
- * space to write the index thrice).
- *
- * Note, the calculation is pessimistic, which means that most of the time
- * UBIFS reports less space than it actually has.
- */
-long long ubifs_reported_space(const struct ubifs_info *c, long long free)
-{
- int divisor, factor, f;
-
- /*
- * Reported space size is @free * X, where X is UBIFS block size
- * divided by UBIFS block size + all overhead one data block
- * introduces. The overhead is the node header + indexing overhead.
- *
- * Indexing overhead calculations are based on the following formula:
- * I = N/(f - 1) + 1, where I - number of indexing nodes, N - number
- * of data nodes, f - fanout. Because effective UBIFS fanout is twice
- * as less than maximum fanout, we assume that each data node
- * introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes.
- * Note, the multiplier 3 is because UBIFS reserves thrice as more space
- * for the index.
- */
- f = c->fanout > 3 ? c->fanout >> 1 : 2;
- factor = UBIFS_BLOCK_SIZE;
- divisor = UBIFS_MAX_DATA_NODE_SZ;
- divisor += (c->max_idx_node_sz * 3) / (f - 1);
- free *= factor;
- return div_u64(free, divisor);
-}
-
-#ifndef __BAREBOX__
-/**
- * ubifs_get_free_space_nolock - return amount of free space.
- * @c: UBIFS file-system description object
- *
- * This function calculates amount of free space to report to user-space.
- *
- * Because UBIFS may introduce substantial overhead (the index, node headers,
- * alignment, wastage at the end of LEBs, etc), it cannot report real amount of
- * free flash space it has (well, because not all dirty space is reclaimable,
- * UBIFS does not actually know the real amount). If UBIFS did so, it would
- * bread user expectations about what free space is. Users seem to accustomed
- * to assume that if the file-system reports N bytes of free space, they would
- * be able to fit a file of N bytes to the FS. This almost works for
- * traditional file-systems, because they have way less overhead than UBIFS.
- * So, to keep users happy, UBIFS tries to take the overhead into account.
- */
-long long ubifs_get_free_space_nolock(struct ubifs_info *c)
-{
- int rsvd_idx_lebs, lebs;
- long long available, outstanding, free;
-
- ubifs_assert(c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
- outstanding = c->bi.data_growth + c->bi.dd_growth;
- available = ubifs_calc_available(c, c->bi.min_idx_lebs);
-
- /*
- * When reporting free space to user-space, UBIFS guarantees that it is
- * possible to write a file of free space size. This means that for
- * empty LEBs we may use more precise calculations than
- * 'ubifs_calc_available()' is using. Namely, we know that in empty
- * LEBs we would waste only @c->leb_overhead bytes, not @c->dark_wm.
- * Thus, amend the available space.
- *
- * Note, the calculations below are similar to what we have in
- * 'do_budget_space()', so refer there for comments.
- */
- if (c->bi.min_idx_lebs > c->lst.idx_lebs)
- rsvd_idx_lebs = c->bi.min_idx_lebs - c->lst.idx_lebs;
- else
- rsvd_idx_lebs = 0;
- lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt -
- c->lst.taken_empty_lebs;
- lebs -= rsvd_idx_lebs;
- available += lebs * (c->dark_wm - c->leb_overhead);
-
- if (available > outstanding)
- free = ubifs_reported_space(c, available - outstanding);
- else
- free = 0;
- return free;
-}
-
-/**
- * ubifs_get_free_space - return amount of free space.
- * @c: UBIFS file-system description object
- *
- * This function calculates and returns amount of free space to report to
- * user-space.
- */
-long long ubifs_get_free_space(struct ubifs_info *c)
-{
- long long free;
-
- spin_lock(&c->space_lock);
- free = ubifs_get_free_space_nolock(c);
- spin_unlock(&c->space_lock);
-
- return free;
-}
-#endif
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 83125577fd..3077339773 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -16,20 +16,9 @@
* various local functions of those subsystems.
*/
-#ifndef __BAREBOX__
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/math64.h>
-#include <linux/uaccess.h>
-#include <linux/random.h>
-#else
#include <linux/err.h>
-#endif
#include "ubifs.h"
-#ifndef __BAREBOX__
-static DEFINE_SPINLOCK(dbg_lock);
-#endif
static const char *get_key_fmt(int fmt)
{
@@ -71,29 +60,6 @@ static const char *get_key_type(int type)
}
}
-#ifndef __BAREBOX__
-static const char *get_dent_type(int type)
-{
- switch (type) {
- case UBIFS_ITYPE_REG:
- return "file";
- case UBIFS_ITYPE_DIR:
- return "dir";
- case UBIFS_ITYPE_LNK:
- return "symlink";
- case UBIFS_ITYPE_BLK:
- return "blkdev";
- case UBIFS_ITYPE_CHR:
- return "char dev";
- case UBIFS_ITYPE_FIFO:
- return "fifo";
- case UBIFS_ITYPE_SOCK:
- return "socket";
- default:
- return "unknown/invalid type";
- }
-}
-#endif
const char *dbg_snprintf_key(const struct ubifs_info *c,
const union ubifs_key *key, char *buffer, int len)
@@ -229,72 +195,6 @@ static void dump_ch(const struct ubifs_ch *ch)
void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
{
-#ifndef __BAREBOX__
- const struct ubifs_inode *ui = ubifs_inode(inode);
- struct qstr nm = { .name = NULL };
- union ubifs_key key;
- struct ubifs_dent_node *dent, *pdent = NULL;
- int count = 2;
-
- pr_err("Dump in-memory inode:");
- pr_err("\tinode %lu\n", inode->i_ino);
- pr_err("\tsize %llu\n",
- (unsigned long long)i_size_read(inode));
- pr_err("\tnlink %u\n", inode->i_nlink);
- pr_err("\tuid %u\n", (unsigned int)i_uid_read(inode));
- pr_err("\tgid %u\n", (unsigned int)i_gid_read(inode));
- pr_err("\tatime %u.%u\n",
- (unsigned int)inode->i_atime.tv_sec,
- (unsigned int)inode->i_atime.tv_nsec);
- pr_err("\tmtime %u.%u\n",
- (unsigned int)inode->i_mtime.tv_sec,
- (unsigned int)inode->i_mtime.tv_nsec);
- pr_err("\tctime %u.%u\n",
- (unsigned int)inode->i_ctime.tv_sec,
- (unsigned int)inode->i_ctime.tv_nsec);
- pr_err("\tcreat_sqnum %llu\n", ui->creat_sqnum);
- pr_err("\txattr_size %u\n", ui->xattr_size);
- pr_err("\txattr_cnt %u\n", ui->xattr_cnt);
- pr_err("\txattr_names %u\n", ui->xattr_names);
- pr_err("\tdirty %u\n", ui->dirty);
- pr_err("\txattr %u\n", ui->xattr);
- pr_err("\tbulk_read %u\n", ui->xattr);
- pr_err("\tsynced_i_size %llu\n",
- (unsigned long long)ui->synced_i_size);
- pr_err("\tui_size %llu\n",
- (unsigned long long)ui->ui_size);
- pr_err("\tflags %d\n", ui->flags);
- pr_err("\tcompr_type %d\n", ui->compr_type);
- pr_err("\tlast_page_read %lu\n", ui->last_page_read);
- pr_err("\tread_in_a_row %lu\n", ui->read_in_a_row);
- pr_err("\tdata_len %d\n", ui->data_len);
-
- if (!S_ISDIR(inode->i_mode))
- return;
-
- pr_err("List of directory entries:\n");
- ubifs_assert(!mutex_is_locked(&c->tnc_mutex));
-
- lowest_dent_key(c, &key, inode->i_ino);
- while (1) {
- dent = ubifs_tnc_next_ent(c, &key, &nm);
- if (IS_ERR(dent)) {
- if (PTR_ERR(dent) != -ENOENT)
- pr_err("error %ld\n", PTR_ERR(dent));
- break;
- }
-
- pr_err("\t%d: %s (%s)\n",
- count++, dent->name, get_dent_type(dent->type));
-
- nm.name = dent->name;
- nm.len = le16_to_cpu(dent->nlen);
- kfree(pdent);
- pdent = dent;
- key_read(c, &dent->key, &key);
- }
- kfree(pdent);
-#endif
}
void ubifs_dump_node(const struct ubifs_info *c, const void *node)
@@ -544,259 +444,9 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node)
spin_unlock(&dbg_lock);
}
-void ubifs_dump_budget_req(const struct ubifs_budget_req *req)
-{
- spin_lock(&dbg_lock);
- pr_err("Budgeting request: new_ino %d, dirtied_ino %d\n",
- req->new_ino, req->dirtied_ino);
- pr_err("\tnew_ino_d %d, dirtied_ino_d %d\n",
- req->new_ino_d, req->dirtied_ino_d);
- pr_err("\tnew_page %d, dirtied_page %d\n",
- req->new_page, req->dirtied_page);
- pr_err("\tnew_dent %d, mod_dent %d\n",
- req->new_dent, req->mod_dent);
- pr_err("\tidx_growth %d\n", req->idx_growth);
- pr_err("\tdata_growth %d dd_growth %d\n",
- req->data_growth, req->dd_growth);
- spin_unlock(&dbg_lock);
-}
-
-void ubifs_dump_lstats(const struct ubifs_lp_stats *lst)
-{
- spin_lock(&dbg_lock);
- pr_err("(pid %d) Lprops statistics: empty_lebs %d, idx_lebs %d\n",
- 0, lst->empty_lebs, lst->idx_lebs);
- pr_err("\ttaken_empty_lebs %d, total_free %lld, total_dirty %lld\n",
- lst->taken_empty_lebs, lst->total_free, lst->total_dirty);
- pr_err("\ttotal_used %lld, total_dark %lld, total_dead %lld\n",
- lst->total_used, lst->total_dark, lst->total_dead);
- spin_unlock(&dbg_lock);
-}
-
-#ifndef __BAREBOX__
-void ubifs_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
-{
- int i;
- struct rb_node *rb;
- struct ubifs_bud *bud;
- struct ubifs_gced_idx_leb *idx_gc;
- long long available, outstanding, free;
-
- spin_lock(&c->space_lock);
- spin_lock(&dbg_lock);
- pr_err("(pid %d) Budgeting info: data budget sum %lld, total budget sum %lld\n",
- 0, bi->data_growth + bi->dd_growth,
- bi->data_growth + bi->dd_growth + bi->idx_growth);
- pr_err("\tbudg_data_growth %lld, budg_dd_growth %lld, budg_idx_growth %lld\n",
- bi->data_growth, bi->dd_growth, bi->idx_growth);
- pr_err("\tmin_idx_lebs %d, old_idx_sz %llu, uncommitted_idx %lld\n",
- bi->min_idx_lebs, bi->old_idx_sz, bi->uncommitted_idx);
- pr_err("\tpage_budget %d, inode_budget %d, dent_budget %d\n",
- bi->page_budget, bi->inode_budget, bi->dent_budget);
- pr_err("\tnospace %u, nospace_rp %u\n", bi->nospace, bi->nospace_rp);
- pr_err("\tdark_wm %d, dead_wm %d, max_idx_node_sz %d\n",
- c->dark_wm, c->dead_wm, c->max_idx_node_sz);
-
- if (bi != &c->bi)
- /*
- * If we are dumping saved budgeting data, do not print
- * additional information which is about the current state, not
- * the old one which corresponded to the saved budgeting data.
- */
- goto out_unlock;
-
- pr_err("\tfreeable_cnt %d, calc_idx_sz %lld, idx_gc_cnt %d\n",
- c->freeable_cnt, c->calc_idx_sz, c->idx_gc_cnt);
- pr_err("\tdirty_pg_cnt %ld, dirty_zn_cnt %ld, clean_zn_cnt %ld\n",
- atomic_long_read(&c->dirty_pg_cnt),
- atomic_long_read(&c->dirty_zn_cnt),
- atomic_long_read(&c->clean_zn_cnt));
- pr_err("\tgc_lnum %d, ihead_lnum %d\n", c->gc_lnum, c->ihead_lnum);
-
- /* If we are in R/O mode, journal heads do not exist */
- if (c->jheads)
- for (i = 0; i < c->jhead_cnt; i++)
- pr_err("\tjhead %s\t LEB %d\n",
- dbg_jhead(c->jheads[i].wbuf.jhead),
- c->jheads[i].wbuf.lnum);
- for (rb = rb_first(&c->buds); rb; rb = rb_next(rb)) {
- bud = rb_entry(rb, struct ubifs_bud, rb);
- pr_err("\tbud LEB %d\n", bud->lnum);
- }
- list_for_each_entry(bud, &c->old_buds, list)
- pr_err("\told bud LEB %d\n", bud->lnum);
- list_for_each_entry(idx_gc, &c->idx_gc, list)
- pr_err("\tGC'ed idx LEB %d unmap %d\n",
- idx_gc->lnum, idx_gc->unmap);
- pr_err("\tcommit state %d\n", c->cmt_state);
-
- /* Print budgeting predictions */
- available = ubifs_calc_available(c, c->bi.min_idx_lebs);
- outstanding = c->bi.data_growth + c->bi.dd_growth;
- free = ubifs_get_free_space_nolock(c);
- pr_err("Budgeting predictions:\n");
- pr_err("\tavailable: %lld, outstanding %lld, free %lld\n",
- available, outstanding, free);
-out_unlock:
- spin_unlock(&dbg_lock);
- spin_unlock(&c->space_lock);
-}
-#else
void ubifs_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
{
}
-#endif
-
-void ubifs_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
-{
- int i, spc, dark = 0, dead = 0;
- struct rb_node *rb;
- struct ubifs_bud *bud;
-
- spc = lp->free + lp->dirty;
- if (spc < c->dead_wm)
- dead = spc;
- else
- dark = ubifs_calc_dark(c, spc);
-
- if (lp->flags & LPROPS_INDEX)
- pr_err("LEB %-7d free %-8d dirty %-8d used %-8d free + dirty %-8d flags %#x (",
- lp->lnum, lp->free, lp->dirty, c->leb_size - spc, spc,
- lp->flags);
- else
- pr_err("LEB %-7d free %-8d dirty %-8d used %-8d free + dirty %-8d dark %-4d dead %-4d nodes fit %-3d flags %#-4x (",
- lp->lnum, lp->free, lp->dirty, c->leb_size - spc, spc,
- dark, dead, (int)(spc / UBIFS_MAX_NODE_SZ), lp->flags);
-
- if (lp->flags & LPROPS_TAKEN) {
- if (lp->flags & LPROPS_INDEX)
- pr_cont("index, taken");
- else
- pr_cont("taken");
- } else {
- const char *s;
-
- if (lp->flags & LPROPS_INDEX) {
- switch (lp->flags & LPROPS_CAT_MASK) {
- case LPROPS_DIRTY_IDX:
- s = "dirty index";
- break;
- case LPROPS_FRDI_IDX:
- s = "freeable index";
- break;
- default:
- s = "index";
- }
- } else {
- switch (lp->flags & LPROPS_CAT_MASK) {
- case LPROPS_UNCAT:
- s = "not categorized";
- break;
- case LPROPS_DIRTY:
- s = "dirty";
- break;
- case LPROPS_FREE:
- s = "free";
- break;
- case LPROPS_EMPTY:
- s = "empty";
- break;
- case LPROPS_FREEABLE:
- s = "freeable";
- break;
- default:
- s = NULL;
- break;
- }
- }
- pr_cont("%s", s);
- }
-
- for (rb = rb_first((struct rb_root *)&c->buds); rb; rb = rb_next(rb)) {
- bud = rb_entry(rb, struct ubifs_bud, rb);
- if (bud->lnum == lp->lnum) {
- int head = 0;
- for (i = 0; i < c->jhead_cnt; i++) {
- /*
- * Note, if we are in R/O mode or in the middle
- * of mounting/re-mounting, the write-buffers do
- * not exist.
- */
- if (c->jheads &&
- lp->lnum == c->jheads[i].wbuf.lnum) {
- pr_cont(", jhead %s", dbg_jhead(i));
- head = 1;
- }
- }
- if (!head)
- pr_cont(", bud of jhead %s",
- dbg_jhead(bud->jhead));
- }
- }
- if (lp->lnum == c->gc_lnum)
- pr_cont(", GC LEB");
- pr_cont(")\n");
-}
-
-void ubifs_dump_lprops(struct ubifs_info *c)
-{
- int lnum, err;
- struct ubifs_lprops lp;
- struct ubifs_lp_stats lst;
-
- pr_err("(pid %d) start dumping LEB properties\n", 0);
- ubifs_get_lp_stats(c, &lst);
- ubifs_dump_lstats(&lst);
-
- for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
- err = ubifs_read_one_lp(c, lnum, &lp);
- if (err) {
- ubifs_err(c, "cannot read lprops for LEB %d", lnum);
- continue;
- }
-
- ubifs_dump_lprop(c, &lp);
- }
- pr_err("(pid %d) finish dumping LEB properties\n", 0);
-}
-
-void ubifs_dump_lpt_info(struct ubifs_info *c)
-{
- int i;
-
- spin_lock(&dbg_lock);
- pr_err("(pid %d) dumping LPT information\n", 0);
- pr_err("\tlpt_sz: %lld\n", c->lpt_sz);
- pr_err("\tpnode_sz: %d\n", c->pnode_sz);
- pr_err("\tnnode_sz: %d\n", c->nnode_sz);
- pr_err("\tltab_sz: %d\n", c->ltab_sz);
- pr_err("\tlsave_sz: %d\n", c->lsave_sz);
- pr_err("\tbig_lpt: %d\n", c->big_lpt);
- pr_err("\tlpt_hght: %d\n", c->lpt_hght);
- pr_err("\tpnode_cnt: %d\n", c->pnode_cnt);
- pr_err("\tnnode_cnt: %d\n", c->nnode_cnt);
- pr_err("\tdirty_pn_cnt: %d\n", c->dirty_pn_cnt);
- pr_err("\tdirty_nn_cnt: %d\n", c->dirty_nn_cnt);
- pr_err("\tlsave_cnt: %d\n", c->lsave_cnt);
- pr_err("\tspace_bits: %d\n", c->space_bits);
- pr_err("\tlpt_lnum_bits: %d\n", c->lpt_lnum_bits);
- pr_err("\tlpt_offs_bits: %d\n", c->lpt_offs_bits);
- pr_err("\tlpt_spc_bits: %d\n", c->lpt_spc_bits);
- pr_err("\tpcnt_bits: %d\n", c->pcnt_bits);
- pr_err("\tlnum_bits: %d\n", c->lnum_bits);
- pr_err("\tLPT root is at %d:%d\n", c->lpt_lnum, c->lpt_offs);
- pr_err("\tLPT head is at %d:%d\n",
- c->nhead_lnum, c->nhead_offs);
- pr_err("\tLPT ltab is at %d:%d\n", c->ltab_lnum, c->ltab_offs);
- if (c->big_lpt)
- pr_err("\tLPT lsave is at %d:%d\n",
- c->lsave_lnum, c->lsave_offs);
- for (i = 0; i < c->lpt_lebs; i++)
- pr_err("\tLPT LEB %d free %d dirty %d tgc %d cmt %d\n",
- i + c->lpt_first, c->ltab[i].free, c->ltab[i].dirty,
- c->ltab[i].tgc, c->ltab[i].cmt);
- spin_unlock(&dbg_lock);
-}
void ubifs_dump_sleb(const struct ubifs_info *c,
const struct ubifs_scan_leb *sleb, int offs)
@@ -891,40 +541,6 @@ void ubifs_dump_znode(const struct ubifs_info *c,
spin_unlock(&dbg_lock);
}
-void ubifs_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
-{
- int i;
-
- pr_err("(pid %d) start dumping heap cat %d (%d elements)\n",
- 0, cat, heap->cnt);
- for (i = 0; i < heap->cnt; i++) {
- struct ubifs_lprops *lprops = heap->arr[i];
-
- pr_err("\t%d. LEB %d hpos %d free %d dirty %d flags %d\n",
- i, lprops->lnum, lprops->hpos, lprops->free,
- lprops->dirty, lprops->flags);
- }
- pr_err("(pid %d) finish dumping heap\n", 0);
-}
-
-void ubifs_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
- struct ubifs_nnode *parent, int iip)
-{
- int i;
-
- pr_err("(pid %d) dumping pnode:\n", 0);
- pr_err("\taddress %zx parent %zx cnext %zx\n",
- (size_t)pnode, (size_t)parent, (size_t)pnode->cnext);
- pr_err("\tflags %lu iip %d level %d num %d\n",
- pnode->flags, iip, pnode->level, pnode->num);
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- struct ubifs_lprops *lp = &pnode->lprops[i];
-
- pr_err("\t%d: free %d dirty %d flags %d lnum %d\n",
- i, lp->free, lp->dirty, lp->flags, lp->lnum);
- }
-}
-
void ubifs_dump_tnc(struct ubifs_info *c)
{
struct ubifs_znode *znode;
@@ -965,505 +581,6 @@ void ubifs_dump_index(struct ubifs_info *c)
dbg_walk_index(c, NULL, dump_znode, NULL);
}
-#ifndef __BAREBOX__
-/**
- * dbg_save_space_info - save information about flash space.
- * @c: UBIFS file-system description object
- *
- * This function saves information about UBIFS free space, dirty space, etc, in
- * order to check it later.
- */
-void dbg_save_space_info(struct ubifs_info *c)
-{
- struct ubifs_debug_info *d = c->dbg;
- int freeable_cnt;
-
- spin_lock(&c->space_lock);
- memcpy(&d->saved_lst, &c->lst, sizeof(struct ubifs_lp_stats));
- memcpy(&d->saved_bi, &c->bi, sizeof(struct ubifs_budg_info));
- d->saved_idx_gc_cnt = c->idx_gc_cnt;
-
- /*
- * We use a dirty hack here and zero out @c->freeable_cnt, because it
- * affects the free space calculations, and UBIFS might not know about
- * all freeable eraseblocks. Indeed, we know about freeable eraseblocks
- * only when we read their lprops, and we do this only lazily, upon the
- * need. So at any given point of time @c->freeable_cnt might be not
- * exactly accurate.
- *
- * Just one example about the issue we hit when we did not zero
- * @c->freeable_cnt.
- * 1. The file-system is mounted R/O, c->freeable_cnt is %0. We save the
- * amount of free space in @d->saved_free
- * 2. We re-mount R/W, which makes UBIFS to read the "lsave"
- * information from flash, where we cache LEBs from various
- * categories ('ubifs_remount_fs()' -> 'ubifs_lpt_init()'
- * -> 'lpt_init_wr()' -> 'read_lsave()' -> 'ubifs_lpt_lookup()'
- * -> 'ubifs_get_pnode()' -> 'update_cats()'
- * -> 'ubifs_add_to_cat()').
- * 3. Lsave contains a freeable eraseblock, and @c->freeable_cnt
- * becomes %1.
- * 4. We calculate the amount of free space when the re-mount is
- * finished in 'dbg_check_space_info()' and it does not match
- * @d->saved_free.
- */
- freeable_cnt = c->freeable_cnt;
- c->freeable_cnt = 0;
- d->saved_free = ubifs_get_free_space_nolock(c);
- c->freeable_cnt = freeable_cnt;
- spin_unlock(&c->space_lock);
-}
-
-/**
- * dbg_check_space_info - check flash space information.
- * @c: UBIFS file-system description object
- *
- * This function compares current flash space information with the information
- * which was saved when the 'dbg_save_space_info()' function was called.
- * Returns zero if the information has not changed, and %-EINVAL it it has
- * changed.
- */
-int dbg_check_space_info(struct ubifs_info *c)
-{
- struct ubifs_debug_info *d = c->dbg;
- struct ubifs_lp_stats lst;
- long long free;
- int freeable_cnt;
-
- spin_lock(&c->space_lock);
- freeable_cnt = c->freeable_cnt;
- c->freeable_cnt = 0;
- free = ubifs_get_free_space_nolock(c);
- c->freeable_cnt = freeable_cnt;
- spin_unlock(&c->space_lock);
-
- if (free != d->saved_free) {
- ubifs_err(c, "free space changed from %lld to %lld",
- d->saved_free, free);
- goto out;
- }
-
- return 0;
-
-out:
- ubifs_msg(c, "saved lprops statistics dump");
- ubifs_dump_lstats(&d->saved_lst);
- ubifs_msg(c, "saved budgeting info dump");
- ubifs_dump_budg(c, &d->saved_bi);
- ubifs_msg(c, "saved idx_gc_cnt %d", d->saved_idx_gc_cnt);
- ubifs_msg(c, "current lprops statistics dump");
- ubifs_get_lp_stats(c, &lst);
- ubifs_dump_lstats(&lst);
- ubifs_msg(c, "current budgeting info dump");
- ubifs_dump_budg(c, &c->bi);
- dump_stack();
- return -EINVAL;
-}
-
-/**
- * dbg_check_synced_i_size - check synchronized inode size.
- * @c: UBIFS file-system description object
- * @inode: inode to check
- *
- * If inode is clean, synchronized inode size has to be equivalent to current
- * inode size. This function has to be called only for locked inodes (@i_mutex
- * has to be locked). Returns %0 if synchronized inode size if correct, and
- * %-EINVAL if not.
- */
-int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode)
-{
- int err = 0;
- struct ubifs_inode *ui = ubifs_inode(inode);
-
- if (!dbg_is_chk_gen(c))
- return 0;
- if (!S_ISREG(inode->i_mode))
- return 0;
-
- mutex_lock(&ui->ui_mutex);
- spin_lock(&ui->ui_lock);
- if (ui->ui_size != ui->synced_i_size && !ui->dirty) {
- ubifs_err(c, "ui_size is %lld, synced_i_size is %lld, but inode is clean",
- ui->ui_size, ui->synced_i_size);
- ubifs_err(c, "i_ino %lu, i_mode %#x, i_size %lld", inode->i_ino,
- inode->i_mode, i_size_read(inode));
- dump_stack();
- err = -EINVAL;
- }
- spin_unlock(&ui->ui_lock);
- mutex_unlock(&ui->ui_mutex);
- return err;
-}
-
-/*
- * dbg_check_dir - check directory inode size and link count.
- * @c: UBIFS file-system description object
- * @dir: the directory to calculate size for
- * @size: the result is returned here
- *
- * This function makes sure that directory size and link count are correct.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- *
- * Note, it is good idea to make sure the @dir->i_mutex is locked before
- * calling this function.
- */
-int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
-{
- unsigned int nlink = 2;
- union ubifs_key key;
- struct ubifs_dent_node *dent, *pdent = NULL;
- struct qstr nm = { .name = NULL };
- loff_t size = UBIFS_INO_NODE_SZ;
-
- if (!dbg_is_chk_gen(c))
- return 0;
-
- if (!S_ISDIR(dir->i_mode))
- return 0;
-
- lowest_dent_key(c, &key, dir->i_ino);
- while (1) {
- int err;
-
- dent = ubifs_tnc_next_ent(c, &key, &nm);
- if (IS_ERR(dent)) {
- err = PTR_ERR(dent);
- if (err == -ENOENT)
- break;
- return err;
- }
-
- nm.name = dent->name;
- nm.len = le16_to_cpu(dent->nlen);
- size += CALC_DENT_SIZE(nm.len);
- if (dent->type == UBIFS_ITYPE_DIR)
- nlink += 1;
- kfree(pdent);
- pdent = dent;
- key_read(c, &dent->key, &key);
- }
- kfree(pdent);
-
- if (i_size_read(dir) != size) {
- ubifs_err(c, "directory inode %lu has size %llu, but calculated size is %llu",
- dir->i_ino, (unsigned long long)i_size_read(dir),
- (unsigned long long)size);
- ubifs_dump_inode(c, dir);
- dump_stack();
- return -EINVAL;
- }
- if (dir->i_nlink != nlink) {
- ubifs_err(c, "directory inode %lu has nlink %u, but calculated nlink is %u",
- dir->i_ino, dir->i_nlink, nlink);
- ubifs_dump_inode(c, dir);
- dump_stack();
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * dbg_check_key_order - make sure that colliding keys are properly ordered.
- * @c: UBIFS file-system description object
- * @zbr1: first zbranch
- * @zbr2: following zbranch
- *
- * In UBIFS indexing B-tree colliding keys has to be sorted in binary order of
- * names of the direntries/xentries which are referred by the keys. This
- * function reads direntries/xentries referred by @zbr1 and @zbr2 and makes
- * sure the name of direntry/xentry referred by @zbr1 is less than
- * direntry/xentry referred by @zbr2. Returns zero if this is true, %1 if not,
- * and a negative error code in case of failure.
- */
-static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
- struct ubifs_zbranch *zbr2)
-{
- int err, nlen1, nlen2, cmp;
- struct ubifs_dent_node *dent1, *dent2;
- union ubifs_key key;
- char key_buf[DBG_KEY_BUF_LEN];
-
- ubifs_assert(!keys_cmp(c, &zbr1->key, &zbr2->key));
- dent1 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
- if (!dent1)
- return -ENOMEM;
- dent2 = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
- if (!dent2) {
- err = -ENOMEM;
- goto out_free;
- }
-
- err = ubifs_tnc_read_node(c, zbr1, dent1);
- if (err)
- goto out_free;
- err = ubifs_validate_entry(c, dent1);
- if (err)
- goto out_free;
-
- err = ubifs_tnc_read_node(c, zbr2, dent2);
- if (err)
- goto out_free;
- err = ubifs_validate_entry(c, dent2);
- if (err)
- goto out_free;
-
- /* Make sure node keys are the same as in zbranch */
- err = 1;
- key_read(c, &dent1->key, &key);
- if (keys_cmp(c, &zbr1->key, &key)) {
- ubifs_err(c, "1st entry at %d:%d has key %s", zbr1->lnum,
- zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
- DBG_KEY_BUF_LEN));
- ubifs_err(c, "but it should have key %s according to tnc",
- dbg_snprintf_key(c, &zbr1->key, key_buf,
- DBG_KEY_BUF_LEN));
- ubifs_dump_node(c, dent1);
- goto out_free;
- }
-
- key_read(c, &dent2->key, &key);
- if (keys_cmp(c, &zbr2->key, &key)) {
- ubifs_err(c, "2nd entry at %d:%d has key %s", zbr1->lnum,
- zbr1->offs, dbg_snprintf_key(c, &key, key_buf,
- DBG_KEY_BUF_LEN));
- ubifs_err(c, "but it should have key %s according to tnc",
- dbg_snprintf_key(c, &zbr2->key, key_buf,
- DBG_KEY_BUF_LEN));
- ubifs_dump_node(c, dent2);
- goto out_free;
- }
-
- nlen1 = le16_to_cpu(dent1->nlen);
- nlen2 = le16_to_cpu(dent2->nlen);
-
- cmp = memcmp(dent1->name, dent2->name, min_t(int, nlen1, nlen2));
- if (cmp < 0 || (cmp == 0 && nlen1 < nlen2)) {
- err = 0;
- goto out_free;
- }
- if (cmp == 0 && nlen1 == nlen2)
- ubifs_err(c, "2 xent/dent nodes with the same name");
- else
- ubifs_err(c, "bad order of colliding key %s",
- dbg_snprintf_key(c, &key, key_buf, DBG_KEY_BUF_LEN));
-
- ubifs_msg(c, "first node at %d:%d\n", zbr1->lnum, zbr1->offs);
- ubifs_dump_node(c, dent1);
- ubifs_msg(c, "second node at %d:%d\n", zbr2->lnum, zbr2->offs);
- ubifs_dump_node(c, dent2);
-
-out_free:
- kfree(dent2);
- kfree(dent1);
- return err;
-}
-
-/**
- * dbg_check_znode - check if znode is all right.
- * @c: UBIFS file-system description object
- * @zbr: zbranch which points to this znode
- *
- * This function makes sure that znode referred to by @zbr is all right.
- * Returns zero if it is, and %-EINVAL if it is not.
- */
-static int dbg_check_znode(struct ubifs_info *c, struct ubifs_zbranch *zbr)
-{
- struct ubifs_znode *znode = zbr->znode;
- struct ubifs_znode *zp = znode->parent;
- int n, err, cmp;
-
- if (znode->child_cnt <= 0 || znode->child_cnt > c->fanout) {
- err = 1;
- goto out;
- }
- if (znode->level < 0) {
- err = 2;
- goto out;
- }
- if (znode->iip < 0 || znode->iip >= c->fanout) {
- err = 3;
- goto out;
- }
-
- if (zbr->len == 0)
- /* Only dirty zbranch may have no on-flash nodes */
- if (!ubifs_zn_dirty(znode)) {
- err = 4;
- goto out;
- }
-
- if (ubifs_zn_dirty(znode)) {
- /*
- * If znode is dirty, its parent has to be dirty as well. The
- * order of the operation is important, so we have to have
- * memory barriers.
- */
- smp_mb();
- if (zp && !ubifs_zn_dirty(zp)) {
- /*
- * The dirty flag is atomic and is cleared outside the
- * TNC mutex, so znode's dirty flag may now have
- * been cleared. The child is always cleared before the
- * parent, so we just need to check again.
- */
- smp_mb();
- if (ubifs_zn_dirty(znode)) {
- err = 5;
- goto out;
- }
- }
- }
-
- if (zp) {
- const union ubifs_key *min, *max;
-
- if (znode->level != zp->level - 1) {
- err = 6;
- goto out;
- }
-
- /* Make sure the 'parent' pointer in our znode is correct */
- err = ubifs_search_zbranch(c, zp, &zbr->key, &n);
- if (!err) {
- /* This zbranch does not exist in the parent */
- err = 7;
- goto out;
- }
-
- if (znode->iip >= zp->child_cnt) {
- err = 8;
- goto out;
- }
-
- if (znode->iip != n) {
- /* This may happen only in case of collisions */
- if (keys_cmp(c, &zp->zbranch[n].key,
- &zp->zbranch[znode->iip].key)) {
- err = 9;
- goto out;
- }
- n = znode->iip;
- }
-
- /*
- * Make sure that the first key in our znode is greater than or
- * equal to the key in the pointing zbranch.
- */
- min = &zbr->key;
- cmp = keys_cmp(c, min, &znode->zbranch[0].key);
- if (cmp == 1) {
- err = 10;
- goto out;
- }
-
- if (n + 1 < zp->child_cnt) {
- max = &zp->zbranch[n + 1].key;
-
- /*
- * Make sure the last key in our znode is less or
- * equivalent than the key in the zbranch which goes
- * after our pointing zbranch.
- */
- cmp = keys_cmp(c, max,
- &znode->zbranch[znode->child_cnt - 1].key);
- if (cmp == -1) {
- err = 11;
- goto out;
- }
- }
- } else {
- /* This may only be root znode */
- if (zbr != &c->zroot) {
- err = 12;
- goto out;
- }
- }
-
- /*
- * Make sure that next key is greater or equivalent then the previous
- * one.
- */
- for (n = 1; n < znode->child_cnt; n++) {
- cmp = keys_cmp(c, &znode->zbranch[n - 1].key,
- &znode->zbranch[n].key);
- if (cmp > 0) {
- err = 13;
- goto out;
- }
- if (cmp == 0) {
- /* This can only be keys with colliding hash */
- if (!is_hash_key(c, &znode->zbranch[n].key)) {
- err = 14;
- goto out;
- }
-
- if (znode->level != 0 || c->replaying)
- continue;
-
- /*
- * Colliding keys should follow binary order of
- * corresponding xentry/dentry names.
- */
- err = dbg_check_key_order(c, &znode->zbranch[n - 1],
- &znode->zbranch[n]);
- if (err < 0)
- return err;
- if (err) {
- err = 15;
- goto out;
- }
- }
- }
-
- for (n = 0; n < znode->child_cnt; n++) {
- if (!znode->zbranch[n].znode &&
- (znode->zbranch[n].lnum == 0 ||
- znode->zbranch[n].len == 0)) {
- err = 16;
- goto out;
- }
-
- if (znode->zbranch[n].lnum != 0 &&
- znode->zbranch[n].len == 0) {
- err = 17;
- goto out;
- }
-
- if (znode->zbranch[n].lnum == 0 &&
- znode->zbranch[n].len != 0) {
- err = 18;
- goto out;
- }
-
- if (znode->zbranch[n].lnum == 0 &&
- znode->zbranch[n].offs != 0) {
- err = 19;
- goto out;
- }
-
- if (znode->level != 0 && znode->zbranch[n].znode)
- if (znode->zbranch[n].znode->parent != znode) {
- err = 20;
- goto out;
- }
- }
-
- return 0;
-
-out:
- ubifs_err(c, "failed, error %d", err);
- ubifs_msg(c, "dump of the znode");
- ubifs_dump_znode(c, znode);
- if (zp) {
- ubifs_msg(c, "dump of the parent znode");
- ubifs_dump_znode(c, zp);
- }
- dump_stack();
- return -EINVAL;
-}
-#else
int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
{
@@ -1490,1658 +607,8 @@ int dbg_debugfs_init_fs(struct ubifs_info *c)
{
return 0;
}
-#endif
-
-#ifndef __BAREBOX__
-/**
- * dbg_check_tnc - check TNC tree.
- * @c: UBIFS file-system description object
- * @extra: do extra checks that are possible at start commit
- *
- * This function traverses whole TNC tree and checks every znode. Returns zero
- * if everything is all right and %-EINVAL if something is wrong with TNC.
- */
-int dbg_check_tnc(struct ubifs_info *c, int extra)
-{
- struct ubifs_znode *znode;
- long clean_cnt = 0, dirty_cnt = 0;
- int err, last;
-
- if (!dbg_is_chk_index(c))
- return 0;
-
- ubifs_assert(mutex_is_locked(&c->tnc_mutex));
- if (!c->zroot.znode)
- return 0;
-
- znode = ubifs_tnc_postorder_first(c->zroot.znode);
- while (1) {
- struct ubifs_znode *prev;
- struct ubifs_zbranch *zbr;
-
- if (!znode->parent)
- zbr = &c->zroot;
- else
- zbr = &znode->parent->zbranch[znode->iip];
-
- err = dbg_check_znode(c, zbr);
- if (err)
- return err;
-
- if (extra) {
- if (ubifs_zn_dirty(znode))
- dirty_cnt += 1;
- else
- clean_cnt += 1;
- }
-
- prev = znode;
- znode = ubifs_tnc_postorder_next(znode);
- if (!znode)
- break;
-
- /*
- * If the last key of this znode is equivalent to the first key
- * of the next znode (collision), then check order of the keys.
- */
- last = prev->child_cnt - 1;
- if (prev->level == 0 && znode->level == 0 && !c->replaying &&
- !keys_cmp(c, &prev->zbranch[last].key,
- &znode->zbranch[0].key)) {
- err = dbg_check_key_order(c, &prev->zbranch[last],
- &znode->zbranch[0]);
- if (err < 0)
- return err;
- if (err) {
- ubifs_msg(c, "first znode");
- ubifs_dump_znode(c, prev);
- ubifs_msg(c, "second znode");
- ubifs_dump_znode(c, znode);
- return -EINVAL;
- }
- }
- }
-
- if (extra) {
- if (clean_cnt != atomic_long_read(&c->clean_zn_cnt)) {
- ubifs_err(c, "incorrect clean_zn_cnt %ld, calculated %ld",
- atomic_long_read(&c->clean_zn_cnt),
- clean_cnt);
- return -EINVAL;
- }
- if (dirty_cnt != atomic_long_read(&c->dirty_zn_cnt)) {
- ubifs_err(c, "incorrect dirty_zn_cnt %ld, calculated %ld",
- atomic_long_read(&c->dirty_zn_cnt),
- dirty_cnt);
- return -EINVAL;
- }
- }
- return 0;
-}
-#else
int dbg_check_tnc(struct ubifs_info *c, int extra)
{
return 0;
}
-#endif
-
-/**
- * dbg_walk_index - walk the on-flash index.
- * @c: UBIFS file-system description object
- * @leaf_cb: called for each leaf node
- * @znode_cb: called for each indexing node
- * @priv: private data which is passed to callbacks
- *
- * This function walks the UBIFS index and calls the @leaf_cb for each leaf
- * node and @znode_cb for each indexing node. Returns zero in case of success
- * and a negative error code in case of failure.
- *
- * It would be better if this function removed every znode it pulled to into
- * the TNC, so that the behavior more closely matched the non-debugging
- * behavior.
- */
-int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
- dbg_znode_callback znode_cb, void *priv)
-{
- int err;
- struct ubifs_zbranch *zbr;
- struct ubifs_znode *znode, *child;
-
- mutex_lock(&c->tnc_mutex);
- /* If the root indexing node is not in TNC - pull it */
- if (!c->zroot.znode) {
- c->zroot.znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
- if (IS_ERR(c->zroot.znode)) {
- err = PTR_ERR(c->zroot.znode);
- c->zroot.znode = NULL;
- goto out_unlock;
- }
- }
-
- /*
- * We are going to traverse the indexing tree in the postorder manner.
- * Go down and find the leftmost indexing node where we are going to
- * start from.
- */
- znode = c->zroot.znode;
- while (znode->level > 0) {
- zbr = &znode->zbranch[0];
- child = zbr->znode;
- if (!child) {
- child = ubifs_load_znode(c, zbr, znode, 0);
- if (IS_ERR(child)) {
- err = PTR_ERR(child);
- goto out_unlock;
- }
- zbr->znode = child;
- }
-
- znode = child;
- }
-
- /* Iterate over all indexing nodes */
- while (1) {
- int idx;
-
- cond_resched();
-
- if (znode_cb) {
- err = znode_cb(c, znode, priv);
- if (err) {
- ubifs_err(c, "znode checking function returned error %d",
- err);
- ubifs_dump_znode(c, znode);
- goto out_dump;
- }
- }
- if (leaf_cb && znode->level == 0) {
- for (idx = 0; idx < znode->child_cnt; idx++) {
- zbr = &znode->zbranch[idx];
- err = leaf_cb(c, zbr, priv);
- if (err) {
- ubifs_err(c, "leaf checking function returned error %d, for leaf at LEB %d:%d",
- err, zbr->lnum, zbr->offs);
- goto out_dump;
- }
- }
- }
-
- if (!znode->parent)
- break;
-
- idx = znode->iip + 1;
- znode = znode->parent;
- if (idx < znode->child_cnt) {
- /* Switch to the next index in the parent */
- zbr = &znode->zbranch[idx];
- child = zbr->znode;
- if (!child) {
- child = ubifs_load_znode(c, zbr, znode, idx);
- if (IS_ERR(child)) {
- err = PTR_ERR(child);
- goto out_unlock;
- }
- zbr->znode = child;
- }
- znode = child;
- } else
- /*
- * This is the last child, switch to the parent and
- * continue.
- */
- continue;
-
- /* Go to the lowest leftmost znode in the new sub-tree */
- while (znode->level > 0) {
- zbr = &znode->zbranch[0];
- child = zbr->znode;
- if (!child) {
- child = ubifs_load_znode(c, zbr, znode, 0);
- if (IS_ERR(child)) {
- err = PTR_ERR(child);
- goto out_unlock;
- }
- zbr->znode = child;
- }
- znode = child;
- }
- }
-
- mutex_unlock(&c->tnc_mutex);
- return 0;
-
-out_dump:
- if (znode->parent)
- zbr = &znode->parent->zbranch[znode->iip];
- else
- zbr = &c->zroot;
- ubifs_msg(c, "dump of znode at LEB %d:%d", zbr->lnum, zbr->offs);
- ubifs_dump_znode(c, znode);
-out_unlock:
- mutex_unlock(&c->tnc_mutex);
- return err;
-}
-
-/**
- * add_size - add znode size to partially calculated index size.
- * @c: UBIFS file-system description object
- * @znode: znode to add size for
- * @priv: partially calculated index size
- *
- * This is a helper function for 'dbg_check_idx_size()' which is called for
- * every indexing node and adds its size to the 'long long' variable pointed to
- * by @priv.
- */
-static int add_size(struct ubifs_info *c, struct ubifs_znode *znode, void *priv)
-{
- long long *idx_size = priv;
- int add;
-
- add = ubifs_idx_node_sz(c, znode->child_cnt);
- add = ALIGN(add, 8);
- *idx_size += add;
- return 0;
-}
-
-/**
- * dbg_check_idx_size - check index size.
- * @c: UBIFS file-system description object
- * @idx_size: size to check
- *
- * This function walks the UBIFS index, calculates its size and checks that the
- * size is equivalent to @idx_size. Returns zero in case of success and a
- * negative error code in case of failure.
- */
-int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
-{
- int err;
- long long calc = 0;
-
- if (!dbg_is_chk_index(c))
- return 0;
-
- err = dbg_walk_index(c, NULL, add_size, &calc);
- if (err) {
- ubifs_err(c, "error %d while walking the index", err);
- return err;
- }
-
- if (calc != idx_size) {
- ubifs_err(c, "index size check failed: calculated size is %lld, should be %lld",
- calc, idx_size);
- dump_stack();
- return -EINVAL;
- }
-
- return 0;
-}
-
-#ifndef __BAREBOX__
-/**
- * struct fsck_inode - information about an inode used when checking the file-system.
- * @rb: link in the RB-tree of inodes
- * @inum: inode number
- * @mode: inode type, permissions, etc
- * @nlink: inode link count
- * @xattr_cnt: count of extended attributes
- * @references: how many directory/xattr entries refer this inode (calculated
- * while walking the index)
- * @calc_cnt: for directory inode count of child directories
- * @size: inode size (read from on-flash inode)
- * @xattr_sz: summary size of all extended attributes (read from on-flash
- * inode)
- * @calc_sz: for directories calculated directory size
- * @calc_xcnt: count of extended attributes
- * @calc_xsz: calculated summary size of all extended attributes
- * @xattr_nms: sum of lengths of all extended attribute names belonging to this
- * inode (read from on-flash inode)
- * @calc_xnms: calculated sum of lengths of all extended attribute names
- */
-struct fsck_inode {
- struct rb_node rb;
- ino_t inum;
- umode_t mode;
- unsigned int nlink;
- unsigned int xattr_cnt;
- int references;
- int calc_cnt;
- long long size;
- unsigned int xattr_sz;
- long long calc_sz;
- long long calc_xcnt;
- long long calc_xsz;
- unsigned int xattr_nms;
- long long calc_xnms;
-};
-
-/**
- * struct fsck_data - private FS checking information.
- * @inodes: RB-tree of all inodes (contains @struct fsck_inode objects)
- */
-struct fsck_data {
- struct rb_root inodes;
-};
-
-/**
- * add_inode - add inode information to RB-tree of inodes.
- * @c: UBIFS file-system description object
- * @fsckd: FS checking information
- * @ino: raw UBIFS inode to add
- *
- * This is a helper function for 'check_leaf()' which adds information about
- * inode @ino to the RB-tree of inodes. Returns inode information pointer in
- * case of success and a negative error code in case of failure.
- */
-static struct fsck_inode *add_inode(struct ubifs_info *c,
- struct fsck_data *fsckd,
- struct ubifs_ino_node *ino)
-{
- struct rb_node **p, *parent = NULL;
- struct fsck_inode *fscki;
- ino_t inum = key_inum_flash(c, &ino->key);
- struct inode *inode;
- struct ubifs_inode *ui;
-
- p = &fsckd->inodes.rb_node;
- while (*p) {
- parent = *p;
- fscki = rb_entry(parent, struct fsck_inode, rb);
- if (inum < fscki->inum)
- p = &(*p)->rb_left;
- else if (inum > fscki->inum)
- p = &(*p)->rb_right;
- else
- return fscki;
- }
-
- if (inum > c->highest_inum) {
- ubifs_err(c, "too high inode number, max. is %lu",
- (unsigned long)c->highest_inum);
- return ERR_PTR(-EINVAL);
- }
-
- fscki = kzalloc(sizeof(struct fsck_inode), GFP_NOFS);
- if (!fscki)
- return ERR_PTR(-ENOMEM);
-
- inode = ilookup(c->vfs_sb, inum);
-
- fscki->inum = inum;
- /*
- * If the inode is present in the VFS inode cache, use it instead of
- * the on-flash inode which might be out-of-date. E.g., the size might
- * be out-of-date. If we do not do this, the following may happen, for
- * example:
- * 1. A power cut happens
- * 2. We mount the file-system R/O, the replay process fixes up the
- * inode size in the VFS cache, but on on-flash.
- * 3. 'check_leaf()' fails because it hits a data node beyond inode
- * size.
- */
- if (!inode) {
- fscki->nlink = le32_to_cpu(ino->nlink);
- fscki->size = le64_to_cpu(ino->size);
- fscki->xattr_cnt = le32_to_cpu(ino->xattr_cnt);
- fscki->xattr_sz = le32_to_cpu(ino->xattr_size);
- fscki->xattr_nms = le32_to_cpu(ino->xattr_names);
- fscki->mode = le32_to_cpu(ino->mode);
- } else {
- ui = ubifs_inode(inode);
- fscki->nlink = inode->i_nlink;
- fscki->size = inode->i_size;
- fscki->xattr_cnt = ui->xattr_cnt;
- fscki->xattr_sz = ui->xattr_size;
- fscki->xattr_nms = ui->xattr_names;
- fscki->mode = inode->i_mode;
- iput(inode);
- }
-
- if (S_ISDIR(fscki->mode)) {
- fscki->calc_sz = UBIFS_INO_NODE_SZ;
- fscki->calc_cnt = 2;
- }
-
- rb_link_node(&fscki->rb, parent, p);
- rb_insert_color(&fscki->rb, &fsckd->inodes);
-
- return fscki;
-}
-
-/**
- * search_inode - search inode in the RB-tree of inodes.
- * @fsckd: FS checking information
- * @inum: inode number to search
- *
- * This is a helper function for 'check_leaf()' which searches inode @inum in
- * the RB-tree of inodes and returns an inode information pointer or %NULL if
- * the inode was not found.
- */
-static struct fsck_inode *search_inode(struct fsck_data *fsckd, ino_t inum)
-{
- struct rb_node *p;
- struct fsck_inode *fscki;
-
- p = fsckd->inodes.rb_node;
- while (p) {
- fscki = rb_entry(p, struct fsck_inode, rb);
- if (inum < fscki->inum)
- p = p->rb_left;
- else if (inum > fscki->inum)
- p = p->rb_right;
- else
- return fscki;
- }
- return NULL;
-}
-
-/**
- * read_add_inode - read inode node and add it to RB-tree of inodes.
- * @c: UBIFS file-system description object
- * @fsckd: FS checking information
- * @inum: inode number to read
- *
- * This is a helper function for 'check_leaf()' which finds inode node @inum in
- * the index, reads it, and adds it to the RB-tree of inodes. Returns inode
- * information pointer in case of success and a negative error code in case of
- * failure.
- */
-static struct fsck_inode *read_add_inode(struct ubifs_info *c,
- struct fsck_data *fsckd, ino_t inum)
-{
- int n, err;
- union ubifs_key key;
- struct ubifs_znode *znode;
- struct ubifs_zbranch *zbr;
- struct ubifs_ino_node *ino;
- struct fsck_inode *fscki;
-
- fscki = search_inode(fsckd, inum);
- if (fscki)
- return fscki;
-
- ino_key_init(c, &key, inum);
- err = ubifs_lookup_level0(c, &key, &znode, &n);
- if (!err) {
- ubifs_err(c, "inode %lu not found in index", (unsigned long)inum);
- return ERR_PTR(-ENOENT);
- } else if (err < 0) {
- ubifs_err(c, "error %d while looking up inode %lu",
- err, (unsigned long)inum);
- return ERR_PTR(err);
- }
-
- zbr = &znode->zbranch[n];
- if (zbr->len < UBIFS_INO_NODE_SZ) {
- ubifs_err(c, "bad node %lu node length %d",
- (unsigned long)inum, zbr->len);
- return ERR_PTR(-EINVAL);
- }
-
- ino = kmalloc(zbr->len, GFP_NOFS);
- if (!ino)
- return ERR_PTR(-ENOMEM);
-
- err = ubifs_tnc_read_node(c, zbr, ino);
- if (err) {
- ubifs_err(c, "cannot read inode node at LEB %d:%d, error %d",
- zbr->lnum, zbr->offs, err);
- kfree(ino);
- return ERR_PTR(err);
- }
-
- fscki = add_inode(c, fsckd, ino);
- kfree(ino);
- if (IS_ERR(fscki)) {
- ubifs_err(c, "error %ld while adding inode %lu node",
- PTR_ERR(fscki), (unsigned long)inum);
- return fscki;
- }
-
- return fscki;
-}
-
-/**
- * check_leaf - check leaf node.
- * @c: UBIFS file-system description object
- * @zbr: zbranch of the leaf node to check
- * @priv: FS checking information
- *
- * This is a helper function for 'dbg_check_filesystem()' which is called for
- * every single leaf node while walking the indexing tree. It checks that the
- * leaf node referred from the indexing tree exists, has correct CRC, and does
- * some other basic validation. This function is also responsible for building
- * an RB-tree of inodes - it adds all inodes into the RB-tree. It also
- * calculates reference count, size, etc for each inode in order to later
- * compare them to the information stored inside the inodes and detect possible
- * inconsistencies. Returns zero in case of success and a negative error code
- * in case of failure.
- */
-static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
- void *priv)
-{
- ino_t inum;
- void *node;
- struct ubifs_ch *ch;
- int err, type = key_type(c, &zbr->key);
- struct fsck_inode *fscki;
-
- if (zbr->len < UBIFS_CH_SZ) {
- ubifs_err(c, "bad leaf length %d (LEB %d:%d)",
- zbr->len, zbr->lnum, zbr->offs);
- return -EINVAL;
- }
-
- node = kmalloc(zbr->len, GFP_NOFS);
- if (!node)
- return -ENOMEM;
-
- err = ubifs_tnc_read_node(c, zbr, node);
- if (err) {
- ubifs_err(c, "cannot read leaf node at LEB %d:%d, error %d",
- zbr->lnum, zbr->offs, err);
- goto out_free;
- }
-
- /* If this is an inode node, add it to RB-tree of inodes */
- if (type == UBIFS_INO_KEY) {
- fscki = add_inode(c, priv, node);
- if (IS_ERR(fscki)) {
- err = PTR_ERR(fscki);
- ubifs_err(c, "error %d while adding inode node", err);
- goto out_dump;
- }
- goto out;
- }
-
- if (type != UBIFS_DENT_KEY && type != UBIFS_XENT_KEY &&
- type != UBIFS_DATA_KEY) {
- ubifs_err(c, "unexpected node type %d at LEB %d:%d",
- type, zbr->lnum, zbr->offs);
- err = -EINVAL;
- goto out_free;
- }
-
- ch = node;
- if (le64_to_cpu(ch->sqnum) > c->max_sqnum) {
- ubifs_err(c, "too high sequence number, max. is %llu",
- c->max_sqnum);
- err = -EINVAL;
- goto out_dump;
- }
-
- if (type == UBIFS_DATA_KEY) {
- long long blk_offs;
- struct ubifs_data_node *dn = node;
-
- ubifs_assert(zbr->len >= UBIFS_DATA_NODE_SZ);
-
- /*
- * Search the inode node this data node belongs to and insert
- * it to the RB-tree of inodes.
- */
- inum = key_inum_flash(c, &dn->key);
- fscki = read_add_inode(c, priv, inum);
- if (IS_ERR(fscki)) {
- err = PTR_ERR(fscki);
- ubifs_err(c, "error %d while processing data node and trying to find inode node %lu",
- err, (unsigned long)inum);
- goto out_dump;
- }
-
- /* Make sure the data node is within inode size */
- blk_offs = key_block_flash(c, &dn->key);
- blk_offs <<= UBIFS_BLOCK_SHIFT;
- blk_offs += le32_to_cpu(dn->size);
- if (blk_offs > fscki->size) {
- ubifs_err(c, "data node at LEB %d:%d is not within inode size %lld",
- zbr->lnum, zbr->offs, fscki->size);
- err = -EINVAL;
- goto out_dump;
- }
- } else {
- int nlen;
- struct ubifs_dent_node *dent = node;
- struct fsck_inode *fscki1;
-
- ubifs_assert(zbr->len >= UBIFS_DENT_NODE_SZ);
-
- err = ubifs_validate_entry(c, dent);
- if (err)
- goto out_dump;
-
- /*
- * Search the inode node this entry refers to and the parent
- * inode node and insert them to the RB-tree of inodes.
- */
- inum = le64_to_cpu(dent->inum);
- fscki = read_add_inode(c, priv, inum);
- if (IS_ERR(fscki)) {
- err = PTR_ERR(fscki);
- ubifs_err(c, "error %d while processing entry node and trying to find inode node %lu",
- err, (unsigned long)inum);
- goto out_dump;
- }
-
- /* Count how many direntries or xentries refers this inode */
- fscki->references += 1;
-
- inum = key_inum_flash(c, &dent->key);
- fscki1 = read_add_inode(c, priv, inum);
- if (IS_ERR(fscki1)) {
- err = PTR_ERR(fscki1);
- ubifs_err(c, "error %d while processing entry node and trying to find parent inode node %lu",
- err, (unsigned long)inum);
- goto out_dump;
- }
-
- nlen = le16_to_cpu(dent->nlen);
- if (type == UBIFS_XENT_KEY) {
- fscki1->calc_xcnt += 1;
- fscki1->calc_xsz += CALC_DENT_SIZE(nlen);
- fscki1->calc_xsz += CALC_XATTR_BYTES(fscki->size);
- fscki1->calc_xnms += nlen;
- } else {
- fscki1->calc_sz += CALC_DENT_SIZE(nlen);
- if (dent->type == UBIFS_ITYPE_DIR)
- fscki1->calc_cnt += 1;
- }
- }
-
-out:
- kfree(node);
- return 0;
-
-out_dump:
- ubifs_msg(c, "dump of node at LEB %d:%d", zbr->lnum, zbr->offs);
- ubifs_dump_node(c, node);
-out_free:
- kfree(node);
- return err;
-}
-
-/**
- * free_inodes - free RB-tree of inodes.
- * @fsckd: FS checking information
- */
-static void free_inodes(struct fsck_data *fsckd)
-{
- struct fsck_inode *fscki, *n;
-
- rbtree_postorder_for_each_entry_safe(fscki, n, &fsckd->inodes, rb)
- kfree(fscki);
-}
-
-/**
- * check_inodes - checks all inodes.
- * @c: UBIFS file-system description object
- * @fsckd: FS checking information
- *
- * This is a helper function for 'dbg_check_filesystem()' which walks the
- * RB-tree of inodes after the index scan has been finished, and checks that
- * inode nlink, size, etc are correct. Returns zero if inodes are fine,
- * %-EINVAL if not, and a negative error code in case of failure.
- */
-static int check_inodes(struct ubifs_info *c, struct fsck_data *fsckd)
-{
- int n, err;
- union ubifs_key key;
- struct ubifs_znode *znode;
- struct ubifs_zbranch *zbr;
- struct ubifs_ino_node *ino;
- struct fsck_inode *fscki;
- struct rb_node *this = rb_first(&fsckd->inodes);
-
- while (this) {
- fscki = rb_entry(this, struct fsck_inode, rb);
- this = rb_next(this);
-
- if (S_ISDIR(fscki->mode)) {
- /*
- * Directories have to have exactly one reference (they
- * cannot have hardlinks), although root inode is an
- * exception.
- */
- if (fscki->inum != UBIFS_ROOT_INO &&
- fscki->references != 1) {
- ubifs_err(c, "directory inode %lu has %d direntries which refer it, but should be 1",
- (unsigned long)fscki->inum,
- fscki->references);
- goto out_dump;
- }
- if (fscki->inum == UBIFS_ROOT_INO &&
- fscki->references != 0) {
- ubifs_err(c, "root inode %lu has non-zero (%d) direntries which refer it",
- (unsigned long)fscki->inum,
- fscki->references);
- goto out_dump;
- }
- if (fscki->calc_sz != fscki->size) {
- ubifs_err(c, "directory inode %lu size is %lld, but calculated size is %lld",
- (unsigned long)fscki->inum,
- fscki->size, fscki->calc_sz);
- goto out_dump;
- }
- if (fscki->calc_cnt != fscki->nlink) {
- ubifs_err(c, "directory inode %lu nlink is %d, but calculated nlink is %d",
- (unsigned long)fscki->inum,
- fscki->nlink, fscki->calc_cnt);
- goto out_dump;
- }
- } else {
- if (fscki->references != fscki->nlink) {
- ubifs_err(c, "inode %lu nlink is %d, but calculated nlink is %d",
- (unsigned long)fscki->inum,
- fscki->nlink, fscki->references);
- goto out_dump;
- }
- }
- if (fscki->xattr_sz != fscki->calc_xsz) {
- ubifs_err(c, "inode %lu has xattr size %u, but calculated size is %lld",
- (unsigned long)fscki->inum, fscki->xattr_sz,
- fscki->calc_xsz);
- goto out_dump;
- }
- if (fscki->xattr_cnt != fscki->calc_xcnt) {
- ubifs_err(c, "inode %lu has %u xattrs, but calculated count is %lld",
- (unsigned long)fscki->inum,
- fscki->xattr_cnt, fscki->calc_xcnt);
- goto out_dump;
- }
- if (fscki->xattr_nms != fscki->calc_xnms) {
- ubifs_err(c, "inode %lu has xattr names' size %u, but calculated names' size is %lld",
- (unsigned long)fscki->inum, fscki->xattr_nms,
- fscki->calc_xnms);
- goto out_dump;
- }
- }
-
- return 0;
-
-out_dump:
- /* Read the bad inode and dump it */
- ino_key_init(c, &key, fscki->inum);
- err = ubifs_lookup_level0(c, &key, &znode, &n);
- if (!err) {
- ubifs_err(c, "inode %lu not found in index",
- (unsigned long)fscki->inum);
- return -ENOENT;
- } else if (err < 0) {
- ubifs_err(c, "error %d while looking up inode %lu",
- err, (unsigned long)fscki->inum);
- return err;
- }
-
- zbr = &znode->zbranch[n];
- ino = kmalloc(zbr->len, GFP_NOFS);
- if (!ino)
- return -ENOMEM;
-
- err = ubifs_tnc_read_node(c, zbr, ino);
- if (err) {
- ubifs_err(c, "cannot read inode node at LEB %d:%d, error %d",
- zbr->lnum, zbr->offs, err);
- kfree(ino);
- return err;
- }
-
- ubifs_msg(c, "dump of the inode %lu sitting in LEB %d:%d",
- (unsigned long)fscki->inum, zbr->lnum, zbr->offs);
- ubifs_dump_node(c, ino);
- kfree(ino);
- return -EINVAL;
-}
-
-/**
- * dbg_check_filesystem - check the file-system.
- * @c: UBIFS file-system description object
- *
- * This function checks the file system, namely:
- * o makes sure that all leaf nodes exist and their CRCs are correct;
- * o makes sure inode nlink, size, xattr size/count are correct (for all
- * inodes).
- *
- * The function reads whole indexing tree and all nodes, so it is pretty
- * heavy-weight. Returns zero if the file-system is consistent, %-EINVAL if
- * not, and a negative error code in case of failure.
- */
-int dbg_check_filesystem(struct ubifs_info *c)
-{
- int err;
- struct fsck_data fsckd;
-
- if (!dbg_is_chk_fs(c))
- return 0;
-
- fsckd.inodes = RB_ROOT;
- err = dbg_walk_index(c, check_leaf, NULL, &fsckd);
- if (err)
- goto out_free;
-
- err = check_inodes(c, &fsckd);
- if (err)
- goto out_free;
-
- free_inodes(&fsckd);
- return 0;
-
-out_free:
- ubifs_err(c, "file-system check failed with error %d", err);
- dump_stack();
- free_inodes(&fsckd);
- return err;
-}
-
-/**
- * dbg_check_data_nodes_order - check that list of data nodes is sorted.
- * @c: UBIFS file-system description object
- * @head: the list of nodes ('struct ubifs_scan_node' objects)
- *
- * This function returns zero if the list of data nodes is sorted correctly,
- * and %-EINVAL if not.
- */
-int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
-{
- struct list_head *cur;
- struct ubifs_scan_node *sa, *sb;
-
- if (!dbg_is_chk_gen(c))
- return 0;
-
- for (cur = head->next; cur->next != head; cur = cur->next) {
- ino_t inuma, inumb;
- uint32_t blka, blkb;
-
- cond_resched();
- sa = container_of(cur, struct ubifs_scan_node, list);
- sb = container_of(cur->next, struct ubifs_scan_node, list);
-
- if (sa->type != UBIFS_DATA_NODE) {
- ubifs_err(c, "bad node type %d", sa->type);
- ubifs_dump_node(c, sa->node);
- return -EINVAL;
- }
- if (sb->type != UBIFS_DATA_NODE) {
- ubifs_err(c, "bad node type %d", sb->type);
- ubifs_dump_node(c, sb->node);
- return -EINVAL;
- }
-
- inuma = key_inum(c, &sa->key);
- inumb = key_inum(c, &sb->key);
-
- if (inuma < inumb)
- continue;
- if (inuma > inumb) {
- ubifs_err(c, "larger inum %lu goes before inum %lu",
- (unsigned long)inuma, (unsigned long)inumb);
- goto error_dump;
- }
-
- blka = key_block(c, &sa->key);
- blkb = key_block(c, &sb->key);
-
- if (blka > blkb) {
- ubifs_err(c, "larger block %u goes before %u", blka, blkb);
- goto error_dump;
- }
- if (blka == blkb) {
- ubifs_err(c, "two data nodes for the same block");
- goto error_dump;
- }
- }
-
- return 0;
-
-error_dump:
- ubifs_dump_node(c, sa->node);
- ubifs_dump_node(c, sb->node);
- return -EINVAL;
-}
-
-/**
- * dbg_check_nondata_nodes_order - check that list of data nodes is sorted.
- * @c: UBIFS file-system description object
- * @head: the list of nodes ('struct ubifs_scan_node' objects)
- *
- * This function returns zero if the list of non-data nodes is sorted correctly,
- * and %-EINVAL if not.
- */
-int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
-{
- struct list_head *cur;
- struct ubifs_scan_node *sa, *sb;
-
- if (!dbg_is_chk_gen(c))
- return 0;
-
- for (cur = head->next; cur->next != head; cur = cur->next) {
- ino_t inuma, inumb;
- uint32_t hasha, hashb;
-
- cond_resched();
- sa = container_of(cur, struct ubifs_scan_node, list);
- sb = container_of(cur->next, struct ubifs_scan_node, list);
-
- if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
- sa->type != UBIFS_XENT_NODE) {
- ubifs_err(c, "bad node type %d", sa->type);
- ubifs_dump_node(c, sa->node);
- return -EINVAL;
- }
- if (sa->type != UBIFS_INO_NODE && sa->type != UBIFS_DENT_NODE &&
- sa->type != UBIFS_XENT_NODE) {
- ubifs_err(c, "bad node type %d", sb->type);
- ubifs_dump_node(c, sb->node);
- return -EINVAL;
- }
-
- if (sa->type != UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
- ubifs_err(c, "non-inode node goes before inode node");
- goto error_dump;
- }
-
- if (sa->type == UBIFS_INO_NODE && sb->type != UBIFS_INO_NODE)
- continue;
-
- if (sa->type == UBIFS_INO_NODE && sb->type == UBIFS_INO_NODE) {
- /* Inode nodes are sorted in descending size order */
- if (sa->len < sb->len) {
- ubifs_err(c, "smaller inode node goes first");
- goto error_dump;
- }
- continue;
- }
-
- /*
- * This is either a dentry or xentry, which should be sorted in
- * ascending (parent ino, hash) order.
- */
- inuma = key_inum(c, &sa->key);
- inumb = key_inum(c, &sb->key);
-
- if (inuma < inumb)
- continue;
- if (inuma > inumb) {
- ubifs_err(c, "larger inum %lu goes before inum %lu",
- (unsigned long)inuma, (unsigned long)inumb);
- goto error_dump;
- }
-
- hasha = key_block(c, &sa->key);
- hashb = key_block(c, &sb->key);
-
- if (hasha > hashb) {
- ubifs_err(c, "larger hash %u goes before %u",
- hasha, hashb);
- goto error_dump;
- }
- }
-
- return 0;
-
-error_dump:
- ubifs_msg(c, "dumping first node");
- ubifs_dump_node(c, sa->node);
- ubifs_msg(c, "dumping second node");
- ubifs_dump_node(c, sb->node);
- return -EINVAL;
- return 0;
-}
-
-static inline int chance(unsigned int n, unsigned int out_of)
-{
- return !!((prandom_u32() % out_of) + 1 <= n);
-
-}
-
-static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
-{
- struct ubifs_debug_info *d = c->dbg;
-
- ubifs_assert(dbg_is_tst_rcvry(c));
-
- if (!d->pc_cnt) {
- /* First call - decide delay to the power cut */
- if (chance(1, 2)) {
- unsigned long delay;
-
- if (chance(1, 2)) {
- d->pc_delay = 1;
- /* Fail within 1 minute */
- delay = prandom_u32() % 60000;
- d->pc_timeout = jiffies;
- d->pc_timeout += msecs_to_jiffies(delay);
- ubifs_warn(c, "failing after %lums", delay);
- } else {
- d->pc_delay = 2;
- delay = prandom_u32() % 10000;
- /* Fail within 10000 operations */
- d->pc_cnt_max = delay;
- ubifs_warn(c, "failing after %lu calls", delay);
- }
- }
-
- d->pc_cnt += 1;
- }
-
- /* Determine if failure delay has expired */
- if (d->pc_delay == 1 && time_before(jiffies, d->pc_timeout))
- return 0;
- if (d->pc_delay == 2 && d->pc_cnt++ < d->pc_cnt_max)
- return 0;
-
- if (lnum == UBIFS_SB_LNUM) {
- if (write && chance(1, 2))
- return 0;
- if (chance(19, 20))
- return 0;
- ubifs_warn(c, "failing in super block LEB %d", lnum);
- } else if (lnum == UBIFS_MST_LNUM || lnum == UBIFS_MST_LNUM + 1) {
- if (chance(19, 20))
- return 0;
- ubifs_warn(c, "failing in master LEB %d", lnum);
- } else if (lnum >= UBIFS_LOG_LNUM && lnum <= c->log_last) {
- if (write && chance(99, 100))
- return 0;
- if (chance(399, 400))
- return 0;
- ubifs_warn(c, "failing in log LEB %d", lnum);
- } else if (lnum >= c->lpt_first && lnum <= c->lpt_last) {
- if (write && chance(7, 8))
- return 0;
- if (chance(19, 20))
- return 0;
- ubifs_warn(c, "failing in LPT LEB %d", lnum);
- } else if (lnum >= c->orph_first && lnum <= c->orph_last) {
- if (write && chance(1, 2))
- return 0;
- if (chance(9, 10))
- return 0;
- ubifs_warn(c, "failing in orphan LEB %d", lnum);
- } else if (lnum == c->ihead_lnum) {
- if (chance(99, 100))
- return 0;
- ubifs_warn(c, "failing in index head LEB %d", lnum);
- } else if (c->jheads && lnum == c->jheads[GCHD].wbuf.lnum) {
- if (chance(9, 10))
- return 0;
- ubifs_warn(c, "failing in GC head LEB %d", lnum);
- } else if (write && !RB_EMPTY_ROOT(&c->buds) &&
- !ubifs_search_bud(c, lnum)) {
- if (chance(19, 20))
- return 0;
- ubifs_warn(c, "failing in non-bud LEB %d", lnum);
- } else if (c->cmt_state == COMMIT_RUNNING_BACKGROUND ||
- c->cmt_state == COMMIT_RUNNING_REQUIRED) {
- if (chance(999, 1000))
- return 0;
- ubifs_warn(c, "failing in bud LEB %d commit running", lnum);
- } else {
- if (chance(9999, 10000))
- return 0;
- ubifs_warn(c, "failing in bud LEB %d commit not running", lnum);
- }
-
- d->pc_happened = 1;
- ubifs_warn(c, "========== Power cut emulated ==========");
- dump_stack();
- return 1;
-}
-
-static int corrupt_data(const struct ubifs_info *c, const void *buf,
- unsigned int len)
-{
- unsigned int from, to, ffs = chance(1, 2);
- unsigned char *p = (void *)buf;
-
- from = prandom_u32() % len;
- /* Corruption span max to end of write unit */
- to = min(len, ALIGN(from + 1, c->max_write_size));
-
- ubifs_warn(c, "filled bytes %u-%u with %s", from, to - 1,
- ffs ? "0xFFs" : "random data");
-
- if (ffs)
- memset(p + from, 0xFF, to - from);
- else
- prandom_bytes(p + from, to - from);
-
- return to;
-}
-
-int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
- int offs, int len)
-{
- int err, failing;
-
- if (c->dbg->pc_happened)
- return -EROFS;
-
- failing = power_cut_emulated(c, lnum, 1);
- if (failing) {
- len = corrupt_data(c, buf, len);
- ubifs_warn(c, "actually write %d bytes to LEB %d:%d (the buffer was corrupted)",
- len, lnum, offs);
- }
- err = ubi_leb_write(c->ubi, lnum, buf, offs, len);
- if (err)
- return err;
- if (failing)
- return -EROFS;
- return 0;
-}
-
-int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
- int len)
-{
- int err;
-
- if (c->dbg->pc_happened)
- return -EROFS;
- if (power_cut_emulated(c, lnum, 1))
- return -EROFS;
- err = ubi_leb_change(c->ubi, lnum, buf, len);
- if (err)
- return err;
- if (power_cut_emulated(c, lnum, 1))
- return -EROFS;
- return 0;
-}
-
-int dbg_leb_unmap(struct ubifs_info *c, int lnum)
-{
- int err;
-
- if (c->dbg->pc_happened)
- return -EROFS;
- if (power_cut_emulated(c, lnum, 0))
- return -EROFS;
- err = ubi_leb_unmap(c->ubi, lnum);
- if (err)
- return err;
- if (power_cut_emulated(c, lnum, 0))
- return -EROFS;
- return 0;
-}
-
-int dbg_leb_map(struct ubifs_info *c, int lnum)
-{
- int err;
-
- if (c->dbg->pc_happened)
- return -EROFS;
- if (power_cut_emulated(c, lnum, 0))
- return -EROFS;
- err = ubi_leb_map(c->ubi, lnum);
- if (err)
- return err;
- if (power_cut_emulated(c, lnum, 0))
- return -EROFS;
- return 0;
-}
-
-/*
- * Root directory for UBIFS stuff in debugfs. Contains sub-directories which
- * contain the stuff specific to particular file-system mounts.
- */
-static struct dentry *dfs_rootdir;
-
-static int dfs_file_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return nonseekable_open(inode, file);
-}
-
-/**
- * provide_user_output - provide output to the user reading a debugfs file.
- * @val: boolean value for the answer
- * @u: the buffer to store the answer at
- * @count: size of the buffer
- * @ppos: position in the @u output buffer
- *
- * This is a simple helper function which stores @val boolean value in the user
- * buffer when the user reads one of UBIFS debugfs files. Returns amount of
- * bytes written to @u in case of success and a negative error code in case of
- * failure.
- */
-static int provide_user_output(int val, char __user *u, size_t count,
- loff_t *ppos)
-{
- char buf[3];
-
- if (val)
- buf[0] = '1';
- else
- buf[0] = '0';
- buf[1] = '\n';
- buf[2] = 0x00;
-
- return simple_read_from_buffer(u, count, ppos, buf, 2);
-}
-
-static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count,
- loff_t *ppos)
-{
- struct dentry *dent = file->f_path.dentry;
- struct ubifs_info *c = file->private_data;
- struct ubifs_debug_info *d = c->dbg;
- int val;
-
- if (dent == d->dfs_chk_gen)
- val = d->chk_gen;
- else if (dent == d->dfs_chk_index)
- val = d->chk_index;
- else if (dent == d->dfs_chk_orph)
- val = d->chk_orph;
- else if (dent == d->dfs_chk_lprops)
- val = d->chk_lprops;
- else if (dent == d->dfs_chk_fs)
- val = d->chk_fs;
- else if (dent == d->dfs_tst_rcvry)
- val = d->tst_rcvry;
- else if (dent == d->dfs_ro_error)
- val = c->ro_error;
- else
- return -EINVAL;
-
- return provide_user_output(val, u, count, ppos);
-}
-
-/**
- * interpret_user_input - interpret user debugfs file input.
- * @u: user-provided buffer with the input
- * @count: buffer size
- *
- * This is a helper function which interpret user input to a boolean UBIFS
- * debugfs file. Returns %0 or %1 in case of success and a negative error code
- * in case of failure.
- */
-static int interpret_user_input(const char __user *u, size_t count)
-{
- size_t buf_size;
- char buf[8];
-
- buf_size = min_t(size_t, count, (sizeof(buf) - 1));
- if (copy_from_user(buf, u, buf_size))
- return -EFAULT;
-
- if (buf[0] == '1')
- return 1;
- else if (buf[0] == '0')
- return 0;
-
- return -EINVAL;
-}
-
-static ssize_t dfs_file_write(struct file *file, const char __user *u,
- size_t count, loff_t *ppos)
-{
- struct ubifs_info *c = file->private_data;
- struct ubifs_debug_info *d = c->dbg;
- struct dentry *dent = file->f_path.dentry;
- int val;
-
- /*
- * TODO: this is racy - the file-system might have already been
- * unmounted and we'd oops in this case. The plan is to fix it with
- * help of 'iterate_supers_type()' which we should have in v3.0: when
- * a debugfs opened, we rember FS's UUID in file->private_data. Then
- * whenever we access the FS via a debugfs file, we iterate all UBIFS
- * superblocks and fine the one with the same UUID, and take the
- * locking right.
- *
- * The other way to go suggested by Al Viro is to create a separate
- * 'ubifs-debug' file-system instead.
- */
- if (file->f_path.dentry == d->dfs_dump_lprops) {
- ubifs_dump_lprops(c);
- return count;
- }
- if (file->f_path.dentry == d->dfs_dump_budg) {
- ubifs_dump_budg(c, &c->bi);
- return count;
- }
- if (file->f_path.dentry == d->dfs_dump_tnc) {
- mutex_lock(&c->tnc_mutex);
- ubifs_dump_tnc(c);
- mutex_unlock(&c->tnc_mutex);
- return count;
- }
-
- val = interpret_user_input(u, count);
- if (val < 0)
- return val;
-
- if (dent == d->dfs_chk_gen)
- d->chk_gen = val;
- else if (dent == d->dfs_chk_index)
- d->chk_index = val;
- else if (dent == d->dfs_chk_orph)
- d->chk_orph = val;
- else if (dent == d->dfs_chk_lprops)
- d->chk_lprops = val;
- else if (dent == d->dfs_chk_fs)
- d->chk_fs = val;
- else if (dent == d->dfs_tst_rcvry)
- d->tst_rcvry = val;
- else if (dent == d->dfs_ro_error)
- c->ro_error = !!val;
- else
- return -EINVAL;
-
- return count;
-}
-
-static const struct file_operations dfs_fops = {
- .open = dfs_file_open,
- .read = dfs_file_read,
- .write = dfs_file_write,
- .owner = THIS_MODULE,
- .llseek = no_llseek,
-};
-
-/**
- * dbg_debugfs_init_fs - initialize debugfs for UBIFS instance.
- * @c: UBIFS file-system description object
- *
- * This function creates all debugfs files for this instance of UBIFS. Returns
- * zero in case of success and a negative error code in case of failure.
- *
- * Note, the only reason we have not merged this function with the
- * 'ubifs_debugging_init()' function is because it is better to initialize
- * debugfs interfaces at the very end of the mount process, and remove them at
- * the very beginning of the mount process.
- */
-int dbg_debugfs_init_fs(struct ubifs_info *c)
-{
- int err, n;
- const char *fname;
- struct dentry *dent;
- struct ubifs_debug_info *d = c->dbg;
-
- if (!IS_ENABLED(CONFIG_DEBUG_FS))
- return 0;
-
- n = snprintf(d->dfs_dir_name, UBIFS_DFS_DIR_LEN + 1, UBIFS_DFS_DIR_NAME,
- c->vi.ubi_num, c->vi.vol_id);
- if (n == UBIFS_DFS_DIR_LEN) {
- /* The array size is too small */
- fname = UBIFS_DFS_DIR_NAME;
- dent = ERR_PTR(-EINVAL);
- goto out;
- }
-
- fname = d->dfs_dir_name;
- dent = debugfs_create_dir(fname, dfs_rootdir);
- if (IS_ERR_OR_NULL(dent))
- goto out;
- d->dfs_dir = dent;
-
- fname = "dump_lprops";
- dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_dump_lprops = dent;
-
- fname = "dump_budg";
- dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_dump_budg = dent;
-
- fname = "dump_tnc";
- dent = debugfs_create_file(fname, S_IWUSR, d->dfs_dir, c, &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_dump_tnc = dent;
-
- fname = "chk_general";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
- &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_chk_gen = dent;
-
- fname = "chk_index";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
- &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_chk_index = dent;
-
- fname = "chk_orphans";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
- &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_chk_orph = dent;
-
- fname = "chk_lprops";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
- &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_chk_lprops = dent;
-
- fname = "chk_fs";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
- &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_chk_fs = dent;
-
- fname = "tst_recovery";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
- &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_tst_rcvry = dent;
-
- fname = "ro_error";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, d->dfs_dir, c,
- &dfs_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- d->dfs_ro_error = dent;
-
- return 0;
-
-out_remove:
- debugfs_remove_recursive(d->dfs_dir);
-out:
- err = dent ? PTR_ERR(dent) : -ENODEV;
- ubifs_err(c, "cannot create \"%s\" debugfs file or directory, error %d\n",
- fname, err);
- return err;
-}
-
-/**
- * dbg_debugfs_exit_fs - remove all debugfs files.
- * @c: UBIFS file-system description object
- */
-void dbg_debugfs_exit_fs(struct ubifs_info *c)
-{
- if (IS_ENABLED(CONFIG_DEBUG_FS))
- debugfs_remove_recursive(c->dbg->dfs_dir);
-}
-
-struct ubifs_global_debug_info ubifs_dbg;
-
-static struct dentry *dfs_chk_gen;
-static struct dentry *dfs_chk_index;
-static struct dentry *dfs_chk_orph;
-static struct dentry *dfs_chk_lprops;
-static struct dentry *dfs_chk_fs;
-static struct dentry *dfs_tst_rcvry;
-
-static ssize_t dfs_global_file_read(struct file *file, char __user *u,
- size_t count, loff_t *ppos)
-{
- struct dentry *dent = file->f_path.dentry;
- int val;
-
- if (dent == dfs_chk_gen)
- val = ubifs_dbg.chk_gen;
- else if (dent == dfs_chk_index)
- val = ubifs_dbg.chk_index;
- else if (dent == dfs_chk_orph)
- val = ubifs_dbg.chk_orph;
- else if (dent == dfs_chk_lprops)
- val = ubifs_dbg.chk_lprops;
- else if (dent == dfs_chk_fs)
- val = ubifs_dbg.chk_fs;
- else if (dent == dfs_tst_rcvry)
- val = ubifs_dbg.tst_rcvry;
- else
- return -EINVAL;
-
- return provide_user_output(val, u, count, ppos);
-}
-
-static ssize_t dfs_global_file_write(struct file *file, const char __user *u,
- size_t count, loff_t *ppos)
-{
- struct dentry *dent = file->f_path.dentry;
- int val;
-
- val = interpret_user_input(u, count);
- if (val < 0)
- return val;
-
- if (dent == dfs_chk_gen)
- ubifs_dbg.chk_gen = val;
- else if (dent == dfs_chk_index)
- ubifs_dbg.chk_index = val;
- else if (dent == dfs_chk_orph)
- ubifs_dbg.chk_orph = val;
- else if (dent == dfs_chk_lprops)
- ubifs_dbg.chk_lprops = val;
- else if (dent == dfs_chk_fs)
- ubifs_dbg.chk_fs = val;
- else if (dent == dfs_tst_rcvry)
- ubifs_dbg.tst_rcvry = val;
- else
- return -EINVAL;
-
- return count;
-}
-
-static const struct file_operations dfs_global_fops = {
- .read = dfs_global_file_read,
- .write = dfs_global_file_write,
- .owner = THIS_MODULE,
- .llseek = no_llseek,
-};
-
-/**
- * dbg_debugfs_init - initialize debugfs file-system.
- *
- * UBIFS uses debugfs file-system to expose various debugging knobs to
- * user-space. This function creates "ubifs" directory in the debugfs
- * file-system. Returns zero in case of success and a negative error code in
- * case of failure.
- */
-int dbg_debugfs_init(void)
-{
- int err;
- const char *fname;
- struct dentry *dent;
-
- if (!IS_ENABLED(CONFIG_DEBUG_FS))
- return 0;
-
- fname = "ubifs";
- dent = debugfs_create_dir(fname, NULL);
- if (IS_ERR_OR_NULL(dent))
- goto out;
- dfs_rootdir = dent;
-
- fname = "chk_general";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
- &dfs_global_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- dfs_chk_gen = dent;
-
- fname = "chk_index";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
- &dfs_global_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- dfs_chk_index = dent;
-
- fname = "chk_orphans";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
- &dfs_global_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- dfs_chk_orph = dent;
-
- fname = "chk_lprops";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
- &dfs_global_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- dfs_chk_lprops = dent;
-
- fname = "chk_fs";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
- &dfs_global_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- dfs_chk_fs = dent;
-
- fname = "tst_recovery";
- dent = debugfs_create_file(fname, S_IRUSR | S_IWUSR, dfs_rootdir, NULL,
- &dfs_global_fops);
- if (IS_ERR_OR_NULL(dent))
- goto out_remove;
- dfs_tst_rcvry = dent;
-
- return 0;
-
-out_remove:
- debugfs_remove_recursive(dfs_rootdir);
-out:
- err = dent ? PTR_ERR(dent) : -ENODEV;
- pr_err("UBIFS error (pid %d): cannot create \"%s\" debugfs file or directory, error %d\n",
- 0, fname, err);
- return err;
-}
-
-/**
- * dbg_debugfs_exit - remove the "ubifs" directory from debugfs file-system.
- */
-void dbg_debugfs_exit(void)
-{
- if (IS_ENABLED(CONFIG_DEBUG_FS))
- debugfs_remove_recursive(dfs_rootdir);
-}
-
-/**
- * ubifs_debugging_init - initialize UBIFS debugging.
- * @c: UBIFS file-system description object
- *
- * This function initializes debugging-related data for the file system.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- */
-int ubifs_debugging_init(struct ubifs_info *c)
-{
- c->dbg = kzalloc(sizeof(struct ubifs_debug_info), GFP_KERNEL);
- if (!c->dbg)
- return -ENOMEM;
-
- return 0;
-}
-
-/**
- * ubifs_debugging_exit - free debugging data.
- * @c: UBIFS file-system description object
- */
-void ubifs_debugging_exit(struct ubifs_info *c)
-{
- kfree(c->dbg);
-}
-#endif
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index 72587b50b6..9afb16d897 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -137,35 +137,6 @@ struct ubifs_global_debug_info {
unsigned int tst_rcvry:1;
};
-#ifndef __BAREBOX__
-#define ubifs_assert(expr) do { \
- if (unlikely(!(expr))) { \
- pr_crit("UBIFS assert failed in %s at %u (pid %d)\n", \
- __func__, __LINE__, current->pid); \
- dump_stack(); \
- } \
-} while (0)
-
-#define ubifs_assert_cmt_locked(c) do { \
- if (unlikely(down_write_trylock(&(c)->commit_sem))) { \
- up_write(&(c)->commit_sem); \
- pr_crit("commit lock is not locked!\n"); \
- ubifs_assert(0); \
- } \
-} while (0)
-
-#define ubifs_dbg_msg(type, fmt, ...) \
- pr_debug("UBIFS DBG " type " (pid %d): " fmt "\n", current->pid, \
- ##__VA_ARGS__)
-
-#define DBG_KEY_BUF_LEN 48
-#define ubifs_dbg_msg_key(type, key, fmt, ...) do { \
- char __tmp_key_buf[DBG_KEY_BUF_LEN]; \
- pr_debug("UBIFS DBG " type " (pid %d): " fmt "%s\n", current->pid, \
- ##__VA_ARGS__, \
- dbg_snprintf_key(c, key, __tmp_key_buf, DBG_KEY_BUF_LEN)); \
-} while (0)
-#else
#define ubifs_assert(expr) do { \
if (0 && unlikely(!(expr))) { \
pr_crit("UBIFS assert failed in %s at %u\n", \
@@ -201,7 +172,6 @@ struct ubifs_global_debug_info {
#endif
-#endif
/* General messages */
#define dbg_gen(fmt, ...) ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
@@ -236,41 +206,6 @@ struct ubifs_global_debug_info {
/* Additional recovery messages */
#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
-#ifndef __BAREBOX__
-extern struct ubifs_global_debug_info ubifs_dbg;
-
-static inline int dbg_is_chk_gen(const struct ubifs_info *c)
-{
- return !!(ubifs_dbg.chk_gen || c->dbg->chk_gen);
-}
-static inline int dbg_is_chk_index(const struct ubifs_info *c)
-{
- return !!(ubifs_dbg.chk_index || c->dbg->chk_index);
-}
-static inline int dbg_is_chk_orph(const struct ubifs_info *c)
-{
- return !!(ubifs_dbg.chk_orph || c->dbg->chk_orph);
-}
-static inline int dbg_is_chk_lprops(const struct ubifs_info *c)
-{
- return !!(ubifs_dbg.chk_lprops || c->dbg->chk_lprops);
-}
-static inline int dbg_is_chk_fs(const struct ubifs_info *c)
-{
- return !!(ubifs_dbg.chk_fs || c->dbg->chk_fs);
-}
-static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)
-{
- return !!(ubifs_dbg.tst_rcvry || c->dbg->tst_rcvry);
-}
-static inline int dbg_is_power_cut(const struct ubifs_info *c)
-{
- return !!c->dbg->pc_happened;
-}
-
-int ubifs_debugging_init(struct ubifs_info *c);
-void ubifs_debugging_exit(struct ubifs_info *c);
-#else
static inline int dbg_is_chk_gen(const struct ubifs_info *c)
{
return 0;
@@ -303,7 +238,6 @@ static inline int dbg_is_power_cut(const struct ubifs_info *c)
int ubifs_debugging_init(struct ubifs_info *c);
void ubifs_debugging_exit(struct ubifs_info *c);
-#endif
/* Dump functions */
const char *dbg_ntype(int type);
diff --git a/fs/ubifs/gc.c b/fs/ubifs/gc.c
deleted file mode 100644
index 39f749dc82..0000000000
--- a/fs/ubifs/gc.c
+++ /dev/null
@@ -1,976 +0,0 @@
-/*
- * This file is part of UBIFS.
- *
- * Copyright (C) 2006-2008 Nokia Corporation.
- *
- * SPDX-License-Identifier: GPL-2.0
- *
- * 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 __BAREBOX__
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <linux/list_sort.h>
-#endif
-#include "ubifs.h"
-
-#ifndef __BAREBOX__
-/*
- * 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);
- dbg_gc("switch GC head from LEB %d:%d to LEB %d (waste %d bytes)",
- wbuf->lnum, wbuf->offs + wbuf->used, gc_lnum,
- c->leb_size - wbuf->offs - wbuf->used);
-
- err = ubifs_wbuf_sync_nolock(wbuf);
- if (err)
- return err;
-
- /*
- * The GC write-buffer was synchronized, we may safely unmap
- * 'c->gc_lnum'.
- */
- err = ubifs_leb_unmap(c, gc_lnum);
- if (err)
- return err;
-
- err = ubifs_wbuf_sync_nolock(wbuf);
- if (err)
- return err;
-
- err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0);
- if (err)
- return err;
-
- c->gc_lnum = -1;
- err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0);
- return err;
-}
-
-/**
- * data_nodes_cmp - compare 2 data nodes.
- * @priv: UBIFS file-system description object
- * @a: first data node
- * @a: second data node
- *
- * This function compares data nodes @a and @b. Returns %1 if @a has greater
- * inode or block number, and %-1 otherwise.
- */
-static int data_nodes_cmp(void *priv, struct list_head *a, struct list_head *b)
-{
- ino_t inuma, inumb;
- struct ubifs_info *c = priv;
- struct ubifs_scan_node *sa, *sb;
-
- cond_resched();
- if (a == b)
- return 0;
-
- sa = list_entry(a, struct ubifs_scan_node, list);
- sb = list_entry(b, struct ubifs_scan_node, list);
-
- ubifs_assert(key_type(c, &sa->key) == UBIFS_DATA_KEY);
- ubifs_assert(key_type(c, &sb->key) == UBIFS_DATA_KEY);
- ubifs_assert(sa->type == UBIFS_DATA_NODE);
- ubifs_assert(sb->type == UBIFS_DATA_NODE);
-
- inuma = key_inum(c, &sa->key);
- inumb = key_inum(c, &sb->key);
-
- if (inuma == inumb) {
- unsigned int blka = key_block(c, &sa->key);
- unsigned int blkb = key_block(c, &sb->key);
-
- if (blka <= blkb)
- return -1;
- } else if (inuma <= inumb)
- return -1;
-
- return 1;
-}
-
-/*
- * nondata_nodes_cmp - compare 2 non-data nodes.
- * @priv: UBIFS file-system description object
- * @a: first node
- * @a: second node
- *
- * This function compares nodes @a and @b. It makes sure that inode nodes go
- * first and sorted by length in descending order. Directory entry nodes go
- * after inode nodes and are sorted in ascending hash valuer order.
- */
-static int nondata_nodes_cmp(void *priv, struct list_head *a,
- struct list_head *b)
-{
- ino_t inuma, inumb;
- struct ubifs_info *c = priv;
- struct ubifs_scan_node *sa, *sb;
-
- cond_resched();
- if (a == b)
- return 0;
-
- sa = list_entry(a, struct ubifs_scan_node, list);
- sb = list_entry(b, struct ubifs_scan_node, list);
-
- ubifs_assert(key_type(c, &sa->key) != UBIFS_DATA_KEY &&
- key_type(c, &sb->key) != UBIFS_DATA_KEY);
- ubifs_assert(sa->type != UBIFS_DATA_NODE &&
- sb->type != UBIFS_DATA_NODE);
-
- /* Inodes go before directory entries */
- if (sa->type == UBIFS_INO_NODE) {
- if (sb->type == UBIFS_INO_NODE)
- return sb->len - sa->len;
- return -1;
- }
- if (sb->type == UBIFS_INO_NODE)
- return 1;
-
- ubifs_assert(key_type(c, &sa->key) == UBIFS_DENT_KEY ||
- key_type(c, &sa->key) == UBIFS_XENT_KEY);
- ubifs_assert(key_type(c, &sb->key) == UBIFS_DENT_KEY ||
- key_type(c, &sb->key) == UBIFS_XENT_KEY);
- ubifs_assert(sa->type == UBIFS_DENT_NODE ||
- sa->type == UBIFS_XENT_NODE);
- ubifs_assert(sb->type == UBIFS_DENT_NODE ||
- sb->type == UBIFS_XENT_NODE);
-
- inuma = key_inum(c, &sa->key);
- inumb = key_inum(c, &sb->key);
-
- if (inuma == inumb) {
- uint32_t hasha = key_hash(c, &sa->key);
- uint32_t hashb = key_hash(c, &sb->key);
-
- if (hasha <= hashb)
- return -1;
- } else if (inuma <= inumb)
- return -1;
-
- return 1;
-}
-
-/**
- * sort_nodes - sort nodes for GC.
- * @c: UBIFS file-system description object
- * @sleb: describes nodes to sort and contains the result on exit
- * @nondata: contains non-data nodes on exit
- * @min: minimum node size is returned here
- *
- * This function sorts the list of inodes to garbage collect. First of all, it
- * kills obsolete nodes and separates data and non-data nodes to the
- * @sleb->nodes and @nondata lists correspondingly.
- *
- * Data nodes are then sorted in block number order - this is important for
- * bulk-read; data nodes with lower inode number go before data nodes with
- * higher inode number, and data nodes with lower block number go before data
- * nodes with higher block number;
- *
- * Non-data nodes are sorted as follows.
- * o First go inode nodes - they are sorted in descending length order.
- * o Then go directory entry nodes - they are sorted in hash order, which
- * should supposedly optimize 'readdir()'. Direntry nodes with lower parent
- * inode number go before direntry nodes with higher parent inode number,
- * and direntry nodes with lower name hash values go before direntry nodes
- * with higher name hash values.
- *
- * This function returns zero in case of success and a negative error code in
- * case of failure.
- */
-static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
- struct list_head *nondata, int *min)
-{
- int err;
- struct ubifs_scan_node *snod, *tmp;
-
- *min = INT_MAX;
-
- /* Separate data nodes and non-data nodes */
- list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
- ubifs_assert(snod->type == UBIFS_INO_NODE ||
- snod->type == UBIFS_DATA_NODE ||
- snod->type == UBIFS_DENT_NODE ||
- snod->type == UBIFS_XENT_NODE ||
- snod->type == UBIFS_TRUN_NODE);
-
- if (snod->type != UBIFS_INO_NODE &&
- snod->type != UBIFS_DATA_NODE &&
- snod->type != UBIFS_DENT_NODE &&
- snod->type != UBIFS_XENT_NODE) {
- /* Probably truncation node, zap it */
- list_del(&snod->list);
- kfree(snod);
- continue;
- }
-
- ubifs_assert(key_type(c, &snod->key) == UBIFS_DATA_KEY ||
- key_type(c, &snod->key) == UBIFS_INO_KEY ||
- key_type(c, &snod->key) == UBIFS_DENT_KEY ||
- key_type(c, &snod->key) == UBIFS_XENT_KEY);
-
- err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum,
- snod->offs, 0);
- if (err < 0)
- return err;
-
- if (!err) {
- /* The node is obsolete, remove it from the list */
- list_del(&snod->list);
- kfree(snod);
- continue;
- }
-
- if (snod->len < *min)
- *min = snod->len;
-
- if (key_type(c, &snod->key) != UBIFS_DATA_KEY)
- list_move_tail(&snod->list, nondata);
- }
-
- /* Sort data and non-data nodes */
- list_sort(c, &sleb->nodes, &data_nodes_cmp);
- list_sort(c, nondata, &nondata_nodes_cmp);
-
- err = dbg_check_data_nodes_order(c, &sleb->nodes);
- if (err)
- return err;
- err = dbg_check_nondata_nodes_order(c, nondata);
- if (err)
- return err;
- return 0;
-}
-
-/**
- * move_node - move a node.
- * @c: UBIFS file-system description object
- * @sleb: describes the LEB to move nodes from
- * @snod: the mode to move
- * @wbuf: write-buffer to move node to
- *
- * This function moves node @snod to @wbuf, changes TNC correspondingly, and
- * destroys @snod. Returns zero in case of success and a negative error code in
- * case of failure.
- */
-static int move_node(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
- struct ubifs_scan_node *snod, struct ubifs_wbuf *wbuf)
-{
- int err, new_lnum = wbuf->lnum, new_offs = wbuf->offs + wbuf->used;
-
- cond_resched();
- err = ubifs_wbuf_write_nolock(wbuf, snod->node, snod->len);
- if (err)
- return err;
-
- err = ubifs_tnc_replace(c, &snod->key, sleb->lnum,
- snod->offs, new_lnum, new_offs,
- snod->len);
- list_del(&snod->list);
- kfree(snod);
- return err;
-}
-
-/**
- * move_nodes - move nodes.
- * @c: UBIFS file-system description object
- * @sleb: describes the LEB to move nodes from
- *
- * This function moves valid nodes from data LEB described by @sleb to the GC
- * journal head. This function returns zero in case of success, %-EAGAIN if
- * commit is required, and other negative error codes in case of other
- * failures.
- */
-static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb)
-{
- int err, min;
- LIST_HEAD(nondata);
- struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
-
- if (wbuf->lnum == -1) {
- /*
- * The GC journal head is not set, because it is the first GC
- * invocation since mount.
- */
- err = switch_gc_head(c);
- if (err)
- return err;
- }
-
- err = sort_nodes(c, sleb, &nondata, &min);
- if (err)
- goto out;
-
- /* Write nodes to their new location. Use the first-fit strategy */
- while (1) {
- int avail;
- struct ubifs_scan_node *snod, *tmp;
-
- /* Move data nodes */
- list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) {
- avail = c->leb_size - wbuf->offs - wbuf->used;
- if (snod->len > avail)
- /*
- * Do not skip data nodes in order to optimize
- * bulk-read.
- */
- break;
-
- err = move_node(c, sleb, snod, wbuf);
- if (err)
- goto out;
- }
-
- /* Move non-data nodes */
- list_for_each_entry_safe(snod, tmp, &nondata, list) {
- avail = c->leb_size - wbuf->offs - wbuf->used;
- if (avail < min)
- break;
-
- if (snod->len > avail) {
- /*
- * Keep going only if this is an inode with
- * some data. Otherwise stop and switch the GC
- * head. IOW, we assume that data-less inode
- * nodes and direntry nodes are roughly of the
- * same size.
- */
- if (key_type(c, &snod->key) == UBIFS_DENT_KEY ||
- snod->len == UBIFS_INO_NODE_SZ)
- break;
- continue;
- }
-
- err = move_node(c, sleb, snod, wbuf);
- if (err)
- goto out;
- }
-
- if (list_empty(&sleb->nodes) && list_empty(&nondata))
- break;
-
- /*
- * Waste the rest of the space in the LEB and switch to the
- * next LEB.
- */
- err = switch_gc_head(c);
- if (err)
- goto out;
- }
-
- return 0;
-
-out:
- list_splice_tail(&nondata, &sleb->nodes);
- return err;
-}
-
-/**
- * gc_sync_wbufs - sync write-buffers for GC.
- * @c: UBIFS file-system description object
- *
- * We must guarantee that obsoleting nodes are on flash. Unfortunately they may
- * be in a write-buffer instead. That is, a node could be written to a
- * write-buffer, obsoleting another node in a LEB that is GC'd. If that LEB is
- * erased before the write-buffer is sync'd and then there is an unclean
- * unmount, then an existing node is lost. To avoid this, we sync all
- * write-buffers.
- *
- * This function returns %0 on success or a negative error code on failure.
- */
-static int gc_sync_wbufs(struct ubifs_info *c)
-{
- int err, i;
-
- for (i = 0; i < c->jhead_cnt; i++) {
- if (i == GCHD)
- continue;
- err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
- if (err)
- return err;
- }
- return 0;
-}
-
-/**
- * ubifs_garbage_collect_leb - garbage-collect a logical eraseblock.
- * @c: UBIFS file-system description object
- * @lp: describes the LEB to garbage collect
- *
- * This function garbage-collects an LEB and returns one of the @LEB_FREED,
- * @LEB_RETAINED, etc positive codes in case of success, %-EAGAIN if commit is
- * required, and other negative error codes in case of failures.
- */
-int ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp)
-{
- struct ubifs_scan_leb *sleb;
- struct ubifs_scan_node *snod;
- struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
- int err = 0, lnum = lp->lnum;
-
- ubifs_assert(c->gc_lnum != -1 || wbuf->offs + wbuf->used == 0 ||
- c->need_recovery);
- ubifs_assert(c->gc_lnum != lnum);
- ubifs_assert(wbuf->lnum != lnum);
-
- if (lp->free + lp->dirty == c->leb_size) {
- /* Special case - a free LEB */
- dbg_gc("LEB %d is free, return it", lp->lnum);
- ubifs_assert(!(lp->flags & LPROPS_INDEX));
-
- if (lp->free != c->leb_size) {
- /*
- * Write buffers must be sync'd before unmapping
- * freeable LEBs, because one of them may contain data
- * which obsoletes something in 'lp->pnum'.
- */
- err = gc_sync_wbufs(c);
- if (err)
- return err;
- err = ubifs_change_one_lp(c, lp->lnum, c->leb_size,
- 0, 0, 0, 0);
- if (err)
- return err;
- }
- err = ubifs_leb_unmap(c, lp->lnum);
- if (err)
- return err;
-
- if (c->gc_lnum == -1) {
- c->gc_lnum = lnum;
- return LEB_RETAINED;
- }
-
- return LEB_FREED;
- }
-
- /*
- * We scan the entire LEB even though we only really need to scan up to
- * (c->leb_size - lp->free).
- */
- sleb = ubifs_scan(c, lnum, 0, c->sbuf, 0);
- if (IS_ERR(sleb))
- return PTR_ERR(sleb);
-
- ubifs_assert(!list_empty(&sleb->nodes));
- snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list);
-
- if (snod->type == UBIFS_IDX_NODE) {
- struct ubifs_gced_idx_leb *idx_gc;
-
- dbg_gc("indexing LEB %d (free %d, dirty %d)",
- lnum, lp->free, lp->dirty);
- list_for_each_entry(snod, &sleb->nodes, list) {
- struct ubifs_idx_node *idx = snod->node;
- int level = le16_to_cpu(idx->level);
-
- ubifs_assert(snod->type == UBIFS_IDX_NODE);
- key_read(c, ubifs_idx_key(c, idx), &snod->key);
- err = ubifs_dirty_idx_node(c, &snod->key, level, lnum,
- snod->offs);
- if (err)
- goto out;
- }
-
- idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS);
- if (!idx_gc) {
- err = -ENOMEM;
- goto out;
- }
-
- idx_gc->lnum = lnum;
- idx_gc->unmap = 0;
- list_add(&idx_gc->list, &c->idx_gc);
-
- /*
- * Don't release the LEB until after the next commit, because
- * it may contain data which is needed for recovery. So
- * although we freed this LEB, it will become usable only after
- * the commit.
- */
- err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0,
- LPROPS_INDEX, 1);
- if (err)
- goto out;
- err = LEB_FREED_IDX;
- } else {
- dbg_gc("data LEB %d (free %d, dirty %d)",
- lnum, lp->free, lp->dirty);
-
- err = move_nodes(c, sleb);
- if (err)
- goto out_inc_seq;
-
- err = gc_sync_wbufs(c);
- if (err)
- goto out_inc_seq;
-
- err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0, 0, 0);
- if (err)
- goto out_inc_seq;
-
- /* Allow for races with TNC */
- c->gced_lnum = lnum;
- smp_wmb();
- c->gc_seq += 1;
- smp_wmb();
-
- if (c->gc_lnum == -1) {
- c->gc_lnum = lnum;
- err = LEB_RETAINED;
- } else {
- err = ubifs_wbuf_sync_nolock(wbuf);
- if (err)
- goto out;
-
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- goto out;
-
- err = LEB_FREED;
- }
- }
-
-out:
- ubifs_scan_destroy(sleb);
- return err;
-
-out_inc_seq:
- /* We may have moved at least some nodes so allow for races with TNC */
- c->gced_lnum = lnum;
- smp_wmb();
- c->gc_seq += 1;
- smp_wmb();
- goto out;
-}
-
-/**
- * ubifs_garbage_collect - UBIFS garbage collector.
- * @c: UBIFS file-system description object
- * @anyway: do GC even if there are free LEBs
- *
- * This function does out-of-place garbage collection. The return codes are:
- * o positive LEB number if the LEB has been freed and may be used;
- * o %-EAGAIN if the caller has to run commit;
- * o %-ENOSPC if GC failed to make any progress;
- * o other negative error codes in case of other errors.
- *
- * Garbage collector writes data to the journal when GC'ing data LEBs, and just
- * marking indexing nodes dirty when GC'ing indexing LEBs. Thus, at some point
- * commit may be required. But commit cannot be run from inside GC, because the
- * caller might be holding the commit lock, so %-EAGAIN is returned instead;
- * And this error code means that the caller has to run commit, and re-run GC
- * if there is still no free space.
- *
- * There are many reasons why this function may return %-EAGAIN:
- * o the log is full and there is no space to write an LEB reference for
- * @c->gc_lnum;
- * o the journal is too large and exceeds size limitations;
- * o GC moved indexing LEBs, but they can be used only after the commit;
- * o the shrinker fails to find clean znodes to free and requests the commit;
- * o etc.
- *
- * Note, if the file-system is close to be full, this function may return
- * %-EAGAIN infinitely, so the caller has to limit amount of re-invocations of
- * the function. E.g., this happens if the limits on the journal size are too
- * tough and GC writes too much to the journal before an LEB is freed. This
- * might also mean that the journal is too large, and the TNC becomes to big,
- * so that the shrinker is constantly called, finds not clean znodes to free,
- * and requests commit. Well, this may also happen if the journal is all right,
- * but another kernel process consumes too much memory. Anyway, infinite
- * %-EAGAIN may happen, but in some extreme/misconfiguration cases.
- */
-int ubifs_garbage_collect(struct ubifs_info *c, int anyway)
-{
- int i, err, ret, min_space = c->dead_wm;
- struct ubifs_lprops lp;
- struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
-
- ubifs_assert_cmt_locked(c);
- ubifs_assert(!c->ro_media && !c->ro_mount);
-
- if (ubifs_gc_should_commit(c))
- return -EAGAIN;
-
- mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
-
- if (c->ro_error) {
- ret = -EROFS;
- goto out_unlock;
- }
-
- /* We expect the write-buffer to be empty on entry */
- ubifs_assert(!wbuf->used);
-
- for (i = 0; ; i++) {
- int space_before, space_after;
-
- cond_resched();
-
- /* Give the commit an opportunity to run */
- if (ubifs_gc_should_commit(c)) {
- ret = -EAGAIN;
- break;
- }
-
- if (i > SOFT_LEBS_LIMIT && !list_empty(&c->idx_gc)) {
- /*
- * We've done enough iterations. Indexing LEBs were
- * moved and will be available after the commit.
- */
- dbg_gc("soft limit, some index LEBs GC'ed, -EAGAIN");
- ubifs_commit_required(c);
- ret = -EAGAIN;
- break;
- }
-
- if (i > HARD_LEBS_LIMIT) {
- /*
- * We've moved too many LEBs and have not made
- * progress, give up.
- */
- dbg_gc("hard limit, -ENOSPC");
- ret = -ENOSPC;
- break;
- }
-
- /*
- * Empty and freeable LEBs can turn up while we waited for
- * the wbuf lock, or while we have been running GC. In that
- * case, we should just return one of those instead of
- * continuing to GC dirty LEBs. Hence we request
- * 'ubifs_find_dirty_leb()' to return an empty LEB if it can.
- */
- ret = ubifs_find_dirty_leb(c, &lp, min_space, anyway ? 0 : 1);
- if (ret) {
- if (ret == -ENOSPC)
- dbg_gc("no more dirty LEBs");
- break;
- }
-
- dbg_gc("found LEB %d: free %d, dirty %d, sum %d (min. space %d)",
- lp.lnum, lp.free, lp.dirty, lp.free + lp.dirty,
- min_space);
-
- space_before = c->leb_size - wbuf->offs - wbuf->used;
- if (wbuf->lnum == -1)
- space_before = 0;
-
- ret = ubifs_garbage_collect_leb(c, &lp);
- if (ret < 0) {
- if (ret == -EAGAIN) {
- /*
- * This is not error, so we have to return the
- * LEB to lprops. But if 'ubifs_return_leb()'
- * fails, its failure code is propagated to the
- * caller instead of the original '-EAGAIN'.
- */
- err = ubifs_return_leb(c, lp.lnum);
- if (err)
- ret = err;
- break;
- }
- goto out;
- }
-
- if (ret == LEB_FREED) {
- /* An LEB has been freed and is ready for use */
- dbg_gc("LEB %d freed, return", lp.lnum);
- ret = lp.lnum;
- break;
- }
-
- if (ret == LEB_FREED_IDX) {
- /*
- * This was an indexing LEB and it cannot be
- * immediately used. And instead of requesting the
- * commit straight away, we try to garbage collect some
- * more.
- */
- dbg_gc("indexing LEB %d freed, continue", lp.lnum);
- continue;
- }
-
- ubifs_assert(ret == LEB_RETAINED);
- space_after = c->leb_size - wbuf->offs - wbuf->used;
- dbg_gc("LEB %d retained, freed %d bytes", lp.lnum,
- space_after - space_before);
-
- if (space_after > space_before) {
- /* GC makes progress, keep working */
- min_space >>= 1;
- if (min_space < c->dead_wm)
- min_space = c->dead_wm;
- continue;
- }
-
- dbg_gc("did not make progress");
-
- /*
- * GC moved an LEB bud have not done any progress. This means
- * that the previous GC head LEB contained too few free space
- * and the LEB which was GC'ed contained only large nodes which
- * did not fit that space.
- *
- * We can do 2 things:
- * 1. pick another LEB in a hope it'll contain a small node
- * which will fit the space we have at the end of current GC
- * head LEB, but there is no guarantee, so we try this out
- * unless we have already been working for too long;
- * 2. request an LEB with more dirty space, which will force
- * 'ubifs_find_dirty_leb()' to start scanning the lprops
- * table, instead of just picking one from the heap
- * (previously it already picked the dirtiest LEB).
- */
- if (i < SOFT_LEBS_LIMIT) {
- dbg_gc("try again");
- continue;
- }
-
- min_space <<= 1;
- if (min_space > c->dark_wm)
- min_space = c->dark_wm;
- dbg_gc("set min. space to %d", min_space);
- }
-
- if (ret == -ENOSPC && !list_empty(&c->idx_gc)) {
- dbg_gc("no space, some index LEBs GC'ed, -EAGAIN");
- ubifs_commit_required(c);
- ret = -EAGAIN;
- }
-
- err = ubifs_wbuf_sync_nolock(wbuf);
- if (!err)
- err = ubifs_leb_unmap(c, c->gc_lnum);
- if (err) {
- ret = err;
- goto out;
- }
-out_unlock:
- mutex_unlock(&wbuf->io_mutex);
- return ret;
-
-out:
- ubifs_assert(ret < 0);
- ubifs_assert(ret != -ENOSPC && ret != -EAGAIN);
- ubifs_wbuf_sync_nolock(wbuf);
- ubifs_ro_mode(c, ret);
- mutex_unlock(&wbuf->io_mutex);
- ubifs_return_leb(c, lp.lnum);
- return ret;
-}
-
-/**
- * ubifs_gc_start_commit - garbage collection at start of commit.
- * @c: UBIFS file-system description object
- *
- * If a LEB has only dirty and free space, then we may safely unmap it and make
- * it free. Note, we cannot do this with indexing LEBs because dirty space may
- * correspond index nodes that are required for recovery. In that case, the
- * LEB cannot be unmapped until after the next commit.
- *
- * This function returns %0 upon success and a negative error code upon failure.
- */
-int ubifs_gc_start_commit(struct ubifs_info *c)
-{
- struct ubifs_gced_idx_leb *idx_gc;
- const struct ubifs_lprops *lp;
- int err = 0, flags;
-
- ubifs_get_lprops(c);
-
- /*
- * Unmap (non-index) freeable LEBs. Note that recovery requires that all
- * wbufs are sync'd before this, which is done in 'do_commit()'.
- */
- while (1) {
- lp = ubifs_fast_find_freeable(c);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- goto out;
- }
- if (!lp)
- break;
- ubifs_assert(!(lp->flags & LPROPS_TAKEN));
- ubifs_assert(!(lp->flags & LPROPS_INDEX));
- err = ubifs_leb_unmap(c, lp->lnum);
- if (err)
- goto out;
- lp = ubifs_change_lp(c, lp, c->leb_size, 0, lp->flags, 0);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- goto out;
- }
- ubifs_assert(!(lp->flags & LPROPS_TAKEN));
- ubifs_assert(!(lp->flags & LPROPS_INDEX));
- }
-
- /* Mark GC'd index LEBs OK to unmap after this commit finishes */
- list_for_each_entry(idx_gc, &c->idx_gc, list)
- idx_gc->unmap = 1;
-
- /* Record index freeable LEBs for unmapping after commit */
- while (1) {
- lp = ubifs_fast_find_frdi_idx(c);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- goto out;
- }
- if (!lp)
- break;
- idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS);
- if (!idx_gc) {
- err = -ENOMEM;
- goto out;
- }
- ubifs_assert(!(lp->flags & LPROPS_TAKEN));
- ubifs_assert(lp->flags & LPROPS_INDEX);
- /* Don't release the LEB until after the next commit */
- flags = (lp->flags | LPROPS_TAKEN) ^ LPROPS_INDEX;
- lp = ubifs_change_lp(c, lp, c->leb_size, 0, flags, 1);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- kfree(idx_gc);
- goto out;
- }
- ubifs_assert(lp->flags & LPROPS_TAKEN);
- ubifs_assert(!(lp->flags & LPROPS_INDEX));
- idx_gc->lnum = lp->lnum;
- idx_gc->unmap = 1;
- list_add(&idx_gc->list, &c->idx_gc);
- }
-out:
- ubifs_release_lprops(c);
- return err;
-}
-
-/**
- * ubifs_gc_end_commit - garbage collection at end of commit.
- * @c: UBIFS file-system description object
- *
- * This function completes out-of-place garbage collection of index LEBs.
- */
-int ubifs_gc_end_commit(struct ubifs_info *c)
-{
- struct ubifs_gced_idx_leb *idx_gc, *tmp;
- struct ubifs_wbuf *wbuf;
- int err = 0;
-
- wbuf = &c->jheads[GCHD].wbuf;
- mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
- list_for_each_entry_safe(idx_gc, tmp, &c->idx_gc, list)
- if (idx_gc->unmap) {
- dbg_gc("LEB %d", idx_gc->lnum);
- err = ubifs_leb_unmap(c, idx_gc->lnum);
- if (err)
- goto out;
- err = ubifs_change_one_lp(c, idx_gc->lnum, LPROPS_NC,
- LPROPS_NC, 0, LPROPS_TAKEN, -1);
- if (err)
- goto out;
- list_del(&idx_gc->list);
- kfree(idx_gc);
- }
-out:
- mutex_unlock(&wbuf->io_mutex);
- return err;
-}
-#endif
-/**
- * ubifs_destroy_idx_gc - destroy idx_gc list.
- * @c: UBIFS file-system description object
- *
- * This function destroys the @c->idx_gc list. It is called when unmounting
- * so locks are not needed. Returns zero in case of success and a negative
- * error code in case of failure.
- */
-void ubifs_destroy_idx_gc(struct ubifs_info *c)
-{
- while (!list_empty(&c->idx_gc)) {
- struct ubifs_gced_idx_leb *idx_gc;
-
- idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb,
- list);
- c->idx_gc_cnt -= 1;
- list_del(&idx_gc->list);
- kfree(idx_gc);
- }
-}
-#ifndef __BAREBOX__
-/**
- * ubifs_get_idx_gc_leb - get a LEB from GC'd index LEB list.
- * @c: UBIFS file-system description object
- *
- * Called during start commit so locks are not needed.
- */
-int ubifs_get_idx_gc_leb(struct ubifs_info *c)
-{
- struct ubifs_gced_idx_leb *idx_gc;
- int lnum;
-
- if (list_empty(&c->idx_gc))
- return -ENOSPC;
- idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, list);
- lnum = idx_gc->lnum;
- /* c->idx_gc_cnt is updated by the caller when lprops are updated */
- list_del(&idx_gc->list);
- kfree(idx_gc);
- return lnum;
-}
-#endif
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index 0abe7317b8..08d4e20bda 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -59,12 +59,7 @@
* they are read from the flash media.
*/
-#ifndef __BAREBOX__
-#include <linux/crc32.h>
-#include <linux/slab.h>
-#else
#include <linux/err.h>
-#endif
#include "ubifs.h"
/**
@@ -107,93 +102,6 @@ int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
return err;
}
-int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
- int len)
-{
- int err;
-
- ubifs_assert(!c->ro_media && !c->ro_mount);
- if (c->ro_error)
- return -EROFS;
- if (!dbg_is_tst_rcvry(c))
- err = ubi_leb_write(c->ubi, lnum, buf, offs, len);
-#ifndef __BAREBOX__
- else
- err = dbg_leb_write(c, lnum, buf, offs, len);
-#endif
- if (err) {
- ubifs_err(c, "writing %d bytes to LEB %d:%d failed, error %d",
- len, lnum, offs, err);
- ubifs_ro_mode(c, err);
- dump_stack();
- }
- return err;
-}
-
-int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len)
-{
- int err;
-
- ubifs_assert(!c->ro_media && !c->ro_mount);
- if (c->ro_error)
- return -EROFS;
- if (!dbg_is_tst_rcvry(c))
- err = ubi_leb_change(c->ubi, lnum, buf, len);
-#ifndef __BAREBOX__
- else
- err = dbg_leb_change(c, lnum, buf, len);
-#endif
- if (err) {
- ubifs_err(c, "changing %d bytes in LEB %d failed, error %d",
- len, lnum, err);
- ubifs_ro_mode(c, err);
- dump_stack();
- }
- return err;
-}
-
-int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
-{
- int err;
-
- ubifs_assert(!c->ro_media && !c->ro_mount);
- if (c->ro_error)
- return -EROFS;
- if (!dbg_is_tst_rcvry(c))
- err = ubi_leb_unmap(c->ubi, lnum);
-#ifndef __BAREBOX__
- else
- err = dbg_leb_unmap(c, lnum);
-#endif
- if (err) {
- ubifs_err(c, "unmap LEB %d failed, error %d", lnum, err);
- ubifs_ro_mode(c, err);
- dump_stack();
- }
- return err;
-}
-
-int ubifs_leb_map(struct ubifs_info *c, int lnum)
-{
- int err;
-
- ubifs_assert(!c->ro_media && !c->ro_mount);
- if (c->ro_error)
- return -EROFS;
- if (!dbg_is_tst_rcvry(c))
- err = ubi_leb_map(c->ubi, lnum);
-#ifndef __BAREBOX__
- else
- err = dbg_leb_map(c, lnum);
-#endif
- if (err) {
- ubifs_err(c, "mapping LEB %d failed, error %d", lnum, err);
- ubifs_ro_mode(c, err);
- dump_stack();
- }
- return err;
-}
-
int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
{
int err;
@@ -342,629 +250,6 @@ void ubifs_pad(const struct ubifs_info *c, void *buf, int pad)
memset(buf, UBIFS_PADDING_BYTE, pad);
}
-/**
- * next_sqnum - get next sequence number.
- * @c: UBIFS file-system description object
- */
-static unsigned long long next_sqnum(struct ubifs_info *c)
-{
- unsigned long long sqnum;
-
- spin_lock(&c->cnt_lock);
- sqnum = ++c->max_sqnum;
- spin_unlock(&c->cnt_lock);
-
- if (unlikely(sqnum >= SQNUM_WARN_WATERMARK)) {
- if (sqnum >= SQNUM_WATERMARK) {
- ubifs_err(c, "sequence number overflow %llu, end of life",
- sqnum);
- ubifs_ro_mode(c, -EINVAL);
- }
- ubifs_warn(c, "running out of sequence numbers, end of life soon");
- }
-
- return sqnum;
-}
-
-/**
- * ubifs_prepare_node - prepare node to be written to flash.
- * @c: UBIFS file-system description object
- * @node: the node to pad
- * @len: node length
- * @pad: if the buffer has to be padded
- *
- * This function prepares node at @node to be written to the media - it
- * calculates node CRC, fills the common header, and adds proper padding up to
- * the next minimum I/O unit if @pad is not zero.
- */
-void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
-{
- uint32_t crc;
- struct ubifs_ch *ch = node;
- unsigned long long sqnum = next_sqnum(c);
-
- ubifs_assert(len >= UBIFS_CH_SZ);
-
- ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
- ch->len = cpu_to_le32(len);
- ch->group_type = UBIFS_NO_NODE_GROUP;
- ch->sqnum = cpu_to_le64(sqnum);
- ch->padding[0] = ch->padding[1] = 0;
- crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
- ch->crc = cpu_to_le32(crc);
-
- if (pad) {
- len = ALIGN(len, 8);
- pad = ALIGN(len, c->min_io_size) - len;
- ubifs_pad(c, node + len, pad);
- }
-}
-
-/**
- * ubifs_prep_grp_node - prepare node of a group to be written to flash.
- * @c: UBIFS file-system description object
- * @node: the node to pad
- * @len: node length
- * @last: indicates the last node of the group
- *
- * This function prepares node at @node to be written to the media - it
- * calculates node CRC and fills the common header.
- */
-void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last)
-{
- uint32_t crc;
- struct ubifs_ch *ch = node;
- unsigned long long sqnum = next_sqnum(c);
-
- ubifs_assert(len >= UBIFS_CH_SZ);
-
- ch->magic = cpu_to_le32(UBIFS_NODE_MAGIC);
- ch->len = cpu_to_le32(len);
- if (last)
- ch->group_type = UBIFS_LAST_OF_NODE_GROUP;
- else
- ch->group_type = UBIFS_IN_NODE_GROUP;
- ch->sqnum = cpu_to_le64(sqnum);
- ch->padding[0] = ch->padding[1] = 0;
- crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8);
- ch->crc = cpu_to_le32(crc);
-}
-
-#ifndef __BAREBOX__
-/**
- * wbuf_timer_callback - write-buffer timer callback function.
- * @timer: timer data (write-buffer descriptor)
- *
- * This function is called when the write-buffer timer expires.
- */
-static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer)
-{
- struct ubifs_wbuf *wbuf = container_of(timer, struct ubifs_wbuf, timer);
-
- dbg_io("jhead %s", dbg_jhead(wbuf->jhead));
- wbuf->need_sync = 1;
- wbuf->c->need_wbuf_sync = 1;
- ubifs_wake_up_bgt(wbuf->c);
- return HRTIMER_NORESTART;
-}
-
-/**
- * new_wbuf_timer - start new write-buffer timer.
- * @wbuf: write-buffer descriptor
- */
-static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
-{
- ubifs_assert(!hrtimer_active(&wbuf->timer));
-
- if (wbuf->no_timer)
- return;
- dbg_io("set timer for jhead %s, %llu-%llu millisecs",
- dbg_jhead(wbuf->jhead),
- div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC),
- div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta,
- USEC_PER_SEC));
- hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
- HRTIMER_MODE_REL);
-}
-#endif
-
-/**
- * cancel_wbuf_timer - cancel write-buffer timer.
- * @wbuf: write-buffer descriptor
- */
-static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
-{
- if (wbuf->no_timer)
- return;
- wbuf->need_sync = 0;
-#ifndef __BAREBOX__
- hrtimer_cancel(&wbuf->timer);
-#endif
-}
-
-/**
- * ubifs_wbuf_sync_nolock - synchronize write-buffer.
- * @wbuf: write-buffer to synchronize
- *
- * This function synchronizes write-buffer @buf and returns zero in case of
- * success or a negative error code in case of failure.
- *
- * Note, although write-buffers are of @c->max_write_size, this function does
- * not necessarily writes all @c->max_write_size bytes to the flash. Instead,
- * if the write-buffer is only partially filled with data, only the used part
- * of the write-buffer (aligned on @c->min_io_size boundary) is synchronized.
- * This way we waste less space.
- */
-int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
-{
- struct ubifs_info *c = wbuf->c;
- int err, dirt, sync_len;
-
- cancel_wbuf_timer_nolock(wbuf);
- if (!wbuf->used || wbuf->lnum == -1)
- /* Write-buffer is empty or not seeked */
- return 0;
-
- dbg_io("LEB %d:%d, %d bytes, jhead %s",
- wbuf->lnum, wbuf->offs, wbuf->used, dbg_jhead(wbuf->jhead));
- ubifs_assert(!(wbuf->avail & 7));
- ubifs_assert(wbuf->offs + wbuf->size <= c->leb_size);
- ubifs_assert(wbuf->size >= c->min_io_size);
- ubifs_assert(wbuf->size <= c->max_write_size);
- ubifs_assert(wbuf->size % c->min_io_size == 0);
- ubifs_assert(!c->ro_media && !c->ro_mount);
- if (c->leb_size - wbuf->offs >= c->max_write_size)
- ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
-
- if (c->ro_error)
- return -EROFS;
-
- /*
- * Do not write whole write buffer but write only the minimum necessary
- * amount of min. I/O units.
- */
- sync_len = ALIGN(wbuf->used, c->min_io_size);
- dirt = sync_len - wbuf->used;
- if (dirt)
- ubifs_pad(c, wbuf->buf + wbuf->used, dirt);
- err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs, sync_len);
- if (err)
- return err;
-
- spin_lock(&wbuf->lock);
- wbuf->offs += sync_len;
- /*
- * Now @wbuf->offs is not necessarily aligned to @c->max_write_size.
- * But our goal is to optimize writes and make sure we write in
- * @c->max_write_size chunks and to @c->max_write_size-aligned offset.
- * Thus, if @wbuf->offs is not aligned to @c->max_write_size now, make
- * sure that @wbuf->offs + @wbuf->size is aligned to
- * @c->max_write_size. This way we make sure that after next
- * write-buffer flush we are again at the optimal offset (aligned to
- * @c->max_write_size).
- */
- if (c->leb_size - wbuf->offs < c->max_write_size)
- wbuf->size = c->leb_size - wbuf->offs;
- else if (wbuf->offs & (c->max_write_size - 1))
- wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
- else
- wbuf->size = c->max_write_size;
- wbuf->avail = wbuf->size;
- wbuf->used = 0;
- wbuf->next_ino = 0;
- spin_unlock(&wbuf->lock);
-
- if (wbuf->sync_callback)
- err = wbuf->sync_callback(c, wbuf->lnum,
- c->leb_size - wbuf->offs, dirt);
- return err;
-}
-
-/**
- * ubifs_wbuf_seek_nolock - seek write-buffer.
- * @wbuf: write-buffer
- * @lnum: logical eraseblock number to seek to
- * @offs: logical eraseblock offset to seek to
- *
- * This function targets the write-buffer to logical eraseblock @lnum:@offs.
- * The write-buffer has to be empty. Returns zero in case of success and a
- * negative error code in case of failure.
- */
-int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs)
-{
- const struct ubifs_info *c = wbuf->c;
-
- dbg_io("LEB %d:%d, jhead %s", lnum, offs, dbg_jhead(wbuf->jhead));
- ubifs_assert(lnum >= 0 && lnum < c->leb_cnt);
- ubifs_assert(offs >= 0 && offs <= c->leb_size);
- ubifs_assert(offs % c->min_io_size == 0 && !(offs & 7));
- ubifs_assert(lnum != wbuf->lnum);
- ubifs_assert(wbuf->used == 0);
-
- spin_lock(&wbuf->lock);
- wbuf->lnum = lnum;
- wbuf->offs = offs;
- if (c->leb_size - wbuf->offs < c->max_write_size)
- wbuf->size = c->leb_size - wbuf->offs;
- else if (wbuf->offs & (c->max_write_size - 1))
- wbuf->size = ALIGN(wbuf->offs, c->max_write_size) - wbuf->offs;
- else
- wbuf->size = c->max_write_size;
- wbuf->avail = wbuf->size;
- wbuf->used = 0;
- spin_unlock(&wbuf->lock);
-
- return 0;
-}
-
-#ifndef __BAREBOX__
-/**
- * ubifs_bg_wbufs_sync - synchronize write-buffers.
- * @c: UBIFS file-system description object
- *
- * This function is called by background thread to synchronize write-buffers.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- */
-int ubifs_bg_wbufs_sync(struct ubifs_info *c)
-{
- int err, i;
-
- ubifs_assert(!c->ro_media && !c->ro_mount);
- if (!c->need_wbuf_sync)
- return 0;
- c->need_wbuf_sync = 0;
-
- if (c->ro_error) {
- err = -EROFS;
- goto out_timers;
- }
-
- dbg_io("synchronize");
- for (i = 0; i < c->jhead_cnt; i++) {
- struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf;
-
- cond_resched();
-
- /*
- * If the mutex is locked then wbuf is being changed, so
- * synchronization is not necessary.
- */
- if (mutex_is_locked(&wbuf->io_mutex))
- continue;
-
- mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
- if (!wbuf->need_sync) {
- mutex_unlock(&wbuf->io_mutex);
- continue;
- }
-
- err = ubifs_wbuf_sync_nolock(wbuf);
- mutex_unlock(&wbuf->io_mutex);
- if (err) {
- ubifs_err(c, "cannot sync write-buffer, error %d", err);
- ubifs_ro_mode(c, err);
- goto out_timers;
- }
- }
-
- return 0;
-
-out_timers:
- /* Cancel all timers to prevent repeated errors */
- for (i = 0; i < c->jhead_cnt; i++) {
- struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf;
-
- mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
- cancel_wbuf_timer_nolock(wbuf);
- mutex_unlock(&wbuf->io_mutex);
- }
- return err;
-}
-
-/**
- * ubifs_wbuf_write_nolock - write data to flash via write-buffer.
- * @wbuf: write-buffer
- * @buf: node to write
- * @len: node length
- *
- * This function writes data to flash via write-buffer @wbuf. This means that
- * the last piece of the node won't reach the flash media immediately if it
- * does not take whole max. write unit (@c->max_write_size). Instead, the node
- * will sit in RAM until the write-buffer is synchronized (e.g., by timer, or
- * because more data are appended to the write-buffer).
- *
- * This function returns zero in case of success and a negative error code in
- * case of failure. If the node cannot be written because there is no more
- * space in this logical eraseblock, %-ENOSPC is returned.
- */
-int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
-{
- struct ubifs_info *c = wbuf->c;
- int err, written, n, aligned_len = ALIGN(len, 8);
-
- dbg_io("%d bytes (%s) to jhead %s wbuf at LEB %d:%d", len,
- dbg_ntype(((struct ubifs_ch *)buf)->node_type),
- dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs + wbuf->used);
- ubifs_assert(len > 0 && wbuf->lnum >= 0 && wbuf->lnum < c->leb_cnt);
- ubifs_assert(wbuf->offs >= 0 && wbuf->offs % c->min_io_size == 0);
- ubifs_assert(!(wbuf->offs & 7) && wbuf->offs <= c->leb_size);
- ubifs_assert(wbuf->avail > 0 && wbuf->avail <= wbuf->size);
- ubifs_assert(wbuf->size >= c->min_io_size);
- ubifs_assert(wbuf->size <= c->max_write_size);
- ubifs_assert(wbuf->size % c->min_io_size == 0);
- ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
- ubifs_assert(!c->ro_media && !c->ro_mount);
- ubifs_assert(!c->space_fixup);
- if (c->leb_size - wbuf->offs >= c->max_write_size)
- ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
-
- if (c->leb_size - wbuf->offs - wbuf->used < aligned_len) {
- err = -ENOSPC;
- goto out;
- }
-
- cancel_wbuf_timer_nolock(wbuf);
-
- if (c->ro_error)
- return -EROFS;
-
- if (aligned_len <= wbuf->avail) {
- /*
- * The node is not very large and fits entirely within
- * write-buffer.
- */
- memcpy(wbuf->buf + wbuf->used, buf, len);
-
- if (aligned_len == wbuf->avail) {
- dbg_io("flush jhead %s wbuf to LEB %d:%d",
- dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
- err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf,
- wbuf->offs, wbuf->size);
- if (err)
- goto out;
-
- spin_lock(&wbuf->lock);
- wbuf->offs += wbuf->size;
- if (c->leb_size - wbuf->offs >= c->max_write_size)
- wbuf->size = c->max_write_size;
- else
- wbuf->size = c->leb_size - wbuf->offs;
- wbuf->avail = wbuf->size;
- wbuf->used = 0;
- wbuf->next_ino = 0;
- spin_unlock(&wbuf->lock);
- } else {
- spin_lock(&wbuf->lock);
- wbuf->avail -= aligned_len;
- wbuf->used += aligned_len;
- spin_unlock(&wbuf->lock);
- }
-
- goto exit;
- }
-
- written = 0;
-
- if (wbuf->used) {
- /*
- * The node is large enough and does not fit entirely within
- * current available space. We have to fill and flush
- * write-buffer and switch to the next max. write unit.
- */
- dbg_io("flush jhead %s wbuf to LEB %d:%d",
- dbg_jhead(wbuf->jhead), wbuf->lnum, wbuf->offs);
- memcpy(wbuf->buf + wbuf->used, buf, wbuf->avail);
- err = ubifs_leb_write(c, wbuf->lnum, wbuf->buf, wbuf->offs,
- wbuf->size);
- if (err)
- goto out;
-
- wbuf->offs += wbuf->size;
- len -= wbuf->avail;
- aligned_len -= wbuf->avail;
- written += wbuf->avail;
- } else if (wbuf->offs & (c->max_write_size - 1)) {
- /*
- * The write-buffer offset is not aligned to
- * @c->max_write_size and @wbuf->size is less than
- * @c->max_write_size. Write @wbuf->size bytes to make sure the
- * following writes are done in optimal @c->max_write_size
- * chunks.
- */
- dbg_io("write %d bytes to LEB %d:%d",
- wbuf->size, wbuf->lnum, wbuf->offs);
- err = ubifs_leb_write(c, wbuf->lnum, buf, wbuf->offs,
- wbuf->size);
- if (err)
- goto out;
-
- wbuf->offs += wbuf->size;
- len -= wbuf->size;
- aligned_len -= wbuf->size;
- written += wbuf->size;
- }
-
- /*
- * The remaining data may take more whole max. write units, so write the
- * remains multiple to max. write unit size directly to the flash media.
- * We align node length to 8-byte boundary because we anyway flash wbuf
- * if the remaining space is less than 8 bytes.
- */
- n = aligned_len >> c->max_write_shift;
- if (n) {
- n <<= c->max_write_shift;
- dbg_io("write %d bytes to LEB %d:%d", n, wbuf->lnum,
- wbuf->offs);
- err = ubifs_leb_write(c, wbuf->lnum, buf + written,
- wbuf->offs, n);
- if (err)
- goto out;
- wbuf->offs += n;
- aligned_len -= n;
- len -= n;
- written += n;
- }
-
- spin_lock(&wbuf->lock);
- if (aligned_len)
- /*
- * And now we have what's left and what does not take whole
- * max. write unit, so write it to the write-buffer and we are
- * done.
- */
- memcpy(wbuf->buf, buf + written, len);
-
- if (c->leb_size - wbuf->offs >= c->max_write_size)
- wbuf->size = c->max_write_size;
- else
- wbuf->size = c->leb_size - wbuf->offs;
- wbuf->avail = wbuf->size - aligned_len;
- wbuf->used = aligned_len;
- wbuf->next_ino = 0;
- spin_unlock(&wbuf->lock);
-
-exit:
- if (wbuf->sync_callback) {
- int free = c->leb_size - wbuf->offs - wbuf->used;
-
- err = wbuf->sync_callback(c, wbuf->lnum, free, 0);
- if (err)
- goto out;
- }
-
- if (wbuf->used)
- new_wbuf_timer_nolock(wbuf);
-
- return 0;
-
-out:
- ubifs_err(c, "cannot write %d bytes to LEB %d:%d, error %d",
- len, wbuf->lnum, wbuf->offs, err);
- ubifs_dump_node(c, buf);
- dump_stack();
- ubifs_dump_leb(c, wbuf->lnum);
- return err;
-}
-
-/**
- * ubifs_write_node - write node to the media.
- * @c: UBIFS file-system description object
- * @buf: the node to write
- * @len: node length
- * @lnum: logical eraseblock number
- * @offs: offset within the logical eraseblock
- *
- * This function automatically fills node magic number, assigns sequence
- * number, and calculates node CRC checksum. The length of the @buf buffer has
- * to be aligned to the minimal I/O unit size. This function automatically
- * appends padding node and padding bytes if needed. Returns zero in case of
- * success and a negative error code in case of failure.
- */
-int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
- int offs)
-{
- int err, buf_len = ALIGN(len, c->min_io_size);
-
- dbg_io("LEB %d:%d, %s, length %d (aligned %d)",
- lnum, offs, dbg_ntype(((struct ubifs_ch *)buf)->node_type), len,
- buf_len);
- ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
- ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size);
- ubifs_assert(!c->ro_media && !c->ro_mount);
- ubifs_assert(!c->space_fixup);
-
- if (c->ro_error)
- return -EROFS;
-
- ubifs_prepare_node(c, buf, len, 1);
- err = ubifs_leb_write(c, lnum, buf, offs, buf_len);
- if (err)
- ubifs_dump_node(c, buf);
-
- return err;
-}
-#endif
-
-/**
- * ubifs_read_node_wbuf - read node from the media or write-buffer.
- * @wbuf: wbuf to check for un-written data
- * @buf: buffer to read to
- * @type: node type
- * @len: node length
- * @lnum: logical eraseblock number
- * @offs: offset within the logical eraseblock
- *
- * This function reads a node of known type and length, checks it and stores
- * in @buf. If the node partially or fully sits in the write-buffer, this
- * function takes data from the buffer, otherwise it reads the flash media.
- * Returns zero in case of success, %-EUCLEAN if CRC mismatched and a negative
- * error code in case of failure.
- */
-int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
- int lnum, int offs)
-{
- const struct ubifs_info *c = wbuf->c;
- int err, rlen, overlap;
- struct ubifs_ch *ch = buf;
-
- dbg_io("LEB %d:%d, %s, length %d, jhead %s", lnum, offs,
- dbg_ntype(type), len, dbg_jhead(wbuf->jhead));
- ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
- ubifs_assert(!(offs & 7) && offs < c->leb_size);
- ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
-
- spin_lock(&wbuf->lock);
- overlap = (lnum == wbuf->lnum && offs + len > wbuf->offs);
- if (!overlap) {
- /* We may safely unlock the write-buffer and read the data */
- spin_unlock(&wbuf->lock);
- return ubifs_read_node(c, buf, type, len, lnum, offs);
- }
-
- /* Don't read under wbuf */
- rlen = wbuf->offs - offs;
- if (rlen < 0)
- rlen = 0;
-
- /* Copy the rest from the write-buffer */
- memcpy(buf + rlen, wbuf->buf + offs + rlen - wbuf->offs, len - rlen);
- spin_unlock(&wbuf->lock);
-
- if (rlen > 0) {
- /* Read everything that goes before write-buffer */
- err = ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
- if (err && err != -EBADMSG)
- return err;
- }
-
- if (type != ch->node_type) {
- ubifs_err(c, "bad node type (%d but expected %d)",
- ch->node_type, type);
- goto out;
- }
-
- err = ubifs_check_node(c, buf, lnum, offs, 0, 0);
- if (err) {
- ubifs_err(c, "expected node type %d", type);
- return err;
- }
-
- rlen = le32_to_cpu(ch->len);
- if (rlen != len) {
- ubifs_err(c, "bad node length %d, expected %d", rlen, len);
- goto out;
- }
-
- return 0;
-
-out:
- ubifs_err(c, "bad node at LEB %d:%d", lnum, offs);
- ubifs_dump_node(c, buf);
- dump_stack();
- return -EINVAL;
-}
-
/**
* ubifs_read_node - read node.
* @c: UBIFS file-system description object
@@ -1064,96 +349,5 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
wbuf->c = c;
wbuf->next_ino = 0;
-#ifndef __BAREBOX__
- hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- wbuf->timer.function = wbuf_timer_callback_nolock;
- wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
- wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
- wbuf->delta *= 1000000000ULL;
- ubifs_assert(wbuf->delta <= ULONG_MAX);
-#endif
- return 0;
-}
-
-/**
- * ubifs_wbuf_add_ino_nolock - add an inode number into the wbuf inode array.
- * @wbuf: the write-buffer where to add
- * @inum: the inode number
- *
- * This function adds an inode number to the inode array of the write-buffer.
- */
-void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum)
-{
- if (!wbuf->buf)
- /* NOR flash or something similar */
- return;
-
- spin_lock(&wbuf->lock);
- if (wbuf->used)
- wbuf->inodes[wbuf->next_ino++] = inum;
- spin_unlock(&wbuf->lock);
-}
-
-/**
- * wbuf_has_ino - returns if the wbuf contains data from the inode.
- * @wbuf: the write-buffer
- * @inum: the inode number
- *
- * This function returns with %1 if the write-buffer contains some data from the
- * given inode otherwise it returns with %0.
- */
-static int wbuf_has_ino(struct ubifs_wbuf *wbuf, ino_t inum)
-{
- int i, ret = 0;
-
- spin_lock(&wbuf->lock);
- for (i = 0; i < wbuf->next_ino; i++)
- if (inum == wbuf->inodes[i]) {
- ret = 1;
- break;
- }
- spin_unlock(&wbuf->lock);
-
- return ret;
-}
-
-/**
- * ubifs_sync_wbufs_by_inode - synchronize write-buffers for an inode.
- * @c: UBIFS file-system description object
- * @inode: inode to synchronize
- *
- * This function synchronizes write-buffers which contain nodes belonging to
- * @inode. Returns zero in case of success and a negative error code in case of
- * failure.
- */
-int ubifs_sync_wbufs_by_inode(struct ubifs_info *c, struct inode *inode)
-{
- int i, err = 0;
-
- for (i = 0; i < c->jhead_cnt; i++) {
- struct ubifs_wbuf *wbuf = &c->jheads[i].wbuf;
-
- if (i == GCHD)
- /*
- * GC head is special, do not look at it. Even if the
- * head contains something related to this inode, it is
- * a _copy_ of corresponding on-flash node which sits
- * somewhere else.
- */
- continue;
-
- if (!wbuf_has_ino(wbuf, inode->i_ino))
- continue;
-
- mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
- if (wbuf_has_ino(wbuf, inode->i_ino))
- err = ubifs_wbuf_sync_nolock(wbuf);
- mutex_unlock(&wbuf->io_mutex);
-
- if (err) {
- ubifs_ro_mode(c, err);
- return err;
- }
- }
return 0;
}
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
index a07fdef12f..db83f564f7 100644
--- a/fs/ubifs/log.c
+++ b/fs/ubifs/log.c
@@ -21,8 +21,6 @@
#endif
#include "ubifs.h"
-static int dbg_check_bud_bytes(struct ubifs_info *c);
-
/**
* ubifs_search_bud - search bud LEB.
* @c: UBIFS file-system description object
@@ -53,61 +51,6 @@ struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum)
return NULL;
}
-/**
- * ubifs_get_wbuf - get the wbuf associated with a LEB, if there is one.
- * @c: UBIFS file-system description object
- * @lnum: logical eraseblock number to search
- *
- * This functions returns the wbuf for @lnum or %NULL if there is not one.
- */
-struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum)
-{
- struct rb_node *p;
- struct ubifs_bud *bud;
- int jhead;
-
- if (!c->jheads)
- return NULL;
-
- spin_lock(&c->buds_lock);
- p = c->buds.rb_node;
- while (p) {
- bud = rb_entry(p, struct ubifs_bud, rb);
- if (lnum < bud->lnum)
- p = p->rb_left;
- else if (lnum > bud->lnum)
- p = p->rb_right;
- else {
- jhead = bud->jhead;
- spin_unlock(&c->buds_lock);
- return &c->jheads[jhead].wbuf;
- }
- }
- spin_unlock(&c->buds_lock);
- return NULL;
-}
-
-/**
- * empty_log_bytes - calculate amount of empty space in the log.
- * @c: UBIFS file-system description object
- */
-static inline long long empty_log_bytes(const struct ubifs_info *c)
-{
- long long h, t;
-
- h = (long long)c->lhead_lnum * c->leb_size + c->lhead_offs;
- t = (long long)c->ltail_lnum * c->leb_size;
-
- if (h > t)
- return c->log_bytes - h + t;
- else if (h != t)
- return t - h;
- else if (c->lhead_lnum != c->ltail_lnum)
- return 0;
- else
- return c->log_bytes;
-}
-
/**
* ubifs_add_bud - add bud LEB to the tree of buds and its journal head list.
* @c: UBIFS file-system description object
@@ -151,595 +94,3 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
bud->start, dbg_jhead(bud->jhead), c->bud_bytes);
spin_unlock(&c->buds_lock);
}
-
-/**
- * ubifs_add_bud_to_log - add a new bud to the log.
- * @c: UBIFS file-system description object
- * @jhead: journal head the bud belongs to
- * @lnum: LEB number of the bud
- * @offs: starting offset of the bud
- *
- * This function writes reference node for the new bud LEB @lnum it to the log,
- * and adds it to the buds tress. It also makes sure that log size does not
- * exceed the 'c->max_bud_bytes' limit. Returns zero in case of success,
- * %-EAGAIN if commit is required, and a negative error codes in case of
- * failure.
- */
-int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
-{
- int err;
- struct ubifs_bud *bud;
- struct ubifs_ref_node *ref;
-
- bud = kmalloc(sizeof(struct ubifs_bud), GFP_NOFS);
- if (!bud)
- return -ENOMEM;
- ref = kzalloc(c->ref_node_alsz, GFP_NOFS);
- if (!ref) {
- kfree(bud);
- return -ENOMEM;
- }
-
- mutex_lock(&c->log_mutex);
- ubifs_assert(!c->ro_media && !c->ro_mount);
- if (c->ro_error) {
- err = -EROFS;
- goto out_unlock;
- }
-
- /* Make sure we have enough space in the log */
- if (empty_log_bytes(c) - c->ref_node_alsz < c->min_log_bytes) {
- dbg_log("not enough log space - %lld, required %d",
- empty_log_bytes(c), c->min_log_bytes);
- ubifs_commit_required(c);
- err = -EAGAIN;
- goto out_unlock;
- }
-
- /*
- * Make sure the amount of space in buds will not exceed the
- * 'c->max_bud_bytes' limit, because we want to guarantee mount time
- * limits.
- *
- * It is not necessary to hold @c->buds_lock when reading @c->bud_bytes
- * because we are holding @c->log_mutex. All @c->bud_bytes take place
- * when both @c->log_mutex and @c->bud_bytes are locked.
- */
- if (c->bud_bytes + c->leb_size - offs > c->max_bud_bytes) {
- dbg_log("bud bytes %lld (%lld max), require commit",
- c->bud_bytes, c->max_bud_bytes);
- ubifs_commit_required(c);
- err = -EAGAIN;
- goto out_unlock;
- }
-
- /*
- * If the journal is full enough - start background commit. Note, it is
- * OK to read 'c->cmt_state' without spinlock because integer reads
- * are atomic in the kernel.
- */
- if (c->bud_bytes >= c->bg_bud_bytes &&
- c->cmt_state == COMMIT_RESTING) {
- dbg_log("bud bytes %lld (%lld max), initiate BG commit",
- c->bud_bytes, c->max_bud_bytes);
- ubifs_request_bg_commit(c);
- }
-
- bud->lnum = lnum;
- bud->start = offs;
- bud->jhead = jhead;
-
- ref->ch.node_type = UBIFS_REF_NODE;
- ref->lnum = cpu_to_le32(bud->lnum);
- ref->offs = cpu_to_le32(bud->start);
- ref->jhead = cpu_to_le32(jhead);
-
- if (c->lhead_offs > c->leb_size - c->ref_node_alsz) {
- c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
- ubifs_assert(c->lhead_lnum != c->ltail_lnum);
- c->lhead_offs = 0;
- }
-
- if (c->lhead_offs == 0) {
- /* Must ensure next log LEB has been unmapped */
- err = ubifs_leb_unmap(c, c->lhead_lnum);
- if (err)
- goto out_unlock;
- }
-
- if (bud->start == 0) {
- /*
- * Before writing the LEB reference which refers an empty LEB
- * to the log, we have to make sure it is mapped, because
- * otherwise we'd risk to refer an LEB with garbage in case of
- * an unclean reboot, because the target LEB might have been
- * unmapped, but not yet physically erased.
- */
- err = ubifs_leb_map(c, bud->lnum);
- if (err)
- goto out_unlock;
- }
-
- dbg_log("write ref LEB %d:%d",
- c->lhead_lnum, c->lhead_offs);
- err = ubifs_write_node(c, ref, UBIFS_REF_NODE_SZ, c->lhead_lnum,
- c->lhead_offs);
- if (err)
- goto out_unlock;
-
- c->lhead_offs += c->ref_node_alsz;
-
- ubifs_add_bud(c, bud);
-
- mutex_unlock(&c->log_mutex);
- kfree(ref);
- return 0;
-
-out_unlock:
- mutex_unlock(&c->log_mutex);
- kfree(ref);
- kfree(bud);
- return err;
-}
-
-/**
- * remove_buds - remove used buds.
- * @c: UBIFS file-system description object
- *
- * This function removes use buds from the buds tree. It does not remove the
- * buds which are pointed to by journal heads.
- */
-static void remove_buds(struct ubifs_info *c)
-{
- struct rb_node *p;
-
- ubifs_assert(list_empty(&c->old_buds));
- c->cmt_bud_bytes = 0;
- spin_lock(&c->buds_lock);
- p = rb_first(&c->buds);
- while (p) {
- struct rb_node *p1 = p;
- struct ubifs_bud *bud;
- struct ubifs_wbuf *wbuf;
-
- p = rb_next(p);
- bud = rb_entry(p1, struct ubifs_bud, rb);
- wbuf = &c->jheads[bud->jhead].wbuf;
-
- if (wbuf->lnum == bud->lnum) {
- /*
- * Do not remove buds which are pointed to by journal
- * heads (non-closed buds).
- */
- c->cmt_bud_bytes += wbuf->offs - bud->start;
- dbg_log("preserve %d:%d, jhead %s, bud bytes %d, cmt_bud_bytes %lld",
- bud->lnum, bud->start, dbg_jhead(bud->jhead),
- wbuf->offs - bud->start, c->cmt_bud_bytes);
- bud->start = wbuf->offs;
- } else {
- c->cmt_bud_bytes += c->leb_size - bud->start;
- dbg_log("remove %d:%d, jhead %s, bud bytes %d, cmt_bud_bytes %lld",
- bud->lnum, bud->start, dbg_jhead(bud->jhead),
- c->leb_size - bud->start, c->cmt_bud_bytes);
- rb_erase(p1, &c->buds);
- /*
- * If the commit does not finish, the recovery will need
- * to replay the journal, in which case the old buds
- * must be unchanged. Do not release them until post
- * commit i.e. do not allow them to be garbage
- * collected.
- */
- list_move(&bud->list, &c->old_buds);
- }
- }
- spin_unlock(&c->buds_lock);
-}
-
-/**
- * ubifs_log_start_commit - start commit.
- * @c: UBIFS file-system description object
- * @ltail_lnum: return new log tail LEB number
- *
- * The commit operation starts with writing "commit start" node to the log and
- * reference nodes for all journal heads which will define new journal after
- * the commit has been finished. The commit start and reference nodes are
- * written in one go to the nearest empty log LEB (hence, when commit is
- * finished UBIFS may safely unmap all the previous log LEBs). This function
- * returns zero in case of success and a negative error code in case of
- * failure.
- */
-int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
-{
- void *buf;
- struct ubifs_cs_node *cs;
- struct ubifs_ref_node *ref;
- int err, i, max_len, len;
-
- err = dbg_check_bud_bytes(c);
- if (err)
- return err;
-
- max_len = UBIFS_CS_NODE_SZ + c->jhead_cnt * UBIFS_REF_NODE_SZ;
- max_len = ALIGN(max_len, c->min_io_size);
- buf = cs = kmalloc(max_len, GFP_NOFS);
- if (!buf)
- return -ENOMEM;
-
- cs->ch.node_type = UBIFS_CS_NODE;
- cs->cmt_no = cpu_to_le64(c->cmt_no);
- ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0);
-
- /*
- * Note, we do not lock 'c->log_mutex' because this is the commit start
- * phase and we are exclusively using the log. And we do not lock
- * write-buffer because nobody can write to the file-system at this
- * phase.
- */
-
- len = UBIFS_CS_NODE_SZ;
- for (i = 0; i < c->jhead_cnt; i++) {
- int lnum = c->jheads[i].wbuf.lnum;
- int offs = c->jheads[i].wbuf.offs;
-
- if (lnum == -1 || offs == c->leb_size)
- continue;
-
- dbg_log("add ref to LEB %d:%d for jhead %s",
- lnum, offs, dbg_jhead(i));
- ref = buf + len;
- ref->ch.node_type = UBIFS_REF_NODE;
- ref->lnum = cpu_to_le32(lnum);
- ref->offs = cpu_to_le32(offs);
- ref->jhead = cpu_to_le32(i);
-
- ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0);
- len += UBIFS_REF_NODE_SZ;
- }
-
- ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len);
-
- /* Switch to the next log LEB */
- if (c->lhead_offs) {
- c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
- ubifs_assert(c->lhead_lnum != c->ltail_lnum);
- c->lhead_offs = 0;
- }
-
- /* Must ensure next LEB has been unmapped */
- err = ubifs_leb_unmap(c, c->lhead_lnum);
- if (err)
- goto out;
-
- len = ALIGN(len, c->min_io_size);
- dbg_log("writing commit start at LEB %d:0, len %d", c->lhead_lnum, len);
- err = ubifs_leb_write(c, c->lhead_lnum, cs, 0, len);
- if (err)
- goto out;
-
- *ltail_lnum = c->lhead_lnum;
-
- c->lhead_offs += len;
- if (c->lhead_offs == c->leb_size) {
- c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
- c->lhead_offs = 0;
- }
-
- remove_buds(c);
-
- /*
- * We have started the commit and now users may use the rest of the log
- * for new writes.
- */
- c->min_log_bytes = 0;
-
-out:
- kfree(buf);
- return err;
-}
-
-/**
- * ubifs_log_end_commit - end commit.
- * @c: UBIFS file-system description object
- * @ltail_lnum: new log tail LEB number
- *
- * This function is called on when the commit operation was finished. It
- * moves log tail to new position and updates the master node so that it stores
- * the new log tail LEB number. Returns zero in case of success and a negative
- * error code in case of failure.
- */
-int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum)
-{
- int err;
-
- /*
- * At this phase we have to lock 'c->log_mutex' because UBIFS allows FS
- * writes during commit. Its only short "commit" start phase when
- * writers are blocked.
- */
- mutex_lock(&c->log_mutex);
-
- dbg_log("old tail was LEB %d:0, new tail is LEB %d:0",
- c->ltail_lnum, ltail_lnum);
-
- c->ltail_lnum = ltail_lnum;
- /*
- * The commit is finished and from now on it must be guaranteed that
- * there is always enough space for the next commit.
- */
- c->min_log_bytes = c->leb_size;
-
- spin_lock(&c->buds_lock);
- c->bud_bytes -= c->cmt_bud_bytes;
- spin_unlock(&c->buds_lock);
-
- err = dbg_check_bud_bytes(c);
- if (err)
- goto out;
-
- err = ubifs_write_master(c);
-
-out:
- mutex_unlock(&c->log_mutex);
- return err;
-}
-
-/**
- * ubifs_log_post_commit - things to do after commit is completed.
- * @c: UBIFS file-system description object
- * @old_ltail_lnum: old log tail LEB number
- *
- * Release buds only after commit is completed, because they must be unchanged
- * if recovery is needed.
- *
- * Unmap log LEBs only after commit is completed, because they may be needed for
- * recovery.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
-{
- int lnum, err = 0;
-
- while (!list_empty(&c->old_buds)) {
- struct ubifs_bud *bud;
-
- bud = list_entry(c->old_buds.next, struct ubifs_bud, list);
- err = ubifs_return_leb(c, bud->lnum);
- if (err)
- return err;
- list_del(&bud->list);
- kfree(bud);
- }
- mutex_lock(&c->log_mutex);
- for (lnum = old_ltail_lnum; lnum != c->ltail_lnum;
- lnum = ubifs_next_log_lnum(c, lnum)) {
- dbg_log("unmap log LEB %d", lnum);
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- goto out;
- }
-out:
- mutex_unlock(&c->log_mutex);
- return err;
-}
-
-/**
- * struct done_ref - references that have been done.
- * @rb: rb-tree node
- * @lnum: LEB number
- */
-struct done_ref {
- struct rb_node rb;
- int lnum;
-};
-
-/**
- * done_already - determine if a reference has been done already.
- * @done_tree: rb-tree to store references that have been done
- * @lnum: LEB number of reference
- *
- * This function returns %1 if the reference has been done, %0 if not, otherwise
- * a negative error code is returned.
- */
-static int done_already(struct rb_root *done_tree, int lnum)
-{
- struct rb_node **p = &done_tree->rb_node, *parent = NULL;
- struct done_ref *dr;
-
- while (*p) {
- parent = *p;
- dr = rb_entry(parent, struct done_ref, rb);
- if (lnum < dr->lnum)
- p = &(*p)->rb_left;
- else if (lnum > dr->lnum)
- p = &(*p)->rb_right;
- else
- return 1;
- }
-
- dr = kzalloc(sizeof(struct done_ref), GFP_NOFS);
- if (!dr)
- return -ENOMEM;
-
- dr->lnum = lnum;
-
- rb_link_node(&dr->rb, parent, p);
- rb_insert_color(&dr->rb, done_tree);
-
- return 0;
-}
-
-/**
- * destroy_done_tree - destroy the done tree.
- * @done_tree: done tree to destroy
- */
-static void destroy_done_tree(struct rb_root *done_tree)
-{
- struct done_ref *dr, *n;
-
- rbtree_postorder_for_each_entry_safe(dr, n, done_tree, rb)
- kfree(dr);
-}
-
-/**
- * add_node - add a node to the consolidated log.
- * @c: UBIFS file-system description object
- * @buf: buffer to which to add
- * @lnum: LEB number to which to write is passed and returned here
- * @offs: offset to where to write is passed and returned here
- * @node: node to add
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
- void *node)
-{
- struct ubifs_ch *ch = node;
- int len = le32_to_cpu(ch->len), remains = c->leb_size - *offs;
-
- if (len > remains) {
- int sz = ALIGN(*offs, c->min_io_size), err;
-
- ubifs_pad(c, buf + *offs, sz - *offs);
- err = ubifs_leb_change(c, *lnum, buf, sz);
- if (err)
- return err;
- *lnum = ubifs_next_log_lnum(c, *lnum);
- *offs = 0;
- }
- memcpy(buf + *offs, node, len);
- *offs += ALIGN(len, 8);
- return 0;
-}
-
-/**
- * ubifs_consolidate_log - consolidate the log.
- * @c: UBIFS file-system description object
- *
- * Repeated failed commits could cause the log to be full, but at least 1 LEB is
- * needed for commit. This function rewrites the reference nodes in the log
- * omitting duplicates, and failed CS nodes, and leaving no gaps.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_consolidate_log(struct ubifs_info *c)
-{
- struct ubifs_scan_leb *sleb;
- struct ubifs_scan_node *snod;
- struct rb_root done_tree = RB_ROOT;
- int lnum, err, first = 1, write_lnum, offs = 0;
- void *buf;
-
- dbg_rcvry("log tail LEB %d, log head LEB %d", c->ltail_lnum,
- c->lhead_lnum);
- buf = vmalloc(c->leb_size);
- if (!buf)
- return -ENOMEM;
- lnum = c->ltail_lnum;
- write_lnum = lnum;
- while (1) {
- sleb = ubifs_scan(c, lnum, 0, c->sbuf, 0);
- if (IS_ERR(sleb)) {
- err = PTR_ERR(sleb);
- goto out_free;
- }
- list_for_each_entry(snod, &sleb->nodes, list) {
- switch (snod->type) {
- case UBIFS_REF_NODE: {
- struct ubifs_ref_node *ref = snod->node;
- int ref_lnum = le32_to_cpu(ref->lnum);
-
- err = done_already(&done_tree, ref_lnum);
- if (err < 0)
- goto out_scan;
- if (err != 1) {
- err = add_node(c, buf, &write_lnum,
- &offs, snod->node);
- if (err)
- goto out_scan;
- }
- break;
- }
- case UBIFS_CS_NODE:
- if (!first)
- break;
- err = add_node(c, buf, &write_lnum, &offs,
- snod->node);
- if (err)
- goto out_scan;
- first = 0;
- break;
- }
- }
- ubifs_scan_destroy(sleb);
- if (lnum == c->lhead_lnum)
- break;
- lnum = ubifs_next_log_lnum(c, lnum);
- }
- if (offs) {
- int sz = ALIGN(offs, c->min_io_size);
-
- ubifs_pad(c, buf + offs, sz - offs);
- err = ubifs_leb_change(c, write_lnum, buf, sz);
- if (err)
- goto out_free;
- offs = ALIGN(offs, c->min_io_size);
- }
- destroy_done_tree(&done_tree);
- vfree(buf);
- if (write_lnum == c->lhead_lnum) {
- ubifs_err(c, "log is too full");
- return -EINVAL;
- }
- /* Unmap remaining LEBs */
- lnum = write_lnum;
- do {
- lnum = ubifs_next_log_lnum(c, lnum);
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- return err;
- } while (lnum != c->lhead_lnum);
- c->lhead_lnum = write_lnum;
- c->lhead_offs = offs;
- dbg_rcvry("new log head at %d:%d", c->lhead_lnum, c->lhead_offs);
- return 0;
-
-out_scan:
- ubifs_scan_destroy(sleb);
-out_free:
- destroy_done_tree(&done_tree);
- vfree(buf);
- return err;
-}
-
-/**
- * dbg_check_bud_bytes - make sure bud bytes calculation are all right.
- * @c: UBIFS file-system description object
- *
- * This function makes sure the amount of flash space used by closed buds
- * ('c->bud_bytes' is correct). Returns zero in case of success and %-EINVAL in
- * case of failure.
- */
-static int dbg_check_bud_bytes(struct ubifs_info *c)
-{
- int i, err = 0;
- struct ubifs_bud *bud;
- long long bud_bytes = 0;
-
- if (!dbg_is_chk_gen(c))
- return 0;
-
- spin_lock(&c->buds_lock);
- for (i = 0; i < c->jhead_cnt; i++)
- list_for_each_entry(bud, &c->jheads[i].buds_list, list)
- bud_bytes += c->leb_size - bud->start;
-
- if (c->bud_bytes != bud_bytes) {
- ubifs_err(c, "bad bud_bytes %lld, calculated %lld",
- c->bud_bytes, bud_bytes);
- err = -EINVAL;
- }
- spin_unlock(&c->buds_lock);
-
- return err;
-}
diff --git a/fs/ubifs/lprops.c b/fs/ubifs/lprops.c
deleted file mode 100644
index 28a1d3d9e1..0000000000
--- a/fs/ubifs/lprops.c
+++ /dev/null
@@ -1,1313 +0,0 @@
-/*
- * This file is part of UBIFS.
- *
- * Copyright (C) 2006-2008 Nokia Corporation.
- *
- * SPDX-License-Identifier: GPL-2.0+
- *
- * Authors: Adrian Hunter
- * Artem Bityutskiy (Битюцкий Артём)
- */
-
-/*
- * This file implements the functions that access LEB properties and their
- * categories. LEBs are categorized based on the needs of UBIFS, and the
- * categories are stored as either heaps or lists to provide a fast way of
- * finding a LEB in a particular category. For example, UBIFS may need to find
- * an empty LEB for the journal, or a very dirty LEB for garbage collection.
- */
-
-#ifdef __BAREBOX__
-#include <linux/err.h>
-#endif
-#include "ubifs.h"
-
-/**
- * get_heap_comp_val - get the LEB properties value for heap comparisons.
- * @lprops: LEB properties
- * @cat: LEB category
- */
-static int get_heap_comp_val(struct ubifs_lprops *lprops, int cat)
-{
- switch (cat) {
- case LPROPS_FREE:
- return lprops->free;
- case LPROPS_DIRTY_IDX:
- return lprops->free + lprops->dirty;
- default:
- return lprops->dirty;
- }
-}
-
-/**
- * move_up_lpt_heap - move a new heap entry up as far as possible.
- * @c: UBIFS file-system description object
- * @heap: LEB category heap
- * @lprops: LEB properties to move
- * @cat: LEB category
- *
- * New entries to a heap are added at the bottom and then moved up until the
- * parent's value is greater. In the case of LPT's category heaps, the value
- * is either the amount of free space or the amount of dirty space, depending
- * on the category.
- */
-static void move_up_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
- struct ubifs_lprops *lprops, int cat)
-{
- int val1, val2, hpos;
-
- hpos = lprops->hpos;
- if (!hpos)
- return; /* Already top of the heap */
- val1 = get_heap_comp_val(lprops, cat);
- /* Compare to parent and, if greater, move up the heap */
- do {
- int ppos = (hpos - 1) / 2;
-
- val2 = get_heap_comp_val(heap->arr[ppos], cat);
- if (val2 >= val1)
- return;
- /* Greater than parent so move up */
- heap->arr[ppos]->hpos = hpos;
- heap->arr[hpos] = heap->arr[ppos];
- heap->arr[ppos] = lprops;
- lprops->hpos = ppos;
- hpos = ppos;
- } while (hpos);
-}
-
-/**
- * adjust_lpt_heap - move a changed heap entry up or down the heap.
- * @c: UBIFS file-system description object
- * @heap: LEB category heap
- * @lprops: LEB properties to move
- * @hpos: heap position of @lprops
- * @cat: LEB category
- *
- * Changed entries in a heap are moved up or down until the parent's value is
- * greater. In the case of LPT's category heaps, the value is either the amount
- * of free space or the amount of dirty space, depending on the category.
- */
-static void adjust_lpt_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap,
- struct ubifs_lprops *lprops, int hpos, int cat)
-{
- int val1, val2, val3, cpos;
-
- val1 = get_heap_comp_val(lprops, cat);
- /* Compare to parent and, if greater than parent, move up the heap */
- if (hpos) {
- int ppos = (hpos - 1) / 2;
-
- val2 = get_heap_comp_val(heap->arr[ppos], cat);
- if (val1 > val2) {
- /* Greater than parent so move up */
- while (1) {
- heap->arr[ppos]->hpos = hpos;
- heap->arr[hpos] = heap->arr[ppos];
- heap->arr[ppos] = lprops;
- lprops->hpos = ppos;
- hpos = ppos;
- if (!hpos)
- return;
- ppos = (hpos - 1) / 2;
- val2 = get_heap_comp_val(heap->arr[ppos], cat);
- if (val1 <= val2)
- return;
- /* Still greater than parent so keep going */
- }
- }
- }
-
- /* Not greater than parent, so compare to children */
- while (1) {
- /* Compare to left child */
- cpos = hpos * 2 + 1;
- if (cpos >= heap->cnt)
- return;
- val2 = get_heap_comp_val(heap->arr[cpos], cat);
- if (val1 < val2) {
- /* Less than left child, so promote biggest child */
- if (cpos + 1 < heap->cnt) {
- val3 = get_heap_comp_val(heap->arr[cpos + 1],
- cat);
- if (val3 > val2)
- cpos += 1; /* Right child is bigger */
- }
- heap->arr[cpos]->hpos = hpos;
- heap->arr[hpos] = heap->arr[cpos];
- heap->arr[cpos] = lprops;
- lprops->hpos = cpos;
- hpos = cpos;
- continue;
- }
- /* Compare to right child */
- cpos += 1;
- if (cpos >= heap->cnt)
- return;
- val3 = get_heap_comp_val(heap->arr[cpos], cat);
- if (val1 < val3) {
- /* Less than right child, so promote right child */
- heap->arr[cpos]->hpos = hpos;
- heap->arr[hpos] = heap->arr[cpos];
- heap->arr[cpos] = lprops;
- lprops->hpos = cpos;
- hpos = cpos;
- continue;
- }
- return;
- }
-}
-
-/**
- * add_to_lpt_heap - add LEB properties to a LEB category heap.
- * @c: UBIFS file-system description object
- * @lprops: LEB properties to add
- * @cat: LEB category
- *
- * This function returns %1 if @lprops is added to the heap for LEB category
- * @cat, otherwise %0 is returned because the heap is full.
- */
-static int add_to_lpt_heap(struct ubifs_info *c, struct ubifs_lprops *lprops,
- int cat)
-{
- struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
-
- if (heap->cnt >= heap->max_cnt) {
- const int b = LPT_HEAP_SZ / 2 - 1;
- int cpos, val1, val2;
-
- /* Compare to some other LEB on the bottom of heap */
- /* Pick a position kind of randomly */
- cpos = (((size_t)lprops >> 4) & b) + b;
- ubifs_assert(cpos >= b);
- ubifs_assert(cpos < LPT_HEAP_SZ);
- ubifs_assert(cpos < heap->cnt);
-
- val1 = get_heap_comp_val(lprops, cat);
- val2 = get_heap_comp_val(heap->arr[cpos], cat);
- if (val1 > val2) {
- struct ubifs_lprops *lp;
-
- lp = heap->arr[cpos];
- lp->flags &= ~LPROPS_CAT_MASK;
- lp->flags |= LPROPS_UNCAT;
- list_add(&lp->list, &c->uncat_list);
- lprops->hpos = cpos;
- heap->arr[cpos] = lprops;
- move_up_lpt_heap(c, heap, lprops, cat);
- dbg_check_heap(c, heap, cat, lprops->hpos);
- return 1; /* Added to heap */
- }
- dbg_check_heap(c, heap, cat, -1);
- return 0; /* Not added to heap */
- } else {
- lprops->hpos = heap->cnt++;
- heap->arr[lprops->hpos] = lprops;
- move_up_lpt_heap(c, heap, lprops, cat);
- dbg_check_heap(c, heap, cat, lprops->hpos);
- return 1; /* Added to heap */
- }
-}
-
-/**
- * remove_from_lpt_heap - remove LEB properties from a LEB category heap.
- * @c: UBIFS file-system description object
- * @lprops: LEB properties to remove
- * @cat: LEB category
- */
-static void remove_from_lpt_heap(struct ubifs_info *c,
- struct ubifs_lprops *lprops, int cat)
-{
- struct ubifs_lpt_heap *heap;
- int hpos = lprops->hpos;
-
- heap = &c->lpt_heap[cat - 1];
- ubifs_assert(hpos >= 0 && hpos < heap->cnt);
- ubifs_assert(heap->arr[hpos] == lprops);
- heap->cnt -= 1;
- if (hpos < heap->cnt) {
- heap->arr[hpos] = heap->arr[heap->cnt];
- heap->arr[hpos]->hpos = hpos;
- adjust_lpt_heap(c, heap, heap->arr[hpos], hpos, cat);
- }
- dbg_check_heap(c, heap, cat, -1);
-}
-
-/**
- * lpt_heap_replace - replace lprops in a category heap.
- * @c: UBIFS file-system description object
- * @old_lprops: LEB properties to replace
- * @new_lprops: LEB properties with which to replace
- * @cat: LEB category
- *
- * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
- * and the lprops that the pnode contains. When that happens, references in
- * the category heaps to those lprops must be updated to point to the new
- * lprops. This function does that.
- */
-static void lpt_heap_replace(struct ubifs_info *c,
- struct ubifs_lprops *old_lprops,
- struct ubifs_lprops *new_lprops, int cat)
-{
- struct ubifs_lpt_heap *heap;
- int hpos = new_lprops->hpos;
-
- heap = &c->lpt_heap[cat - 1];
- heap->arr[hpos] = new_lprops;
-}
-
-/**
- * ubifs_add_to_cat - add LEB properties to a category list or heap.
- * @c: UBIFS file-system description object
- * @lprops: LEB properties to add
- * @cat: LEB category to which to add
- *
- * LEB properties are categorized to enable fast find operations.
- */
-void ubifs_add_to_cat(struct ubifs_info *c, struct ubifs_lprops *lprops,
- int cat)
-{
- switch (cat) {
- case LPROPS_DIRTY:
- case LPROPS_DIRTY_IDX:
- case LPROPS_FREE:
- if (add_to_lpt_heap(c, lprops, cat))
- break;
- /* No more room on heap so make it un-categorized */
- cat = LPROPS_UNCAT;
- /* Fall through */
- case LPROPS_UNCAT:
- list_add(&lprops->list, &c->uncat_list);
- break;
- case LPROPS_EMPTY:
- list_add(&lprops->list, &c->empty_list);
- break;
- case LPROPS_FREEABLE:
- list_add(&lprops->list, &c->freeable_list);
- c->freeable_cnt += 1;
- break;
- case LPROPS_FRDI_IDX:
- list_add(&lprops->list, &c->frdi_idx_list);
- break;
- default:
- ubifs_assert(0);
- }
-
- lprops->flags &= ~LPROPS_CAT_MASK;
- lprops->flags |= cat;
- c->in_a_category_cnt += 1;
- ubifs_assert(c->in_a_category_cnt <= c->main_lebs);
-}
-
-/**
- * ubifs_remove_from_cat - remove LEB properties from a category list or heap.
- * @c: UBIFS file-system description object
- * @lprops: LEB properties to remove
- * @cat: LEB category from which to remove
- *
- * LEB properties are categorized to enable fast find operations.
- */
-static void ubifs_remove_from_cat(struct ubifs_info *c,
- struct ubifs_lprops *lprops, int cat)
-{
- switch (cat) {
- case LPROPS_DIRTY:
- case LPROPS_DIRTY_IDX:
- case LPROPS_FREE:
- remove_from_lpt_heap(c, lprops, cat);
- break;
- case LPROPS_FREEABLE:
- c->freeable_cnt -= 1;
- ubifs_assert(c->freeable_cnt >= 0);
- /* Fall through */
- case LPROPS_UNCAT:
- case LPROPS_EMPTY:
- case LPROPS_FRDI_IDX:
- ubifs_assert(!list_empty(&lprops->list));
- list_del(&lprops->list);
- break;
- default:
- ubifs_assert(0);
- }
-
- c->in_a_category_cnt -= 1;
- ubifs_assert(c->in_a_category_cnt >= 0);
-}
-
-/**
- * ubifs_replace_cat - replace lprops in a category list or heap.
- * @c: UBIFS file-system description object
- * @old_lprops: LEB properties to replace
- * @new_lprops: LEB properties with which to replace
- *
- * During commit it is sometimes necessary to copy a pnode (see dirty_cow_pnode)
- * and the lprops that the pnode contains. When that happens, references in
- * category lists and heaps must be replaced. This function does that.
- */
-void ubifs_replace_cat(struct ubifs_info *c, struct ubifs_lprops *old_lprops,
- struct ubifs_lprops *new_lprops)
-{
- int cat;
-
- cat = new_lprops->flags & LPROPS_CAT_MASK;
- switch (cat) {
- case LPROPS_DIRTY:
- case LPROPS_DIRTY_IDX:
- case LPROPS_FREE:
- lpt_heap_replace(c, old_lprops, new_lprops, cat);
- break;
- case LPROPS_UNCAT:
- case LPROPS_EMPTY:
- case LPROPS_FREEABLE:
- case LPROPS_FRDI_IDX:
- list_replace(&old_lprops->list, &new_lprops->list);
- break;
- default:
- ubifs_assert(0);
- }
-}
-
-/**
- * ubifs_ensure_cat - ensure LEB properties are categorized.
- * @c: UBIFS file-system description object
- * @lprops: LEB properties
- *
- * A LEB may have fallen off of the bottom of a heap, and ended up as
- * un-categorized even though it has enough space for us now. If that is the
- * case this function will put the LEB back onto a heap.
- */
-void ubifs_ensure_cat(struct ubifs_info *c, struct ubifs_lprops *lprops)
-{
- int cat = lprops->flags & LPROPS_CAT_MASK;
-
- if (cat != LPROPS_UNCAT)
- return;
- cat = ubifs_categorize_lprops(c, lprops);
- if (cat == LPROPS_UNCAT)
- return;
- ubifs_remove_from_cat(c, lprops, LPROPS_UNCAT);
- ubifs_add_to_cat(c, lprops, cat);
-}
-
-/**
- * ubifs_categorize_lprops - categorize LEB properties.
- * @c: UBIFS file-system description object
- * @lprops: LEB properties to categorize
- *
- * LEB properties are categorized to enable fast find operations. This function
- * returns the LEB category to which the LEB properties belong. Note however
- * that if the LEB category is stored as a heap and the heap is full, the
- * LEB properties may have their category changed to %LPROPS_UNCAT.
- */
-int ubifs_categorize_lprops(const struct ubifs_info *c,
- const struct ubifs_lprops *lprops)
-{
- if (lprops->flags & LPROPS_TAKEN)
- return LPROPS_UNCAT;
-
- if (lprops->free == c->leb_size) {
- ubifs_assert(!(lprops->flags & LPROPS_INDEX));
- return LPROPS_EMPTY;
- }
-
- if (lprops->free + lprops->dirty == c->leb_size) {
- if (lprops->flags & LPROPS_INDEX)
- return LPROPS_FRDI_IDX;
- else
- return LPROPS_FREEABLE;
- }
-
- if (lprops->flags & LPROPS_INDEX) {
- if (lprops->dirty + lprops->free >= c->min_idx_node_sz)
- return LPROPS_DIRTY_IDX;
- } else {
- if (lprops->dirty >= c->dead_wm &&
- lprops->dirty > lprops->free)
- return LPROPS_DIRTY;
- if (lprops->free > 0)
- return LPROPS_FREE;
- }
-
- return LPROPS_UNCAT;
-}
-
-/**
- * change_category - change LEB properties category.
- * @c: UBIFS file-system description object
- * @lprops: LEB properties to re-categorize
- *
- * LEB properties are categorized to enable fast find operations. When the LEB
- * properties change they must be re-categorized.
- */
-static void change_category(struct ubifs_info *c, struct ubifs_lprops *lprops)
-{
- int old_cat = lprops->flags & LPROPS_CAT_MASK;
- int new_cat = ubifs_categorize_lprops(c, lprops);
-
- if (old_cat == new_cat) {
- struct ubifs_lpt_heap *heap;
-
- /* lprops on a heap now must be moved up or down */
- if (new_cat < 1 || new_cat > LPROPS_HEAP_CNT)
- return; /* Not on a heap */
- heap = &c->lpt_heap[new_cat - 1];
- adjust_lpt_heap(c, heap, lprops, lprops->hpos, new_cat);
- } else {
- ubifs_remove_from_cat(c, lprops, old_cat);
- ubifs_add_to_cat(c, lprops, new_cat);
- }
-}
-
-/**
- * ubifs_calc_dark - calculate LEB dark space size.
- * @c: the UBIFS file-system description object
- * @spc: amount of free and dirty space in the LEB
- *
- * This function calculates and returns amount of dark space in an LEB which
- * has @spc bytes of free and dirty space.
- *
- * UBIFS is trying to account the space which might not be usable, and this
- * space is called "dark space". For example, if an LEB has only %512 free
- * bytes, it is dark space, because it cannot fit a large data node.
- */
-int ubifs_calc_dark(const struct ubifs_info *c, int spc)
-{
- ubifs_assert(!(spc & 7));
-
- if (spc < c->dark_wm)
- return spc;
-
- /*
- * If we have slightly more space then the dark space watermark, we can
- * anyway safely assume it we'll be able to write a node of the
- * smallest size there.
- */
- if (spc - c->dark_wm < MIN_WRITE_SZ)
- return spc - MIN_WRITE_SZ;
-
- return c->dark_wm;
-}
-
-/**
- * is_lprops_dirty - determine if LEB properties are dirty.
- * @c: the UBIFS file-system description object
- * @lprops: LEB properties to test
- */
-static int is_lprops_dirty(struct ubifs_info *c, struct ubifs_lprops *lprops)
-{
- struct ubifs_pnode *pnode;
- int pos;
-
- pos = (lprops->lnum - c->main_first) & (UBIFS_LPT_FANOUT - 1);
- pnode = (struct ubifs_pnode *)container_of(lprops - pos,
- struct ubifs_pnode,
- lprops[0]);
- return !test_bit(COW_CNODE, &pnode->flags) &&
- test_bit(DIRTY_CNODE, &pnode->flags);
-}
-
-/**
- * ubifs_change_lp - change LEB properties.
- * @c: the UBIFS file-system description object
- * @lp: LEB properties to change
- * @free: new free space amount
- * @dirty: new dirty space amount
- * @flags: new flags
- * @idx_gc_cnt: change to the count of @idx_gc list
- *
- * This function changes LEB properties (@free, @dirty or @flag). However, the
- * property which has the %LPROPS_NC value is not changed. Returns a pointer to
- * the updated LEB properties on success and a negative error code on failure.
- *
- * Note, the LEB properties may have had to be copied (due to COW) and
- * consequently the pointer returned may not be the same as the pointer
- * passed.
- */
-const struct ubifs_lprops *ubifs_change_lp(struct ubifs_info *c,
- const struct ubifs_lprops *lp,
- int free, int dirty, int flags,
- int idx_gc_cnt)
-{
- /*
- * This is the only function that is allowed to change lprops, so we
- * discard the "const" qualifier.
- */
- struct ubifs_lprops *lprops = (struct ubifs_lprops *)lp;
-
- dbg_lp("LEB %d, free %d, dirty %d, flags %d",
- lprops->lnum, free, dirty, flags);
-
- ubifs_assert(mutex_is_locked(&c->lp_mutex));
- ubifs_assert(c->lst.empty_lebs >= 0 &&
- c->lst.empty_lebs <= c->main_lebs);
- ubifs_assert(c->freeable_cnt >= 0);
- ubifs_assert(c->freeable_cnt <= c->main_lebs);
- ubifs_assert(c->lst.taken_empty_lebs >= 0);
- ubifs_assert(c->lst.taken_empty_lebs <= c->lst.empty_lebs);
- ubifs_assert(!(c->lst.total_free & 7) && !(c->lst.total_dirty & 7));
- ubifs_assert(!(c->lst.total_dead & 7) && !(c->lst.total_dark & 7));
- ubifs_assert(!(c->lst.total_used & 7));
- ubifs_assert(free == LPROPS_NC || free >= 0);
- ubifs_assert(dirty == LPROPS_NC || dirty >= 0);
-
- if (!is_lprops_dirty(c, lprops)) {
- lprops = ubifs_lpt_lookup_dirty(c, lprops->lnum);
- if (IS_ERR(lprops))
- return lprops;
- } else
- ubifs_assert(lprops == ubifs_lpt_lookup_dirty(c, lprops->lnum));
-
- ubifs_assert(!(lprops->free & 7) && !(lprops->dirty & 7));
-
- spin_lock(&c->space_lock);
- if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
- c->lst.taken_empty_lebs -= 1;
-
- if (!(lprops->flags & LPROPS_INDEX)) {
- int old_spc;
-
- old_spc = lprops->free + lprops->dirty;
- if (old_spc < c->dead_wm)
- c->lst.total_dead -= old_spc;
- else
- c->lst.total_dark -= ubifs_calc_dark(c, old_spc);
-
- c->lst.total_used -= c->leb_size - old_spc;
- }
-
- if (free != LPROPS_NC) {
- free = ALIGN(free, 8);
- c->lst.total_free += free - lprops->free;
-
- /* Increase or decrease empty LEBs counter if needed */
- if (free == c->leb_size) {
- if (lprops->free != c->leb_size)
- c->lst.empty_lebs += 1;
- } else if (lprops->free == c->leb_size)
- c->lst.empty_lebs -= 1;
- lprops->free = free;
- }
-
- if (dirty != LPROPS_NC) {
- dirty = ALIGN(dirty, 8);
- c->lst.total_dirty += dirty - lprops->dirty;
- lprops->dirty = dirty;
- }
-
- if (flags != LPROPS_NC) {
- /* Take care about indexing LEBs counter if needed */
- if ((lprops->flags & LPROPS_INDEX)) {
- if (!(flags & LPROPS_INDEX))
- c->lst.idx_lebs -= 1;
- } else if (flags & LPROPS_INDEX)
- c->lst.idx_lebs += 1;
- lprops->flags = flags;
- }
-
- if (!(lprops->flags & LPROPS_INDEX)) {
- int new_spc;
-
- new_spc = lprops->free + lprops->dirty;
- if (new_spc < c->dead_wm)
- c->lst.total_dead += new_spc;
- else
- c->lst.total_dark += ubifs_calc_dark(c, new_spc);
-
- c->lst.total_used += c->leb_size - new_spc;
- }
-
- if ((lprops->flags & LPROPS_TAKEN) && lprops->free == c->leb_size)
- c->lst.taken_empty_lebs += 1;
-
- change_category(c, lprops);
- c->idx_gc_cnt += idx_gc_cnt;
- spin_unlock(&c->space_lock);
- return lprops;
-}
-
-/**
- * ubifs_get_lp_stats - get lprops statistics.
- * @c: UBIFS file-system description object
- * @st: return statistics
- */
-void ubifs_get_lp_stats(struct ubifs_info *c, struct ubifs_lp_stats *lst)
-{
- spin_lock(&c->space_lock);
- memcpy(lst, &c->lst, sizeof(struct ubifs_lp_stats));
- spin_unlock(&c->space_lock);
-}
-
-/**
- * ubifs_change_one_lp - change LEB properties.
- * @c: the UBIFS file-system description object
- * @lnum: LEB to change properties for
- * @free: amount of free space
- * @dirty: amount of dirty space
- * @flags_set: flags to set
- * @flags_clean: flags to clean
- * @idx_gc_cnt: change to the count of idx_gc list
- *
- * This function changes properties of LEB @lnum. It is a helper wrapper over
- * 'ubifs_change_lp()' which hides lprops get/release. The arguments are the
- * same as in case of 'ubifs_change_lp()'. Returns zero in case of success and
- * a negative error code in case of failure.
- */
-int ubifs_change_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
- int flags_set, int flags_clean, int idx_gc_cnt)
-{
- int err = 0, flags;
- const struct ubifs_lprops *lp;
-
- ubifs_get_lprops(c);
-
- lp = ubifs_lpt_lookup_dirty(c, lnum);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- goto out;
- }
-
- flags = (lp->flags | flags_set) & ~flags_clean;
- lp = ubifs_change_lp(c, lp, free, dirty, flags, idx_gc_cnt);
- if (IS_ERR(lp))
- err = PTR_ERR(lp);
-
-out:
- ubifs_release_lprops(c);
- if (err)
- ubifs_err(c, "cannot change properties of LEB %d, error %d",
- lnum, err);
- return err;
-}
-
-/**
- * ubifs_update_one_lp - update LEB properties.
- * @c: the UBIFS file-system description object
- * @lnum: LEB to change properties for
- * @free: amount of free space
- * @dirty: amount of dirty space to add
- * @flags_set: flags to set
- * @flags_clean: flags to clean
- *
- * This function is the same as 'ubifs_change_one_lp()' but @dirty is added to
- * current dirty space, not substitutes it.
- */
-int ubifs_update_one_lp(struct ubifs_info *c, int lnum, int free, int dirty,
- int flags_set, int flags_clean)
-{
- int err = 0, flags;
- const struct ubifs_lprops *lp;
-
- ubifs_get_lprops(c);
-
- lp = ubifs_lpt_lookup_dirty(c, lnum);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- goto out;
- }
-
- flags = (lp->flags | flags_set) & ~flags_clean;
- lp = ubifs_change_lp(c, lp, free, lp->dirty + dirty, flags, 0);
- if (IS_ERR(lp))
- err = PTR_ERR(lp);
-
-out:
- ubifs_release_lprops(c);
- if (err)
- ubifs_err(c, "cannot update properties of LEB %d, error %d",
- lnum, err);
- return err;
-}
-
-/**
- * ubifs_read_one_lp - read LEB properties.
- * @c: the UBIFS file-system description object
- * @lnum: LEB to read properties for
- * @lp: where to store read properties
- *
- * This helper function reads properties of a LEB @lnum and stores them in @lp.
- * Returns zero in case of success and a negative error code in case of
- * failure.
- */
-int ubifs_read_one_lp(struct ubifs_info *c, int lnum, struct ubifs_lprops *lp)
-{
- int err = 0;
- const struct ubifs_lprops *lpp;
-
- ubifs_get_lprops(c);
-
- lpp = ubifs_lpt_lookup(c, lnum);
- if (IS_ERR(lpp)) {
- err = PTR_ERR(lpp);
- ubifs_err(c, "cannot read properties of LEB %d, error %d",
- lnum, err);
- goto out;
- }
-
- memcpy(lp, lpp, sizeof(struct ubifs_lprops));
-
-out:
- ubifs_release_lprops(c);
- return err;
-}
-
-/**
- * ubifs_fast_find_free - try to find a LEB with free space quickly.
- * @c: the UBIFS file-system description object
- *
- * This function returns LEB properties for a LEB with free space or %NULL if
- * the function is unable to find a LEB quickly.
- */
-const struct ubifs_lprops *ubifs_fast_find_free(struct ubifs_info *c)
-{
- struct ubifs_lprops *lprops;
- struct ubifs_lpt_heap *heap;
-
- ubifs_assert(mutex_is_locked(&c->lp_mutex));
-
- heap = &c->lpt_heap[LPROPS_FREE - 1];
- if (heap->cnt == 0)
- return NULL;
-
- lprops = heap->arr[0];
- ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
- ubifs_assert(!(lprops->flags & LPROPS_INDEX));
- return lprops;
-}
-
-/**
- * ubifs_fast_find_empty - try to find an empty LEB quickly.
- * @c: the UBIFS file-system description object
- *
- * This function returns LEB properties for an empty LEB or %NULL if the
- * function is unable to find an empty LEB quickly.
- */
-const struct ubifs_lprops *ubifs_fast_find_empty(struct ubifs_info *c)
-{
- struct ubifs_lprops *lprops;
-
- ubifs_assert(mutex_is_locked(&c->lp_mutex));
-
- if (list_empty(&c->empty_list))
- return NULL;
-
- lprops = list_entry(c->empty_list.next, struct ubifs_lprops, list);
- ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
- ubifs_assert(!(lprops->flags & LPROPS_INDEX));
- ubifs_assert(lprops->free == c->leb_size);
- return lprops;
-}
-
-/**
- * ubifs_fast_find_freeable - try to find a freeable LEB quickly.
- * @c: the UBIFS file-system description object
- *
- * This function returns LEB properties for a freeable LEB or %NULL if the
- * function is unable to find a freeable LEB quickly.
- */
-const struct ubifs_lprops *ubifs_fast_find_freeable(struct ubifs_info *c)
-{
- struct ubifs_lprops *lprops;
-
- ubifs_assert(mutex_is_locked(&c->lp_mutex));
-
- if (list_empty(&c->freeable_list))
- return NULL;
-
- lprops = list_entry(c->freeable_list.next, struct ubifs_lprops, list);
- ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
- ubifs_assert(!(lprops->flags & LPROPS_INDEX));
- ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
- ubifs_assert(c->freeable_cnt > 0);
- return lprops;
-}
-
-/**
- * ubifs_fast_find_frdi_idx - try to find a freeable index LEB quickly.
- * @c: the UBIFS file-system description object
- *
- * This function returns LEB properties for a freeable index LEB or %NULL if the
- * function is unable to find a freeable index LEB quickly.
- */
-const struct ubifs_lprops *ubifs_fast_find_frdi_idx(struct ubifs_info *c)
-{
- struct ubifs_lprops *lprops;
-
- ubifs_assert(mutex_is_locked(&c->lp_mutex));
-
- if (list_empty(&c->frdi_idx_list))
- return NULL;
-
- lprops = list_entry(c->frdi_idx_list.next, struct ubifs_lprops, list);
- ubifs_assert(!(lprops->flags & LPROPS_TAKEN));
- ubifs_assert((lprops->flags & LPROPS_INDEX));
- ubifs_assert(lprops->free + lprops->dirty == c->leb_size);
- return lprops;
-}
-
-/*
- * Everything below is related to debugging.
- */
-
-/**
- * dbg_check_cats - check category heaps and lists.
- * @c: UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int dbg_check_cats(struct ubifs_info *c)
-{
- struct ubifs_lprops *lprops;
- struct list_head *pos;
- int i, cat;
-
- if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
- return 0;
-
- list_for_each_entry(lprops, &c->empty_list, list) {
- if (lprops->free != c->leb_size) {
- ubifs_err(c, "non-empty LEB %d on empty list (free %d dirty %d flags %d)",
- lprops->lnum, lprops->free, lprops->dirty,
- lprops->flags);
- return -EINVAL;
- }
- if (lprops->flags & LPROPS_TAKEN) {
- ubifs_err(c, "taken LEB %d on empty list (free %d dirty %d flags %d)",
- lprops->lnum, lprops->free, lprops->dirty,
- lprops->flags);
- return -EINVAL;
- }
- }
-
- i = 0;
- list_for_each_entry(lprops, &c->freeable_list, list) {
- if (lprops->free + lprops->dirty != c->leb_size) {
- ubifs_err(c, "non-freeable LEB %d on freeable list (free %d dirty %d flags %d)",
- lprops->lnum, lprops->free, lprops->dirty,
- lprops->flags);
- return -EINVAL;
- }
- if (lprops->flags & LPROPS_TAKEN) {
- ubifs_err(c, "taken LEB %d on freeable list (free %d dirty %d flags %d)",
- lprops->lnum, lprops->free, lprops->dirty,
- lprops->flags);
- return -EINVAL;
- }
- i += 1;
- }
- if (i != c->freeable_cnt) {
- ubifs_err(c, "freeable list count %d expected %d", i,
- c->freeable_cnt);
- return -EINVAL;
- }
-
- i = 0;
- list_for_each(pos, &c->idx_gc)
- i += 1;
- if (i != c->idx_gc_cnt) {
- ubifs_err(c, "idx_gc list count %d expected %d", i,
- c->idx_gc_cnt);
- return -EINVAL;
- }
-
- list_for_each_entry(lprops, &c->frdi_idx_list, list) {
- if (lprops->free + lprops->dirty != c->leb_size) {
- ubifs_err(c, "non-freeable LEB %d on frdi_idx list (free %d dirty %d flags %d)",
- lprops->lnum, lprops->free, lprops->dirty,
- lprops->flags);
- return -EINVAL;
- }
- if (lprops->flags & LPROPS_TAKEN) {
- ubifs_err(c, "taken LEB %d on frdi_idx list (free %d dirty %d flags %d)",
- lprops->lnum, lprops->free, lprops->dirty,
- lprops->flags);
- return -EINVAL;
- }
- if (!(lprops->flags & LPROPS_INDEX)) {
- ubifs_err(c, "non-index LEB %d on frdi_idx list (free %d dirty %d flags %d)",
- lprops->lnum, lprops->free, lprops->dirty,
- lprops->flags);
- return -EINVAL;
- }
- }
-
- for (cat = 1; cat <= LPROPS_HEAP_CNT; cat++) {
- struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
-
- for (i = 0; i < heap->cnt; i++) {
- lprops = heap->arr[i];
- if (!lprops) {
- ubifs_err(c, "null ptr in LPT heap cat %d", cat);
- return -EINVAL;
- }
- if (lprops->hpos != i) {
- ubifs_err(c, "bad ptr in LPT heap cat %d", cat);
- return -EINVAL;
- }
- if (lprops->flags & LPROPS_TAKEN) {
- ubifs_err(c, "taken LEB in LPT heap cat %d", cat);
- return -EINVAL;
- }
- }
- }
-
- return 0;
-}
-
-void dbg_check_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat,
- int add_pos)
-{
- int i = 0, j, err = 0;
-
- if (!dbg_is_chk_gen(c) && !dbg_is_chk_lprops(c))
- return;
-
- for (i = 0; i < heap->cnt; i++) {
- struct ubifs_lprops *lprops = heap->arr[i];
- struct ubifs_lprops *lp;
-
- if (i != add_pos)
- if ((lprops->flags & LPROPS_CAT_MASK) != cat) {
- err = 1;
- goto out;
- }
- if (lprops->hpos != i) {
- err = 2;
- goto out;
- }
- lp = ubifs_lpt_lookup(c, lprops->lnum);
- if (IS_ERR(lp)) {
- err = 3;
- goto out;
- }
- if (lprops != lp) {
- ubifs_err(c, "lprops %zx lp %zx lprops->lnum %d lp->lnum %d",
- (size_t)lprops, (size_t)lp, lprops->lnum,
- lp->lnum);
- err = 4;
- goto out;
- }
- for (j = 0; j < i; j++) {
- lp = heap->arr[j];
- if (lp == lprops) {
- err = 5;
- goto out;
- }
- if (lp->lnum == lprops->lnum) {
- err = 6;
- goto out;
- }
- }
- }
-out:
- if (err) {
- ubifs_err(c, "failed cat %d hpos %d err %d", cat, i, err);
- dump_stack();
- ubifs_dump_heap(c, heap, cat);
- }
-}
-
-/**
- * scan_check_cb - scan callback.
- * @c: the UBIFS file-system description object
- * @lp: LEB properties to scan
- * @in_tree: whether the LEB properties are in main memory
- * @lst: lprops statistics to update
- *
- * This function returns a code that indicates whether the scan should continue
- * (%LPT_SCAN_CONTINUE), whether the LEB properties should be added to the tree
- * in main memory (%LPT_SCAN_ADD), or whether the scan should stop
- * (%LPT_SCAN_STOP).
- */
-static int scan_check_cb(struct ubifs_info *c,
- const struct ubifs_lprops *lp, int in_tree,
- struct ubifs_lp_stats *lst)
-{
- struct ubifs_scan_leb *sleb;
- struct ubifs_scan_node *snod;
- int cat, lnum = lp->lnum, is_idx = 0, used = 0, free, dirty, ret;
- void *buf = NULL;
-
- cat = lp->flags & LPROPS_CAT_MASK;
- if (cat != LPROPS_UNCAT) {
- cat = ubifs_categorize_lprops(c, lp);
- if (cat != (lp->flags & LPROPS_CAT_MASK)) {
- ubifs_err(c, "bad LEB category %d expected %d",
- (lp->flags & LPROPS_CAT_MASK), cat);
- return -EINVAL;
- }
- }
-
- /* Check lp is on its category list (if it has one) */
- if (in_tree) {
- struct list_head *list = NULL;
-
- switch (cat) {
- case LPROPS_EMPTY:
- list = &c->empty_list;
- break;
- case LPROPS_FREEABLE:
- list = &c->freeable_list;
- break;
- case LPROPS_FRDI_IDX:
- list = &c->frdi_idx_list;
- break;
- case LPROPS_UNCAT:
- list = &c->uncat_list;
- break;
- }
- if (list) {
- struct ubifs_lprops *lprops;
- int found = 0;
-
- list_for_each_entry(lprops, list, list) {
- if (lprops == lp) {
- found = 1;
- break;
- }
- }
- if (!found) {
- ubifs_err(c, "bad LPT list (category %d)", cat);
- return -EINVAL;
- }
- }
- }
-
- /* Check lp is on its category heap (if it has one) */
- if (in_tree && cat > 0 && cat <= LPROPS_HEAP_CNT) {
- struct ubifs_lpt_heap *heap = &c->lpt_heap[cat - 1];
-
- if ((lp->hpos != -1 && heap->arr[lp->hpos]->lnum != lnum) ||
- lp != heap->arr[lp->hpos]) {
- ubifs_err(c, "bad LPT heap (category %d)", cat);
- return -EINVAL;
- }
- }
-
- buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- /*
- * After an unclean unmount, empty and freeable LEBs
- * may contain garbage - do not scan them.
- */
- if (lp->free == c->leb_size) {
- lst->empty_lebs += 1;
- lst->total_free += c->leb_size;
- lst->total_dark += ubifs_calc_dark(c, c->leb_size);
- return LPT_SCAN_CONTINUE;
- }
- if (lp->free + lp->dirty == c->leb_size &&
- !(lp->flags & LPROPS_INDEX)) {
- lst->total_free += lp->free;
- lst->total_dirty += lp->dirty;
- lst->total_dark += ubifs_calc_dark(c, c->leb_size);
- return LPT_SCAN_CONTINUE;
- }
-
- sleb = ubifs_scan(c, lnum, 0, buf, 0);
- if (IS_ERR(sleb)) {
- ret = PTR_ERR(sleb);
- if (ret == -EUCLEAN) {
- ubifs_dump_lprops(c);
- ubifs_dump_budg(c, &c->bi);
- }
- goto out;
- }
-
- is_idx = -1;
- list_for_each_entry(snod, &sleb->nodes, list) {
- int found, level = 0;
-
- cond_resched();
-
- if (is_idx == -1)
- is_idx = (snod->type == UBIFS_IDX_NODE) ? 1 : 0;
-
- if (is_idx && snod->type != UBIFS_IDX_NODE) {
- ubifs_err(c, "indexing node in data LEB %d:%d",
- lnum, snod->offs);
- goto out_destroy;
- }
-
- if (snod->type == UBIFS_IDX_NODE) {
- struct ubifs_idx_node *idx = snod->node;
-
- key_read(c, ubifs_idx_key(c, idx), &snod->key);
- level = le16_to_cpu(idx->level);
- }
-
- found = ubifs_tnc_has_node(c, &snod->key, level, lnum,
- snod->offs, is_idx);
- if (found) {
- if (found < 0)
- goto out_destroy;
- used += ALIGN(snod->len, 8);
- }
- }
-
- free = c->leb_size - sleb->endpt;
- dirty = sleb->endpt - used;
-
- if (free > c->leb_size || free < 0 || dirty > c->leb_size ||
- dirty < 0) {
- ubifs_err(c, "bad calculated accounting for LEB %d: free %d, dirty %d",
- lnum, free, dirty);
- goto out_destroy;
- }
-
- if (lp->free + lp->dirty == c->leb_size &&
- free + dirty == c->leb_size)
- if ((is_idx && !(lp->flags & LPROPS_INDEX)) ||
- (!is_idx && free == c->leb_size) ||
- lp->free == c->leb_size) {
- /*
- * Empty or freeable LEBs could contain index
- * nodes from an uncompleted commit due to an
- * unclean unmount. Or they could be empty for
- * the same reason. Or it may simply not have been
- * unmapped.
- */
- free = lp->free;
- dirty = lp->dirty;
- is_idx = 0;
- }
-
- if (is_idx && lp->free + lp->dirty == free + dirty &&
- lnum != c->ihead_lnum) {
- /*
- * After an unclean unmount, an index LEB could have a different
- * amount of free space than the value recorded by lprops. That
- * is because the in-the-gaps method may use free space or
- * create free space (as a side-effect of using ubi_leb_change
- * and not writing the whole LEB). The incorrect free space
- * value is not a problem because the index is only ever
- * allocated empty LEBs, so there will never be an attempt to
- * write to the free space at the end of an index LEB - except
- * by the in-the-gaps method for which it is not a problem.
- */
- free = lp->free;
- dirty = lp->dirty;
- }
-
- if (lp->free != free || lp->dirty != dirty)
- goto out_print;
-
- if (is_idx && !(lp->flags & LPROPS_INDEX)) {
- if (free == c->leb_size)
- /* Free but not unmapped LEB, it's fine */
- is_idx = 0;
- else {
- ubifs_err(c, "indexing node without indexing flag");
- goto out_print;
- }
- }
-
- if (!is_idx && (lp->flags & LPROPS_INDEX)) {
- ubifs_err(c, "data node with indexing flag");
- goto out_print;
- }
-
- if (free == c->leb_size)
- lst->empty_lebs += 1;
-
- if (is_idx)
- lst->idx_lebs += 1;
-
- if (!(lp->flags & LPROPS_INDEX))
- lst->total_used += c->leb_size - free - dirty;
- lst->total_free += free;
- lst->total_dirty += dirty;
-
- if (!(lp->flags & LPROPS_INDEX)) {
- int spc = free + dirty;
-
- if (spc < c->dead_wm)
- lst->total_dead += spc;
- else
- lst->total_dark += ubifs_calc_dark(c, spc);
- }
-
- ubifs_scan_destroy(sleb);
- vfree(buf);
- return LPT_SCAN_CONTINUE;
-
-out_print:
- ubifs_err(c, "bad accounting of LEB %d: free %d, dirty %d flags %#x, should be free %d, dirty %d",
- lnum, lp->free, lp->dirty, lp->flags, free, dirty);
- ubifs_dump_leb(c, lnum);
-out_destroy:
- ubifs_scan_destroy(sleb);
- ret = -EINVAL;
-out:
- vfree(buf);
- return ret;
-}
-
-/**
- * dbg_check_lprops - check all LEB properties.
- * @c: UBIFS file-system description object
- *
- * This function checks all LEB properties and makes sure they are all correct.
- * It returns zero if everything is fine, %-EINVAL if there is an inconsistency
- * and other negative error codes in case of other errors. This function is
- * called while the file system is locked (because of commit start), so no
- * additional locking is required. Note that locking the LPT mutex would cause
- * a circular lock dependency with the TNC mutex.
- */
-int dbg_check_lprops(struct ubifs_info *c)
-{
- int i, err;
- struct ubifs_lp_stats lst;
-
- if (!dbg_is_chk_lprops(c))
- return 0;
-
- /*
- * As we are going to scan the media, the write buffers have to be
- * synchronized.
- */
- for (i = 0; i < c->jhead_cnt; i++) {
- err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
- if (err)
- return err;
- }
-
- memset(&lst, 0, sizeof(struct ubifs_lp_stats));
- err = ubifs_lpt_scan_nolock(c, c->main_first, c->leb_cnt - 1,
- (ubifs_lpt_scan_callback)scan_check_cb,
- &lst);
- if (err && err != -ENOSPC)
- goto out;
-
- if (lst.empty_lebs != c->lst.empty_lebs ||
- lst.idx_lebs != c->lst.idx_lebs ||
- lst.total_free != c->lst.total_free ||
- lst.total_dirty != c->lst.total_dirty ||
- lst.total_used != c->lst.total_used) {
- ubifs_err(c, "bad overall accounting");
- ubifs_err(c, "calculated: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
- lst.empty_lebs, lst.idx_lebs, lst.total_free,
- lst.total_dirty, lst.total_used);
- ubifs_err(c, "read from lprops: empty_lebs %d, idx_lebs %d, total_free %lld, total_dirty %lld, total_used %lld",
- c->lst.empty_lebs, c->lst.idx_lebs, c->lst.total_free,
- c->lst.total_dirty, c->lst.total_used);
- err = -EINVAL;
- goto out;
- }
-
- if (lst.total_dead != c->lst.total_dead ||
- lst.total_dark != c->lst.total_dark) {
- ubifs_err(c, "bad dead/dark space accounting");
- ubifs_err(c, "calculated: total_dead %lld, total_dark %lld",
- lst.total_dead, lst.total_dark);
- ubifs_err(c, "read from lprops: total_dead %lld, total_dark %lld",
- c->lst.total_dead, c->lst.total_dark);
- err = -EINVAL;
- goto out;
- }
-
- err = dbg_check_cats(c);
-out:
- return err;
-}
diff --git a/fs/ubifs/lpt.c b/fs/ubifs/lpt.c
deleted file mode 100644
index e1f2713df1..0000000000
--- a/fs/ubifs/lpt.c
+++ /dev/null
@@ -1,2282 +0,0 @@
-/*
- * This file is part of UBIFS.
- *
- * Copyright (C) 2006-2008 Nokia Corporation.
- *
- * SPDX-License-Identifier: GPL-2.0+
- *
- * Authors: Adrian Hunter
- * Artem Bityutskiy (Битюцкий Артём)
- */
-
-/*
- * This file implements the LEB properties tree (LPT) area. The LPT area
- * contains the LEB properties tree, a table of LPT area eraseblocks (ltab), and
- * (for the "big" model) a table of saved LEB numbers (lsave). The LPT area sits
- * between the log and the orphan area.
- *
- * The LPT area is like a miniature self-contained file system. It is required
- * that it never runs out of space, is fast to access and update, and scales
- * logarithmically. The LEB properties tree is implemented as a wandering tree
- * much like the TNC, and the LPT area has its own garbage collection.
- *
- * The LPT has two slightly different forms called the "small model" and the
- * "big model". The small model is used when the entire LEB properties table
- * can be written into a single eraseblock. In that case, garbage collection
- * consists of just writing the whole table, which therefore makes all other
- * eraseblocks reusable. In the case of the big model, dirty eraseblocks are
- * selected for garbage collection, which consists of marking the clean nodes in
- * that LEB as dirty, and then only the dirty nodes are written out. Also, in
- * the case of the big model, a table of LEB numbers is saved so that the entire
- * LPT does not to be scanned looking for empty eraseblocks when UBIFS is first
- * mounted.
- */
-
-#include "ubifs.h"
-#ifndef __BAREBOX__
-#include <linux/crc16.h>
-#include <linux/math64.h>
-#include <linux/slab.h>
-#else
-#include <linux/err.h>
-#include "crc16.h"
-#endif
-
-/**
- * do_calc_lpt_geom - calculate sizes for the LPT area.
- * @c: the UBIFS file-system description object
- *
- * Calculate the sizes of LPT bit fields, nodes, and tree, based on the
- * properties of the flash and whether LPT is "big" (c->big_lpt).
- */
-static void do_calc_lpt_geom(struct ubifs_info *c)
-{
- int i, n, bits, per_leb_wastage, max_pnode_cnt;
- long long sz, tot_wastage;
-
- n = c->main_lebs + c->max_leb_cnt - c->leb_cnt;
- max_pnode_cnt = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
-
- c->lpt_hght = 1;
- n = UBIFS_LPT_FANOUT;
- while (n < max_pnode_cnt) {
- c->lpt_hght += 1;
- n <<= UBIFS_LPT_FANOUT_SHIFT;
- }
-
- c->pnode_cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
-
- n = DIV_ROUND_UP(c->pnode_cnt, UBIFS_LPT_FANOUT);
- c->nnode_cnt = n;
- for (i = 1; i < c->lpt_hght; i++) {
- n = DIV_ROUND_UP(n, UBIFS_LPT_FANOUT);
- c->nnode_cnt += n;
- }
-
- c->space_bits = fls(c->leb_size) - 3;
- c->lpt_lnum_bits = fls(c->lpt_lebs);
- c->lpt_offs_bits = fls(c->leb_size - 1);
- c->lpt_spc_bits = fls(c->leb_size);
-
- n = DIV_ROUND_UP(c->max_leb_cnt, UBIFS_LPT_FANOUT);
- c->pcnt_bits = fls(n - 1);
-
- c->lnum_bits = fls(c->max_leb_cnt - 1);
-
- bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
- (c->big_lpt ? c->pcnt_bits : 0) +
- (c->space_bits * 2 + 1) * UBIFS_LPT_FANOUT;
- c->pnode_sz = (bits + 7) / 8;
-
- bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
- (c->big_lpt ? c->pcnt_bits : 0) +
- (c->lpt_lnum_bits + c->lpt_offs_bits) * UBIFS_LPT_FANOUT;
- c->nnode_sz = (bits + 7) / 8;
-
- bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
- c->lpt_lebs * c->lpt_spc_bits * 2;
- c->ltab_sz = (bits + 7) / 8;
-
- bits = UBIFS_LPT_CRC_BITS + UBIFS_LPT_TYPE_BITS +
- c->lnum_bits * c->lsave_cnt;
- c->lsave_sz = (bits + 7) / 8;
-
- /* Calculate the minimum LPT size */
- c->lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
- c->lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
- c->lpt_sz += c->ltab_sz;
- if (c->big_lpt)
- c->lpt_sz += c->lsave_sz;
-
- /* Add wastage */
- sz = c->lpt_sz;
- per_leb_wastage = max_t(int, c->pnode_sz, c->nnode_sz);
- sz += per_leb_wastage;
- tot_wastage = per_leb_wastage;
- while (sz > c->leb_size) {
- sz += per_leb_wastage;
- sz -= c->leb_size;
- tot_wastage += per_leb_wastage;
- }
- tot_wastage += ALIGN(sz, c->min_io_size) - sz;
- c->lpt_sz += tot_wastage;
-}
-
-/**
- * ubifs_calc_lpt_geom - calculate and check sizes for the LPT area.
- * @c: the UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_calc_lpt_geom(struct ubifs_info *c)
-{
- int lebs_needed;
- long long sz;
-
- do_calc_lpt_geom(c);
-
- /* Verify that lpt_lebs is big enough */
- sz = c->lpt_sz * 2; /* Must have at least 2 times the size */
- lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
- if (lebs_needed > c->lpt_lebs) {
- ubifs_err(c, "too few LPT LEBs");
- return -EINVAL;
- }
-
- /* Verify that ltab fits in a single LEB (since ltab is a single node */
- if (c->ltab_sz > c->leb_size) {
- ubifs_err(c, "LPT ltab too big");
- return -EINVAL;
- }
-
- c->check_lpt_free = c->big_lpt;
- return 0;
-}
-
-/**
- * calc_dflt_lpt_geom - calculate default LPT geometry.
- * @c: the UBIFS file-system description object
- * @main_lebs: number of main area LEBs is passed and returned here
- * @big_lpt: whether the LPT area is "big" is returned here
- *
- * The size of the LPT area depends on parameters that themselves are dependent
- * on the size of the LPT area. This function, successively recalculates the LPT
- * area geometry until the parameters and resultant geometry are consistent.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int calc_dflt_lpt_geom(struct ubifs_info *c, int *main_lebs,
- int *big_lpt)
-{
- int i, lebs_needed;
- long long sz;
-
- /* Start by assuming the minimum number of LPT LEBs */
- c->lpt_lebs = UBIFS_MIN_LPT_LEBS;
- c->main_lebs = *main_lebs - c->lpt_lebs;
- if (c->main_lebs <= 0)
- return -EINVAL;
-
- /* And assume we will use the small LPT model */
- c->big_lpt = 0;
-
- /*
- * Calculate the geometry based on assumptions above and then see if it
- * makes sense
- */
- do_calc_lpt_geom(c);
-
- /* Small LPT model must have lpt_sz < leb_size */
- if (c->lpt_sz > c->leb_size) {
- /* Nope, so try again using big LPT model */
- c->big_lpt = 1;
- do_calc_lpt_geom(c);
- }
-
- /* Now check there are enough LPT LEBs */
- for (i = 0; i < 64 ; i++) {
- sz = c->lpt_sz * 4; /* Allow 4 times the size */
- lebs_needed = div_u64(sz + c->leb_size - 1, c->leb_size);
- if (lebs_needed > c->lpt_lebs) {
- /* Not enough LPT LEBs so try again with more */
- c->lpt_lebs = lebs_needed;
- c->main_lebs = *main_lebs - c->lpt_lebs;
- if (c->main_lebs <= 0)
- return -EINVAL;
- do_calc_lpt_geom(c);
- continue;
- }
- if (c->ltab_sz > c->leb_size) {
- ubifs_err(c, "LPT ltab too big");
- return -EINVAL;
- }
- *main_lebs = c->main_lebs;
- *big_lpt = c->big_lpt;
- return 0;
- }
- return -EINVAL;
-}
-
-/**
- * pack_bits - pack bit fields end-to-end.
- * @addr: address at which to pack (passed and next address returned)
- * @pos: bit position at which to pack (passed and next position returned)
- * @val: value to pack
- * @nrbits: number of bits of value to pack (1-32)
- */
-static void pack_bits(uint8_t **addr, int *pos, uint32_t val, int nrbits)
-{
- uint8_t *p = *addr;
- int b = *pos;
-
- ubifs_assert(nrbits > 0);
- ubifs_assert(nrbits <= 32);
- ubifs_assert(*pos >= 0);
- ubifs_assert(*pos < 8);
- ubifs_assert((val >> nrbits) == 0 || nrbits == 32);
- if (b) {
- *p |= ((uint8_t)val) << b;
- nrbits += b;
- if (nrbits > 8) {
- *++p = (uint8_t)(val >>= (8 - b));
- if (nrbits > 16) {
- *++p = (uint8_t)(val >>= 8);
- if (nrbits > 24) {
- *++p = (uint8_t)(val >>= 8);
- if (nrbits > 32)
- *++p = (uint8_t)(val >>= 8);
- }
- }
- }
- } else {
- *p = (uint8_t)val;
- if (nrbits > 8) {
- *++p = (uint8_t)(val >>= 8);
- if (nrbits > 16) {
- *++p = (uint8_t)(val >>= 8);
- if (nrbits > 24)
- *++p = (uint8_t)(val >>= 8);
- }
- }
- }
- b = nrbits & 7;
- if (b == 0)
- p++;
- *addr = p;
- *pos = b;
-}
-
-/**
- * ubifs_unpack_bits - unpack bit fields.
- * @addr: address at which to unpack (passed and next address returned)
- * @pos: bit position at which to unpack (passed and next position returned)
- * @nrbits: number of bits of value to unpack (1-32)
- *
- * This functions returns the value unpacked.
- */
-uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits)
-{
- const int k = 32 - nrbits;
- uint8_t *p = *addr;
- int b = *pos;
- uint32_t uninitialized_var(val);
- const int bytes = (nrbits + b + 7) >> 3;
-
- ubifs_assert(nrbits > 0);
- ubifs_assert(nrbits <= 32);
- ubifs_assert(*pos >= 0);
- ubifs_assert(*pos < 8);
- if (b) {
- switch (bytes) {
- case 2:
- val = p[1];
- break;
- case 3:
- val = p[1] | ((uint32_t)p[2] << 8);
- break;
- case 4:
- val = p[1] | ((uint32_t)p[2] << 8) |
- ((uint32_t)p[3] << 16);
- break;
- case 5:
- val = p[1] | ((uint32_t)p[2] << 8) |
- ((uint32_t)p[3] << 16) |
- ((uint32_t)p[4] << 24);
- }
- val <<= (8 - b);
- val |= *p >> b;
- nrbits += b;
- } else {
- switch (bytes) {
- case 1:
- val = p[0];
- break;
- case 2:
- val = p[0] | ((uint32_t)p[1] << 8);
- break;
- case 3:
- val = p[0] | ((uint32_t)p[1] << 8) |
- ((uint32_t)p[2] << 16);
- break;
- case 4:
- val = p[0] | ((uint32_t)p[1] << 8) |
- ((uint32_t)p[2] << 16) |
- ((uint32_t)p[3] << 24);
- break;
- }
- }
- val <<= k;
- val >>= k;
- b = nrbits & 7;
- p += nrbits >> 3;
- *addr = p;
- *pos = b;
- ubifs_assert((val >> nrbits) == 0 || nrbits - b == 32);
- return val;
-}
-
-/**
- * ubifs_pack_pnode - pack all the bit fields of a pnode.
- * @c: UBIFS file-system description object
- * @buf: buffer into which to pack
- * @pnode: pnode to pack
- */
-void ubifs_pack_pnode(struct ubifs_info *c, void *buf,
- struct ubifs_pnode *pnode)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int i, pos = 0;
- uint16_t crc;
-
- pack_bits(&addr, &pos, UBIFS_LPT_PNODE, UBIFS_LPT_TYPE_BITS);
- if (c->big_lpt)
- pack_bits(&addr, &pos, pnode->num, c->pcnt_bits);
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- pack_bits(&addr, &pos, pnode->lprops[i].free >> 3,
- c->space_bits);
- pack_bits(&addr, &pos, pnode->lprops[i].dirty >> 3,
- c->space_bits);
- if (pnode->lprops[i].flags & LPROPS_INDEX)
- pack_bits(&addr, &pos, 1, 1);
- else
- pack_bits(&addr, &pos, 0, 1);
- }
- crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
- c->pnode_sz - UBIFS_LPT_CRC_BYTES);
- addr = buf;
- pos = 0;
- pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
-}
-
-/**
- * ubifs_pack_nnode - pack all the bit fields of a nnode.
- * @c: UBIFS file-system description object
- * @buf: buffer into which to pack
- * @nnode: nnode to pack
- */
-void ubifs_pack_nnode(struct ubifs_info *c, void *buf,
- struct ubifs_nnode *nnode)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int i, pos = 0;
- uint16_t crc;
-
- pack_bits(&addr, &pos, UBIFS_LPT_NNODE, UBIFS_LPT_TYPE_BITS);
- if (c->big_lpt)
- pack_bits(&addr, &pos, nnode->num, c->pcnt_bits);
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- int lnum = nnode->nbranch[i].lnum;
-
- if (lnum == 0)
- lnum = c->lpt_last + 1;
- pack_bits(&addr, &pos, lnum - c->lpt_first, c->lpt_lnum_bits);
- pack_bits(&addr, &pos, nnode->nbranch[i].offs,
- c->lpt_offs_bits);
- }
- crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
- c->nnode_sz - UBIFS_LPT_CRC_BYTES);
- addr = buf;
- pos = 0;
- pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
-}
-
-/**
- * ubifs_pack_ltab - pack the LPT's own lprops table.
- * @c: UBIFS file-system description object
- * @buf: buffer into which to pack
- * @ltab: LPT's own lprops table to pack
- */
-void ubifs_pack_ltab(struct ubifs_info *c, void *buf,
- struct ubifs_lpt_lprops *ltab)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int i, pos = 0;
- uint16_t crc;
-
- pack_bits(&addr, &pos, UBIFS_LPT_LTAB, UBIFS_LPT_TYPE_BITS);
- for (i = 0; i < c->lpt_lebs; i++) {
- pack_bits(&addr, &pos, ltab[i].free, c->lpt_spc_bits);
- pack_bits(&addr, &pos, ltab[i].dirty, c->lpt_spc_bits);
- }
- crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
- c->ltab_sz - UBIFS_LPT_CRC_BYTES);
- addr = buf;
- pos = 0;
- pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
-}
-
-/**
- * ubifs_pack_lsave - pack the LPT's save table.
- * @c: UBIFS file-system description object
- * @buf: buffer into which to pack
- * @lsave: LPT's save table to pack
- */
-void ubifs_pack_lsave(struct ubifs_info *c, void *buf, int *lsave)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int i, pos = 0;
- uint16_t crc;
-
- pack_bits(&addr, &pos, UBIFS_LPT_LSAVE, UBIFS_LPT_TYPE_BITS);
- for (i = 0; i < c->lsave_cnt; i++)
- pack_bits(&addr, &pos, lsave[i], c->lnum_bits);
- crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
- c->lsave_sz - UBIFS_LPT_CRC_BYTES);
- addr = buf;
- pos = 0;
- pack_bits(&addr, &pos, crc, UBIFS_LPT_CRC_BITS);
-}
-
-/**
- * ubifs_add_lpt_dirt - add dirty space to LPT LEB properties.
- * @c: UBIFS file-system description object
- * @lnum: LEB number to which to add dirty space
- * @dirty: amount of dirty space to add
- */
-void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty)
-{
- if (!dirty || !lnum)
- return;
- dbg_lp("LEB %d add %d to %d",
- lnum, dirty, c->ltab[lnum - c->lpt_first].dirty);
- ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
- c->ltab[lnum - c->lpt_first].dirty += dirty;
-}
-
-/**
- * set_ltab - set LPT LEB properties.
- * @c: UBIFS file-system description object
- * @lnum: LEB number
- * @free: amount of free space
- * @dirty: amount of dirty space
- */
-static void set_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
-{
- dbg_lp("LEB %d free %d dirty %d to %d %d",
- lnum, c->ltab[lnum - c->lpt_first].free,
- c->ltab[lnum - c->lpt_first].dirty, free, dirty);
- ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
- c->ltab[lnum - c->lpt_first].free = free;
- c->ltab[lnum - c->lpt_first].dirty = dirty;
-}
-
-/**
- * ubifs_add_nnode_dirt - add dirty space to LPT LEB properties.
- * @c: UBIFS file-system description object
- * @nnode: nnode for which to add dirt
- */
-void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode)
-{
- struct ubifs_nnode *np = nnode->parent;
-
- if (np)
- ubifs_add_lpt_dirt(c, np->nbranch[nnode->iip].lnum,
- c->nnode_sz);
- else {
- ubifs_add_lpt_dirt(c, c->lpt_lnum, c->nnode_sz);
- if (!(c->lpt_drty_flgs & LTAB_DIRTY)) {
- c->lpt_drty_flgs |= LTAB_DIRTY;
- ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz);
- }
- }
-}
-
-/**
- * add_pnode_dirt - add dirty space to LPT LEB properties.
- * @c: UBIFS file-system description object
- * @pnode: pnode for which to add dirt
- */
-static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode)
-{
- ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum,
- c->pnode_sz);
-}
-
-/**
- * calc_nnode_num - calculate nnode number.
- * @row: the row in the tree (root is zero)
- * @col: the column in the row (leftmost is zero)
- *
- * The nnode number is a number that uniquely identifies a nnode and can be used
- * easily to traverse the tree from the root to that nnode.
- *
- * This function calculates and returns the nnode number for the nnode at @row
- * and @col.
- */
-static int calc_nnode_num(int row, int col)
-{
- int num, bits;
-
- num = 1;
- while (row--) {
- bits = (col & (UBIFS_LPT_FANOUT - 1));
- col >>= UBIFS_LPT_FANOUT_SHIFT;
- num <<= UBIFS_LPT_FANOUT_SHIFT;
- num |= bits;
- }
- return num;
-}
-
-/**
- * calc_nnode_num_from_parent - calculate nnode number.
- * @c: UBIFS file-system description object
- * @parent: parent nnode
- * @iip: index in parent
- *
- * The nnode number is a number that uniquely identifies a nnode and can be used
- * easily to traverse the tree from the root to that nnode.
- *
- * This function calculates and returns the nnode number based on the parent's
- * nnode number and the index in parent.
- */
-static int calc_nnode_num_from_parent(const struct ubifs_info *c,
- struct ubifs_nnode *parent, int iip)
-{
- int num, shft;
-
- if (!parent)
- return 1;
- shft = (c->lpt_hght - parent->level) * UBIFS_LPT_FANOUT_SHIFT;
- num = parent->num ^ (1 << shft);
- num |= (UBIFS_LPT_FANOUT + iip) << shft;
- return num;
-}
-
-/**
- * calc_pnode_num_from_parent - calculate pnode number.
- * @c: UBIFS file-system description object
- * @parent: parent nnode
- * @iip: index in parent
- *
- * The pnode number is a number that uniquely identifies a pnode and can be used
- * easily to traverse the tree from the root to that pnode.
- *
- * This function calculates and returns the pnode number based on the parent's
- * nnode number and the index in parent.
- */
-static int calc_pnode_num_from_parent(const struct ubifs_info *c,
- struct ubifs_nnode *parent, int iip)
-{
- int i, n = c->lpt_hght - 1, pnum = parent->num, num = 0;
-
- for (i = 0; i < n; i++) {
- num <<= UBIFS_LPT_FANOUT_SHIFT;
- num |= pnum & (UBIFS_LPT_FANOUT - 1);
- pnum >>= UBIFS_LPT_FANOUT_SHIFT;
- }
- num <<= UBIFS_LPT_FANOUT_SHIFT;
- num |= iip;
- return num;
-}
-
-/**
- * ubifs_create_dflt_lpt - create default LPT.
- * @c: UBIFS file-system description object
- * @main_lebs: number of main area LEBs is passed and returned here
- * @lpt_first: LEB number of first LPT LEB
- * @lpt_lebs: number of LEBs for LPT is passed and returned here
- * @big_lpt: use big LPT model is passed and returned here
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first,
- int *lpt_lebs, int *big_lpt)
-{
- int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row;
- int blnum, boffs, bsz, bcnt;
- struct ubifs_pnode *pnode = NULL;
- struct ubifs_nnode *nnode = NULL;
- void *buf = NULL, *p;
- struct ubifs_lpt_lprops *ltab = NULL;
- int *lsave = NULL;
-
- err = calc_dflt_lpt_geom(c, main_lebs, big_lpt);
- if (err)
- return err;
- *lpt_lebs = c->lpt_lebs;
-
- /* Needed by 'ubifs_pack_nnode()' and 'set_ltab()' */
- c->lpt_first = lpt_first;
- /* Needed by 'set_ltab()' */
- c->lpt_last = lpt_first + c->lpt_lebs - 1;
- /* Needed by 'ubifs_pack_lsave()' */
- c->main_first = c->leb_cnt - *main_lebs;
-
- lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_KERNEL);
- pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL);
- nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL);
- buf = vmalloc(c->leb_size);
- ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
- if (!pnode || !nnode || !buf || !ltab || !lsave) {
- err = -ENOMEM;
- goto out;
- }
-
- ubifs_assert(!c->ltab);
- c->ltab = ltab; /* Needed by set_ltab */
-
- /* Initialize LPT's own lprops */
- for (i = 0; i < c->lpt_lebs; i++) {
- ltab[i].free = c->leb_size;
- ltab[i].dirty = 0;
- ltab[i].tgc = 0;
- ltab[i].cmt = 0;
- }
-
- lnum = lpt_first;
- p = buf;
- /* Number of leaf nodes (pnodes) */
- cnt = c->pnode_cnt;
-
- /*
- * The first pnode contains the LEB properties for the LEBs that contain
- * the root inode node and the root index node of the index tree.
- */
- node_sz = ALIGN(ubifs_idx_node_sz(c, 1), 8);
- iopos = ALIGN(node_sz, c->min_io_size);
- pnode->lprops[0].free = c->leb_size - iopos;
- pnode->lprops[0].dirty = iopos - node_sz;
- pnode->lprops[0].flags = LPROPS_INDEX;
-
- node_sz = UBIFS_INO_NODE_SZ;
- iopos = ALIGN(node_sz, c->min_io_size);
- pnode->lprops[1].free = c->leb_size - iopos;
- pnode->lprops[1].dirty = iopos - node_sz;
-
- for (i = 2; i < UBIFS_LPT_FANOUT; i++)
- pnode->lprops[i].free = c->leb_size;
-
- /* Add first pnode */
- ubifs_pack_pnode(c, p, pnode);
- p += c->pnode_sz;
- len = c->pnode_sz;
- pnode->num += 1;
-
- /* Reset pnode values for remaining pnodes */
- pnode->lprops[0].free = c->leb_size;
- pnode->lprops[0].dirty = 0;
- pnode->lprops[0].flags = 0;
-
- pnode->lprops[1].free = c->leb_size;
- pnode->lprops[1].dirty = 0;
-
- /*
- * To calculate the internal node branches, we keep information about
- * the level below.
- */
- blnum = lnum; /* LEB number of level below */
- boffs = 0; /* Offset of level below */
- bcnt = cnt; /* Number of nodes in level below */
- bsz = c->pnode_sz; /* Size of nodes in level below */
-
- /* Add all remaining pnodes */
- for (i = 1; i < cnt; i++) {
- if (len + c->pnode_sz > c->leb_size) {
- alen = ALIGN(len, c->min_io_size);
- set_ltab(c, lnum, c->leb_size - alen, alen - len);
- memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum++, buf, alen);
- if (err)
- goto out;
- p = buf;
- len = 0;
- }
- ubifs_pack_pnode(c, p, pnode);
- p += c->pnode_sz;
- len += c->pnode_sz;
- /*
- * pnodes are simply numbered left to right starting at zero,
- * which means the pnode number can be used easily to traverse
- * down the tree to the corresponding pnode.
- */
- pnode->num += 1;
- }
-
- row = 0;
- for (i = UBIFS_LPT_FANOUT; cnt > i; i <<= UBIFS_LPT_FANOUT_SHIFT)
- row += 1;
- /* Add all nnodes, one level at a time */
- while (1) {
- /* Number of internal nodes (nnodes) at next level */
- cnt = DIV_ROUND_UP(cnt, UBIFS_LPT_FANOUT);
- for (i = 0; i < cnt; i++) {
- if (len + c->nnode_sz > c->leb_size) {
- alen = ALIGN(len, c->min_io_size);
- set_ltab(c, lnum, c->leb_size - alen,
- alen - len);
- memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum++, buf, alen);
- if (err)
- goto out;
- p = buf;
- len = 0;
- }
- /* Only 1 nnode at this level, so it is the root */
- if (cnt == 1) {
- c->lpt_lnum = lnum;
- c->lpt_offs = len;
- }
- /* Set branches to the level below */
- for (j = 0; j < UBIFS_LPT_FANOUT; j++) {
- if (bcnt) {
- if (boffs + bsz > c->leb_size) {
- blnum += 1;
- boffs = 0;
- }
- nnode->nbranch[j].lnum = blnum;
- nnode->nbranch[j].offs = boffs;
- boffs += bsz;
- bcnt--;
- } else {
- nnode->nbranch[j].lnum = 0;
- nnode->nbranch[j].offs = 0;
- }
- }
- nnode->num = calc_nnode_num(row, i);
- ubifs_pack_nnode(c, p, nnode);
- p += c->nnode_sz;
- len += c->nnode_sz;
- }
- /* Only 1 nnode at this level, so it is the root */
- if (cnt == 1)
- break;
- /* Update the information about the level below */
- bcnt = cnt;
- bsz = c->nnode_sz;
- row -= 1;
- }
-
- if (*big_lpt) {
- /* Need to add LPT's save table */
- if (len + c->lsave_sz > c->leb_size) {
- alen = ALIGN(len, c->min_io_size);
- set_ltab(c, lnum, c->leb_size - alen, alen - len);
- memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum++, buf, alen);
- if (err)
- goto out;
- p = buf;
- len = 0;
- }
-
- c->lsave_lnum = lnum;
- c->lsave_offs = len;
-
- for (i = 0; i < c->lsave_cnt && i < *main_lebs; i++)
- lsave[i] = c->main_first + i;
- for (; i < c->lsave_cnt; i++)
- lsave[i] = c->main_first;
-
- ubifs_pack_lsave(c, p, lsave);
- p += c->lsave_sz;
- len += c->lsave_sz;
- }
-
- /* Need to add LPT's own LEB properties table */
- if (len + c->ltab_sz > c->leb_size) {
- alen = ALIGN(len, c->min_io_size);
- set_ltab(c, lnum, c->leb_size - alen, alen - len);
- memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum++, buf, alen);
- if (err)
- goto out;
- p = buf;
- len = 0;
- }
-
- c->ltab_lnum = lnum;
- c->ltab_offs = len;
-
- /* Update ltab before packing it */
- len += c->ltab_sz;
- alen = ALIGN(len, c->min_io_size);
- set_ltab(c, lnum, c->leb_size - alen, alen - len);
-
- ubifs_pack_ltab(c, p, ltab);
- p += c->ltab_sz;
-
- /* Write remaining buffer */
- memset(p, 0xff, alen - len);
- err = ubifs_leb_change(c, lnum, buf, alen);
- if (err)
- goto out;
-
- c->nhead_lnum = lnum;
- c->nhead_offs = ALIGN(len, c->min_io_size);
-
- dbg_lp("space_bits %d", c->space_bits);
- dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
- dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
- dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
- dbg_lp("pcnt_bits %d", c->pcnt_bits);
- dbg_lp("lnum_bits %d", c->lnum_bits);
- dbg_lp("pnode_sz %d", c->pnode_sz);
- dbg_lp("nnode_sz %d", c->nnode_sz);
- dbg_lp("ltab_sz %d", c->ltab_sz);
- dbg_lp("lsave_sz %d", c->lsave_sz);
- dbg_lp("lsave_cnt %d", c->lsave_cnt);
- dbg_lp("lpt_hght %d", c->lpt_hght);
- dbg_lp("big_lpt %d", c->big_lpt);
- dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
- dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
- dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
- if (c->big_lpt)
- dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
-out:
- c->ltab = NULL;
- kfree(lsave);
- vfree(ltab);
- vfree(buf);
- kfree(nnode);
- kfree(pnode);
- return err;
-}
-
-/**
- * update_cats - add LEB properties of a pnode to LEB category lists and heaps.
- * @c: UBIFS file-system description object
- * @pnode: pnode
- *
- * When a pnode is loaded into memory, the LEB properties it contains are added,
- * by this function, to the LEB category lists and heaps.
- */
-static void update_cats(struct ubifs_info *c, struct ubifs_pnode *pnode)
-{
- int i;
-
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- int cat = pnode->lprops[i].flags & LPROPS_CAT_MASK;
- int lnum = pnode->lprops[i].lnum;
-
- if (!lnum)
- return;
- ubifs_add_to_cat(c, &pnode->lprops[i], cat);
- }
-}
-
-/**
- * replace_cats - add LEB properties of a pnode to LEB category lists and heaps.
- * @c: UBIFS file-system description object
- * @old_pnode: pnode copied
- * @new_pnode: pnode copy
- *
- * During commit it is sometimes necessary to copy a pnode
- * (see dirty_cow_pnode). When that happens, references in
- * category lists and heaps must be replaced. This function does that.
- */
-static void replace_cats(struct ubifs_info *c, struct ubifs_pnode *old_pnode,
- struct ubifs_pnode *new_pnode)
-{
- int i;
-
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- if (!new_pnode->lprops[i].lnum)
- return;
- ubifs_replace_cat(c, &old_pnode->lprops[i],
- &new_pnode->lprops[i]);
- }
-}
-
-/**
- * check_lpt_crc - check LPT node crc is correct.
- * @c: UBIFS file-system description object
- * @buf: buffer containing node
- * @len: length of node
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int check_lpt_crc(const struct ubifs_info *c, void *buf, int len)
-{
- int pos = 0;
- uint8_t *addr = buf;
- uint16_t crc, calc_crc;
-
- crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS);
- calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
- len - UBIFS_LPT_CRC_BYTES);
- if (crc != calc_crc) {
- ubifs_err(c, "invalid crc in LPT node: crc %hx calc %hx",
- crc, calc_crc);
- dump_stack();
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * check_lpt_type - check LPT node type is correct.
- * @c: UBIFS file-system description object
- * @addr: address of type bit field is passed and returned updated here
- * @pos: position of type bit field is passed and returned updated here
- * @type: expected type
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int check_lpt_type(const struct ubifs_info *c, uint8_t **addr,
- int *pos, int type)
-{
- int node_type;
-
- node_type = ubifs_unpack_bits(addr, pos, UBIFS_LPT_TYPE_BITS);
- if (node_type != type) {
- ubifs_err(c, "invalid type (%d) in LPT node type %d",
- node_type, type);
- dump_stack();
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * unpack_pnode - unpack a pnode.
- * @c: UBIFS file-system description object
- * @buf: buffer containing packed pnode to unpack
- * @pnode: pnode structure to fill
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int unpack_pnode(const struct ubifs_info *c, void *buf,
- struct ubifs_pnode *pnode)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int i, pos = 0, err;
-
- err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_PNODE);
- if (err)
- return err;
- if (c->big_lpt)
- pnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- struct ubifs_lprops * const lprops = &pnode->lprops[i];
-
- lprops->free = ubifs_unpack_bits(&addr, &pos, c->space_bits);
- lprops->free <<= 3;
- lprops->dirty = ubifs_unpack_bits(&addr, &pos, c->space_bits);
- lprops->dirty <<= 3;
-
- if (ubifs_unpack_bits(&addr, &pos, 1))
- lprops->flags = LPROPS_INDEX;
- else
- lprops->flags = 0;
- lprops->flags |= ubifs_categorize_lprops(c, lprops);
- }
- err = check_lpt_crc(c, buf, c->pnode_sz);
- return err;
-}
-
-/**
- * ubifs_unpack_nnode - unpack a nnode.
- * @c: UBIFS file-system description object
- * @buf: buffer containing packed nnode to unpack
- * @nnode: nnode structure to fill
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
- struct ubifs_nnode *nnode)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int i, pos = 0, err;
-
- err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_NNODE);
- if (err)
- return err;
- if (c->big_lpt)
- nnode->num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- int lnum;
-
- lnum = ubifs_unpack_bits(&addr, &pos, c->lpt_lnum_bits) +
- c->lpt_first;
- if (lnum == c->lpt_last + 1)
- lnum = 0;
- nnode->nbranch[i].lnum = lnum;
- nnode->nbranch[i].offs = ubifs_unpack_bits(&addr, &pos,
- c->lpt_offs_bits);
- }
- err = check_lpt_crc(c, buf, c->nnode_sz);
- return err;
-}
-
-/**
- * unpack_ltab - unpack the LPT's own lprops table.
- * @c: UBIFS file-system description object
- * @buf: buffer from which to unpack
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int unpack_ltab(const struct ubifs_info *c, void *buf)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int i, pos = 0, err;
-
- err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_LTAB);
- if (err)
- return err;
- for (i = 0; i < c->lpt_lebs; i++) {
- int free = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
- int dirty = ubifs_unpack_bits(&addr, &pos, c->lpt_spc_bits);
-
- if (free < 0 || free > c->leb_size || dirty < 0 ||
- dirty > c->leb_size || free + dirty > c->leb_size)
- return -EINVAL;
-
- c->ltab[i].free = free;
- c->ltab[i].dirty = dirty;
- c->ltab[i].tgc = 0;
- c->ltab[i].cmt = 0;
- }
- err = check_lpt_crc(c, buf, c->ltab_sz);
- return err;
-}
-
-#ifndef __BAREBOX__
-/**
- * unpack_lsave - unpack the LPT's save table.
- * @c: UBIFS file-system description object
- * @buf: buffer from which to unpack
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int unpack_lsave(const struct ubifs_info *c, void *buf)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int i, pos = 0, err;
-
- err = check_lpt_type(c, &addr, &pos, UBIFS_LPT_LSAVE);
- if (err)
- return err;
- for (i = 0; i < c->lsave_cnt; i++) {
- int lnum = ubifs_unpack_bits(&addr, &pos, c->lnum_bits);
-
- if (lnum < c->main_first || lnum >= c->leb_cnt)
- return -EINVAL;
- c->lsave[i] = lnum;
- }
- err = check_lpt_crc(c, buf, c->lsave_sz);
- return err;
-}
-#endif
-
-/**
- * validate_nnode - validate a nnode.
- * @c: UBIFS file-system description object
- * @nnode: nnode to validate
- * @parent: parent nnode (or NULL for the root nnode)
- * @iip: index in parent
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int validate_nnode(const struct ubifs_info *c, struct ubifs_nnode *nnode,
- struct ubifs_nnode *parent, int iip)
-{
- int i, lvl, max_offs;
-
- if (c->big_lpt) {
- int num = calc_nnode_num_from_parent(c, parent, iip);
-
- if (nnode->num != num)
- return -EINVAL;
- }
- lvl = parent ? parent->level - 1 : c->lpt_hght;
- if (lvl < 1)
- return -EINVAL;
- if (lvl == 1)
- max_offs = c->leb_size - c->pnode_sz;
- else
- max_offs = c->leb_size - c->nnode_sz;
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- int lnum = nnode->nbranch[i].lnum;
- int offs = nnode->nbranch[i].offs;
-
- if (lnum == 0) {
- if (offs != 0)
- return -EINVAL;
- continue;
- }
- if (lnum < c->lpt_first || lnum > c->lpt_last)
- return -EINVAL;
- if (offs < 0 || offs > max_offs)
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * validate_pnode - validate a pnode.
- * @c: UBIFS file-system description object
- * @pnode: pnode to validate
- * @parent: parent nnode
- * @iip: index in parent
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int validate_pnode(const struct ubifs_info *c, struct ubifs_pnode *pnode,
- struct ubifs_nnode *parent, int iip)
-{
- int i;
-
- if (c->big_lpt) {
- int num = calc_pnode_num_from_parent(c, parent, iip);
-
- if (pnode->num != num)
- return -EINVAL;
- }
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- int free = pnode->lprops[i].free;
- int dirty = pnode->lprops[i].dirty;
-
- if (free < 0 || free > c->leb_size || free % c->min_io_size ||
- (free & 7))
- return -EINVAL;
- if (dirty < 0 || dirty > c->leb_size || (dirty & 7))
- return -EINVAL;
- if (dirty + free > c->leb_size)
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * set_pnode_lnum - set LEB numbers on a pnode.
- * @c: UBIFS file-system description object
- * @pnode: pnode to update
- *
- * This function calculates the LEB numbers for the LEB properties it contains
- * based on the pnode number.
- */
-static void set_pnode_lnum(const struct ubifs_info *c,
- struct ubifs_pnode *pnode)
-{
- int i, lnum;
-
- lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + c->main_first;
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- if (lnum >= c->leb_cnt)
- return;
- pnode->lprops[i].lnum = lnum++;
- }
-}
-
-/**
- * ubifs_read_nnode - read a nnode from flash and link it to the tree in memory.
- * @c: UBIFS file-system description object
- * @parent: parent nnode (or NULL for the root)
- * @iip: index in parent
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
-{
- struct ubifs_nbranch *branch = NULL;
- struct ubifs_nnode *nnode = NULL;
- void *buf = c->lpt_nod_buf;
- int err, lnum, offs;
-
- if (parent) {
- branch = &parent->nbranch[iip];
- lnum = branch->lnum;
- offs = branch->offs;
- } else {
- lnum = c->lpt_lnum;
- offs = c->lpt_offs;
- }
- nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
- if (!nnode) {
- err = -ENOMEM;
- goto out;
- }
- if (lnum == 0) {
- /*
- * This nnode was not written which just means that the LEB
- * properties in the subtree below it describe empty LEBs. We
- * make the nnode as though we had read it, which in fact means
- * doing almost nothing.
- */
- if (c->big_lpt)
- nnode->num = calc_nnode_num_from_parent(c, parent, iip);
- } else {
- err = ubifs_leb_read(c, lnum, buf, offs, c->nnode_sz, 1);
- if (err)
- goto out;
- err = ubifs_unpack_nnode(c, buf, nnode);
- if (err)
- goto out;
- }
- err = validate_nnode(c, nnode, parent, iip);
- if (err)
- goto out;
- if (!c->big_lpt)
- nnode->num = calc_nnode_num_from_parent(c, parent, iip);
- if (parent) {
- branch->nnode = nnode;
- nnode->level = parent->level - 1;
- } else {
- c->nroot = nnode;
- nnode->level = c->lpt_hght;
- }
- nnode->parent = parent;
- nnode->iip = iip;
- return 0;
-
-out:
- ubifs_err(c, "error %d reading nnode at %d:%d", err, lnum, offs);
- dump_stack();
- kfree(nnode);
- return err;
-}
-
-/**
- * read_pnode - read a pnode from flash and link it to the tree in memory.
- * @c: UBIFS file-system description object
- * @parent: parent nnode
- * @iip: index in parent
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int read_pnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip)
-{
- struct ubifs_nbranch *branch;
- struct ubifs_pnode *pnode = NULL;
- void *buf = c->lpt_nod_buf;
- int err, lnum, offs;
-
- branch = &parent->nbranch[iip];
- lnum = branch->lnum;
- offs = branch->offs;
- pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
- if (!pnode)
- return -ENOMEM;
-
- if (lnum == 0) {
- /*
- * This pnode was not written which just means that the LEB
- * properties in it describe empty LEBs. We make the pnode as
- * though we had read it.
- */
- int i;
-
- if (c->big_lpt)
- pnode->num = calc_pnode_num_from_parent(c, parent, iip);
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- struct ubifs_lprops * const lprops = &pnode->lprops[i];
-
- lprops->free = c->leb_size;
- lprops->flags = ubifs_categorize_lprops(c, lprops);
- }
- } else {
- err = ubifs_leb_read(c, lnum, buf, offs, c->pnode_sz, 1);
- if (err)
- goto out;
- err = unpack_pnode(c, buf, pnode);
- if (err)
- goto out;
- }
- err = validate_pnode(c, pnode, parent, iip);
- if (err)
- goto out;
- if (!c->big_lpt)
- pnode->num = calc_pnode_num_from_parent(c, parent, iip);
- branch->pnode = pnode;
- pnode->parent = parent;
- pnode->iip = iip;
- set_pnode_lnum(c, pnode);
- c->pnodes_have += 1;
- return 0;
-
-out:
- ubifs_err(c, "error %d reading pnode at %d:%d", err, lnum, offs);
- ubifs_dump_pnode(c, pnode, parent, iip);
- dump_stack();
- ubifs_err(c, "calc num: %d", calc_pnode_num_from_parent(c, parent, iip));
- kfree(pnode);
- return err;
-}
-
-/**
- * read_ltab - read LPT's own lprops table.
- * @c: UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int read_ltab(struct ubifs_info *c)
-{
- int err;
- void *buf;
-
- buf = vmalloc(c->ltab_sz);
- if (!buf)
- return -ENOMEM;
- err = ubifs_leb_read(c, c->ltab_lnum, buf, c->ltab_offs, c->ltab_sz, 1);
- if (err)
- goto out;
- err = unpack_ltab(c, buf);
-out:
- vfree(buf);
- return err;
-}
-
-#ifndef __BAREBOX__
-/**
- * read_lsave - read LPT's save table.
- * @c: UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int read_lsave(struct ubifs_info *c)
-{
- int err, i;
- void *buf;
-
- buf = vmalloc(c->lsave_sz);
- if (!buf)
- return -ENOMEM;
- err = ubifs_leb_read(c, c->lsave_lnum, buf, c->lsave_offs,
- c->lsave_sz, 1);
- if (err)
- goto out;
- err = unpack_lsave(c, buf);
- if (err)
- goto out;
- for (i = 0; i < c->lsave_cnt; i++) {
- int lnum = c->lsave[i];
- struct ubifs_lprops *lprops;
-
- /*
- * Due to automatic resizing, the values in the lsave table
- * could be beyond the volume size - just ignore them.
- */
- if (lnum >= c->leb_cnt)
- continue;
- lprops = ubifs_lpt_lookup(c, lnum);
- if (IS_ERR(lprops)) {
- err = PTR_ERR(lprops);
- goto out;
- }
- }
-out:
- vfree(buf);
- return err;
-}
-#endif
-
-/**
- * ubifs_get_nnode - get a nnode.
- * @c: UBIFS file-system description object
- * @parent: parent nnode (or NULL for the root)
- * @iip: index in parent
- *
- * This function returns a pointer to the nnode on success or a negative error
- * code on failure.
- */
-struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
- struct ubifs_nnode *parent, int iip)
-{
- struct ubifs_nbranch *branch;
- struct ubifs_nnode *nnode;
- int err;
-
- branch = &parent->nbranch[iip];
- nnode = branch->nnode;
- if (nnode)
- return nnode;
- err = ubifs_read_nnode(c, parent, iip);
- if (err)
- return ERR_PTR(err);
- return branch->nnode;
-}
-
-/**
- * ubifs_get_pnode - get a pnode.
- * @c: UBIFS file-system description object
- * @parent: parent nnode
- * @iip: index in parent
- *
- * This function returns a pointer to the pnode on success or a negative error
- * code on failure.
- */
-struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c,
- struct ubifs_nnode *parent, int iip)
-{
- struct ubifs_nbranch *branch;
- struct ubifs_pnode *pnode;
- int err;
-
- branch = &parent->nbranch[iip];
- pnode = branch->pnode;
- if (pnode)
- return pnode;
- err = read_pnode(c, parent, iip);
- if (err)
- return ERR_PTR(err);
- update_cats(c, branch->pnode);
- return branch->pnode;
-}
-
-/**
- * ubifs_lpt_lookup - lookup LEB properties in the LPT.
- * @c: UBIFS file-system description object
- * @lnum: LEB number to lookup
- *
- * This function returns a pointer to the LEB properties on success or a
- * negative error code on failure.
- */
-struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum)
-{
- int err, i, h, iip, shft;
- struct ubifs_nnode *nnode;
- struct ubifs_pnode *pnode;
-
- if (!c->nroot) {
- err = ubifs_read_nnode(c, NULL, 0);
- if (err)
- return ERR_PTR(err);
- }
- nnode = c->nroot;
- i = lnum - c->main_first;
- shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
- for (h = 1; h < c->lpt_hght; h++) {
- iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
- shft -= UBIFS_LPT_FANOUT_SHIFT;
- nnode = ubifs_get_nnode(c, nnode, iip);
- if (IS_ERR(nnode))
- return ERR_CAST(nnode);
- }
- iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
- pnode = ubifs_get_pnode(c, nnode, iip);
- if (IS_ERR(pnode))
- return ERR_CAST(pnode);
- iip = (i & (UBIFS_LPT_FANOUT - 1));
- dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
- pnode->lprops[iip].free, pnode->lprops[iip].dirty,
- pnode->lprops[iip].flags);
- return &pnode->lprops[iip];
-}
-
-/**
- * dirty_cow_nnode - ensure a nnode is not being committed.
- * @c: UBIFS file-system description object
- * @nnode: nnode to check
- *
- * Returns dirtied nnode on success or negative error code on failure.
- */
-static struct ubifs_nnode *dirty_cow_nnode(struct ubifs_info *c,
- struct ubifs_nnode *nnode)
-{
- struct ubifs_nnode *n;
- int i;
-
- if (!test_bit(COW_CNODE, &nnode->flags)) {
- /* nnode is not being committed */
- if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
- c->dirty_nn_cnt += 1;
- ubifs_add_nnode_dirt(c, nnode);
- }
- return nnode;
- }
-
- /* nnode is being committed, so copy it */
- n = kmalloc(sizeof(struct ubifs_nnode), GFP_NOFS);
- if (unlikely(!n))
- return ERR_PTR(-ENOMEM);
-
- memcpy(n, nnode, sizeof(struct ubifs_nnode));
- n->cnext = NULL;
- __set_bit(DIRTY_CNODE, &n->flags);
- __clear_bit(COW_CNODE, &n->flags);
-
- /* The children now have new parent */
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- struct ubifs_nbranch *branch = &n->nbranch[i];
-
- if (branch->cnode)
- branch->cnode->parent = n;
- }
-
- ubifs_assert(!test_bit(OBSOLETE_CNODE, &nnode->flags));
- __set_bit(OBSOLETE_CNODE, &nnode->flags);
-
- c->dirty_nn_cnt += 1;
- ubifs_add_nnode_dirt(c, nnode);
- if (nnode->parent)
- nnode->parent->nbranch[n->iip].nnode = n;
- else
- c->nroot = n;
- return n;
-}
-
-/**
- * dirty_cow_pnode - ensure a pnode is not being committed.
- * @c: UBIFS file-system description object
- * @pnode: pnode to check
- *
- * Returns dirtied pnode on success or negative error code on failure.
- */
-static struct ubifs_pnode *dirty_cow_pnode(struct ubifs_info *c,
- struct ubifs_pnode *pnode)
-{
- struct ubifs_pnode *p;
-
- if (!test_bit(COW_CNODE, &pnode->flags)) {
- /* pnode is not being committed */
- if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
- c->dirty_pn_cnt += 1;
- add_pnode_dirt(c, pnode);
- }
- return pnode;
- }
-
- /* pnode is being committed, so copy it */
- p = kmalloc(sizeof(struct ubifs_pnode), GFP_NOFS);
- if (unlikely(!p))
- return ERR_PTR(-ENOMEM);
-
- memcpy(p, pnode, sizeof(struct ubifs_pnode));
- p->cnext = NULL;
- __set_bit(DIRTY_CNODE, &p->flags);
- __clear_bit(COW_CNODE, &p->flags);
- replace_cats(c, pnode, p);
-
- ubifs_assert(!test_bit(OBSOLETE_CNODE, &pnode->flags));
- __set_bit(OBSOLETE_CNODE, &pnode->flags);
-
- c->dirty_pn_cnt += 1;
- add_pnode_dirt(c, pnode);
- pnode->parent->nbranch[p->iip].pnode = p;
- return p;
-}
-
-/**
- * ubifs_lpt_lookup_dirty - lookup LEB properties in the LPT.
- * @c: UBIFS file-system description object
- * @lnum: LEB number to lookup
- *
- * This function returns a pointer to the LEB properties on success or a
- * negative error code on failure.
- */
-struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum)
-{
- int err, i, h, iip, shft;
- struct ubifs_nnode *nnode;
- struct ubifs_pnode *pnode;
-
- if (!c->nroot) {
- err = ubifs_read_nnode(c, NULL, 0);
- if (err)
- return ERR_PTR(err);
- }
- nnode = c->nroot;
- nnode = dirty_cow_nnode(c, nnode);
- if (IS_ERR(nnode))
- return ERR_CAST(nnode);
- i = lnum - c->main_first;
- shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
- for (h = 1; h < c->lpt_hght; h++) {
- iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
- shft -= UBIFS_LPT_FANOUT_SHIFT;
- nnode = ubifs_get_nnode(c, nnode, iip);
- if (IS_ERR(nnode))
- return ERR_CAST(nnode);
- nnode = dirty_cow_nnode(c, nnode);
- if (IS_ERR(nnode))
- return ERR_CAST(nnode);
- }
- iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
- pnode = ubifs_get_pnode(c, nnode, iip);
- if (IS_ERR(pnode))
- return ERR_CAST(pnode);
- pnode = dirty_cow_pnode(c, pnode);
- if (IS_ERR(pnode))
- return ERR_CAST(pnode);
- iip = (i & (UBIFS_LPT_FANOUT - 1));
- dbg_lp("LEB %d, free %d, dirty %d, flags %d", lnum,
- pnode->lprops[iip].free, pnode->lprops[iip].dirty,
- pnode->lprops[iip].flags);
- ubifs_assert(test_bit(DIRTY_CNODE, &pnode->flags));
- return &pnode->lprops[iip];
-}
-
-/**
- * lpt_init_rd - initialize the LPT for reading.
- * @c: UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int lpt_init_rd(struct ubifs_info *c)
-{
- int err, i;
-
- c->ltab = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
- if (!c->ltab)
- return -ENOMEM;
-
- i = max_t(int, c->nnode_sz, c->pnode_sz);
- c->lpt_nod_buf = kmalloc(i, GFP_KERNEL);
- if (!c->lpt_nod_buf)
- return -ENOMEM;
-
- for (i = 0; i < LPROPS_HEAP_CNT; i++) {
- c->lpt_heap[i].arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ,
- GFP_KERNEL);
- if (!c->lpt_heap[i].arr)
- return -ENOMEM;
- c->lpt_heap[i].cnt = 0;
- c->lpt_heap[i].max_cnt = LPT_HEAP_SZ;
- }
-
- c->dirty_idx.arr = kmalloc(sizeof(void *) * LPT_HEAP_SZ, GFP_KERNEL);
- if (!c->dirty_idx.arr)
- return -ENOMEM;
- c->dirty_idx.cnt = 0;
- c->dirty_idx.max_cnt = LPT_HEAP_SZ;
-
- err = read_ltab(c);
- if (err)
- return err;
-
- dbg_lp("space_bits %d", c->space_bits);
- dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits);
- dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits);
- dbg_lp("lpt_spc_bits %d", c->lpt_spc_bits);
- dbg_lp("pcnt_bits %d", c->pcnt_bits);
- dbg_lp("lnum_bits %d", c->lnum_bits);
- dbg_lp("pnode_sz %d", c->pnode_sz);
- dbg_lp("nnode_sz %d", c->nnode_sz);
- dbg_lp("ltab_sz %d", c->ltab_sz);
- dbg_lp("lsave_sz %d", c->lsave_sz);
- dbg_lp("lsave_cnt %d", c->lsave_cnt);
- dbg_lp("lpt_hght %d", c->lpt_hght);
- dbg_lp("big_lpt %d", c->big_lpt);
- dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
- dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
- dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
- if (c->big_lpt)
- dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
-
- return 0;
-}
-
-#ifndef __BAREBOX__
-/**
- * lpt_init_wr - initialize the LPT for writing.
- * @c: UBIFS file-system description object
- *
- * 'lpt_init_rd()' must have been called already.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int lpt_init_wr(struct ubifs_info *c)
-{
- int err, i;
-
- c->ltab_cmt = vmalloc(sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
- if (!c->ltab_cmt)
- return -ENOMEM;
-
- c->lpt_buf = vmalloc(c->leb_size);
- if (!c->lpt_buf)
- return -ENOMEM;
-
- if (c->big_lpt) {
- c->lsave = kmalloc(sizeof(int) * c->lsave_cnt, GFP_NOFS);
- if (!c->lsave)
- return -ENOMEM;
- err = read_lsave(c);
- if (err)
- return err;
- }
-
- for (i = 0; i < c->lpt_lebs; i++)
- if (c->ltab[i].free == c->leb_size) {
- err = ubifs_leb_unmap(c, i + c->lpt_first);
- if (err)
- return err;
- }
-
- return 0;
-}
-#endif
-
-/**
- * ubifs_lpt_init - initialize the LPT.
- * @c: UBIFS file-system description object
- * @rd: whether to initialize lpt for reading
- * @wr: whether to initialize lpt for writing
- *
- * For mounting 'rw', @rd and @wr are both true. For mounting 'ro', @rd is true
- * and @wr is false. For mounting from 'ro' to 'rw', @rd is false and @wr is
- * true.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr)
-{
- int err;
-
- if (rd) {
- err = lpt_init_rd(c);
- if (err)
- goto out_err;
- }
-
-#ifndef __BAREBOX__
- if (wr) {
- err = lpt_init_wr(c);
- if (err)
- goto out_err;
- }
-#endif
-
- return 0;
-
-out_err:
-#ifndef __BAREBOX__
- if (wr)
- ubifs_lpt_free(c, 1);
-#endif
- if (rd)
- ubifs_lpt_free(c, 0);
- return err;
-}
-
-/**
- * struct lpt_scan_node - somewhere to put nodes while we scan LPT.
- * @nnode: where to keep a nnode
- * @pnode: where to keep a pnode
- * @cnode: where to keep a cnode
- * @in_tree: is the node in the tree in memory
- * @ptr.nnode: pointer to the nnode (if it is an nnode) which may be here or in
- * the tree
- * @ptr.pnode: ditto for pnode
- * @ptr.cnode: ditto for cnode
- */
-struct lpt_scan_node {
- union {
- struct ubifs_nnode nnode;
- struct ubifs_pnode pnode;
- struct ubifs_cnode cnode;
- };
- int in_tree;
- union {
- struct ubifs_nnode *nnode;
- struct ubifs_pnode *pnode;
- struct ubifs_cnode *cnode;
- } ptr;
-};
-
-/**
- * scan_get_nnode - for the scan, get a nnode from either the tree or flash.
- * @c: the UBIFS file-system description object
- * @path: where to put the nnode
- * @parent: parent of the nnode
- * @iip: index in parent of the nnode
- *
- * This function returns a pointer to the nnode on success or a negative error
- * code on failure.
- */
-static struct ubifs_nnode *scan_get_nnode(struct ubifs_info *c,
- struct lpt_scan_node *path,
- struct ubifs_nnode *parent, int iip)
-{
- struct ubifs_nbranch *branch;
- struct ubifs_nnode *nnode;
- void *buf = c->lpt_nod_buf;
- int err;
-
- branch = &parent->nbranch[iip];
- nnode = branch->nnode;
- if (nnode) {
- path->in_tree = 1;
- path->ptr.nnode = nnode;
- return nnode;
- }
- nnode = &path->nnode;
- path->in_tree = 0;
- path->ptr.nnode = nnode;
- memset(nnode, 0, sizeof(struct ubifs_nnode));
- if (branch->lnum == 0) {
- /*
- * This nnode was not written which just means that the LEB
- * properties in the subtree below it describe empty LEBs. We
- * make the nnode as though we had read it, which in fact means
- * doing almost nothing.
- */
- if (c->big_lpt)
- nnode->num = calc_nnode_num_from_parent(c, parent, iip);
- } else {
- err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
- c->nnode_sz, 1);
- if (err)
- return ERR_PTR(err);
- err = ubifs_unpack_nnode(c, buf, nnode);
- if (err)
- return ERR_PTR(err);
- }
- err = validate_nnode(c, nnode, parent, iip);
- if (err)
- return ERR_PTR(err);
- if (!c->big_lpt)
- nnode->num = calc_nnode_num_from_parent(c, parent, iip);
- nnode->level = parent->level - 1;
- nnode->parent = parent;
- nnode->iip = iip;
- return nnode;
-}
-
-/**
- * scan_get_pnode - for the scan, get a pnode from either the tree or flash.
- * @c: the UBIFS file-system description object
- * @path: where to put the pnode
- * @parent: parent of the pnode
- * @iip: index in parent of the pnode
- *
- * This function returns a pointer to the pnode on success or a negative error
- * code on failure.
- */
-static struct ubifs_pnode *scan_get_pnode(struct ubifs_info *c,
- struct lpt_scan_node *path,
- struct ubifs_nnode *parent, int iip)
-{
- struct ubifs_nbranch *branch;
- struct ubifs_pnode *pnode;
- void *buf = c->lpt_nod_buf;
- int err;
-
- branch = &parent->nbranch[iip];
- pnode = branch->pnode;
- if (pnode) {
- path->in_tree = 1;
- path->ptr.pnode = pnode;
- return pnode;
- }
- pnode = &path->pnode;
- path->in_tree = 0;
- path->ptr.pnode = pnode;
- memset(pnode, 0, sizeof(struct ubifs_pnode));
- if (branch->lnum == 0) {
- /*
- * This pnode was not written which just means that the LEB
- * properties in it describe empty LEBs. We make the pnode as
- * though we had read it.
- */
- int i;
-
- if (c->big_lpt)
- pnode->num = calc_pnode_num_from_parent(c, parent, iip);
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- struct ubifs_lprops * const lprops = &pnode->lprops[i];
-
- lprops->free = c->leb_size;
- lprops->flags = ubifs_categorize_lprops(c, lprops);
- }
- } else {
- ubifs_assert(branch->lnum >= c->lpt_first &&
- branch->lnum <= c->lpt_last);
- ubifs_assert(branch->offs >= 0 && branch->offs < c->leb_size);
- err = ubifs_leb_read(c, branch->lnum, buf, branch->offs,
- c->pnode_sz, 1);
- if (err)
- return ERR_PTR(err);
- err = unpack_pnode(c, buf, pnode);
- if (err)
- return ERR_PTR(err);
- }
- err = validate_pnode(c, pnode, parent, iip);
- if (err)
- return ERR_PTR(err);
- if (!c->big_lpt)
- pnode->num = calc_pnode_num_from_parent(c, parent, iip);
- pnode->parent = parent;
- pnode->iip = iip;
- set_pnode_lnum(c, pnode);
- return pnode;
-}
-
-/**
- * ubifs_lpt_scan_nolock - scan the LPT.
- * @c: the UBIFS file-system description object
- * @start_lnum: LEB number from which to start scanning
- * @end_lnum: LEB number at which to stop scanning
- * @scan_cb: callback function called for each lprops
- * @data: data to be passed to the callback function
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_lpt_scan_nolock(struct ubifs_info *c, int start_lnum, int end_lnum,
- ubifs_lpt_scan_callback scan_cb, void *data)
-{
- int err = 0, i, h, iip, shft;
- struct ubifs_nnode *nnode;
- struct ubifs_pnode *pnode;
- struct lpt_scan_node *path;
-
- if (start_lnum == -1) {
- start_lnum = end_lnum + 1;
- if (start_lnum >= c->leb_cnt)
- start_lnum = c->main_first;
- }
-
- ubifs_assert(start_lnum >= c->main_first && start_lnum < c->leb_cnt);
- ubifs_assert(end_lnum >= c->main_first && end_lnum < c->leb_cnt);
-
- if (!c->nroot) {
- err = ubifs_read_nnode(c, NULL, 0);
- if (err)
- return err;
- }
-
- path = kmalloc(sizeof(struct lpt_scan_node) * (c->lpt_hght + 1),
- GFP_NOFS);
- if (!path)
- return -ENOMEM;
-
- path[0].ptr.nnode = c->nroot;
- path[0].in_tree = 1;
-again:
- /* Descend to the pnode containing start_lnum */
- nnode = c->nroot;
- i = start_lnum - c->main_first;
- shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
- for (h = 1; h < c->lpt_hght; h++) {
- iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
- shft -= UBIFS_LPT_FANOUT_SHIFT;
- nnode = scan_get_nnode(c, path + h, nnode, iip);
- if (IS_ERR(nnode)) {
- err = PTR_ERR(nnode);
- goto out;
- }
- }
- iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
- pnode = scan_get_pnode(c, path + h, nnode, iip);
- if (IS_ERR(pnode)) {
- err = PTR_ERR(pnode);
- goto out;
- }
- iip = (i & (UBIFS_LPT_FANOUT - 1));
-
- /* Loop for each lprops */
- while (1) {
- struct ubifs_lprops *lprops = &pnode->lprops[iip];
- int ret, lnum = lprops->lnum;
-
- ret = scan_cb(c, lprops, path[h].in_tree, data);
- if (ret < 0) {
- err = ret;
- goto out;
- }
- if (ret & LPT_SCAN_ADD) {
- /* Add all the nodes in path to the tree in memory */
- for (h = 1; h < c->lpt_hght; h++) {
- const size_t sz = sizeof(struct ubifs_nnode);
- struct ubifs_nnode *parent;
-
- if (path[h].in_tree)
- continue;
- nnode = kmemdup(&path[h].nnode, sz, GFP_NOFS);
- if (!nnode) {
- err = -ENOMEM;
- goto out;
- }
- parent = nnode->parent;
- parent->nbranch[nnode->iip].nnode = nnode;
- path[h].ptr.nnode = nnode;
- path[h].in_tree = 1;
- path[h + 1].cnode.parent = nnode;
- }
- if (path[h].in_tree)
- ubifs_ensure_cat(c, lprops);
- else {
- const size_t sz = sizeof(struct ubifs_pnode);
- struct ubifs_nnode *parent;
-
- pnode = kmemdup(&path[h].pnode, sz, GFP_NOFS);
- if (!pnode) {
- err = -ENOMEM;
- goto out;
- }
- parent = pnode->parent;
- parent->nbranch[pnode->iip].pnode = pnode;
- path[h].ptr.pnode = pnode;
- path[h].in_tree = 1;
- update_cats(c, pnode);
- c->pnodes_have += 1;
- }
- err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)
- c->nroot, 0, 0);
- if (err)
- goto out;
- err = dbg_check_cats(c);
- if (err)
- goto out;
- }
- if (ret & LPT_SCAN_STOP) {
- err = 0;
- break;
- }
- /* Get the next lprops */
- if (lnum == end_lnum) {
- /*
- * We got to the end without finding what we were
- * looking for
- */
- err = -ENOSPC;
- goto out;
- }
- if (lnum + 1 >= c->leb_cnt) {
- /* Wrap-around to the beginning */
- start_lnum = c->main_first;
- goto again;
- }
- if (iip + 1 < UBIFS_LPT_FANOUT) {
- /* Next lprops is in the same pnode */
- iip += 1;
- continue;
- }
- /* We need to get the next pnode. Go up until we can go right */
- iip = pnode->iip;
- while (1) {
- h -= 1;
- ubifs_assert(h >= 0);
- nnode = path[h].ptr.nnode;
- if (iip + 1 < UBIFS_LPT_FANOUT)
- break;
- iip = nnode->iip;
- }
- /* Go right */
- iip += 1;
- /* Descend to the pnode */
- h += 1;
- for (; h < c->lpt_hght; h++) {
- nnode = scan_get_nnode(c, path + h, nnode, iip);
- if (IS_ERR(nnode)) {
- err = PTR_ERR(nnode);
- goto out;
- }
- iip = 0;
- }
- pnode = scan_get_pnode(c, path + h, nnode, iip);
- if (IS_ERR(pnode)) {
- err = PTR_ERR(pnode);
- goto out;
- }
- iip = 0;
- }
-out:
- kfree(path);
- return err;
-}
-
-/**
- * dbg_chk_pnode - check a pnode.
- * @c: the UBIFS file-system description object
- * @pnode: pnode to check
- * @col: pnode column
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int dbg_chk_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
- int col)
-{
- int i;
-
- if (pnode->num != col) {
- ubifs_err(c, "pnode num %d expected %d parent num %d iip %d",
- pnode->num, col, pnode->parent->num, pnode->iip);
- return -EINVAL;
- }
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- struct ubifs_lprops *lp, *lprops = &pnode->lprops[i];
- int lnum = (pnode->num << UBIFS_LPT_FANOUT_SHIFT) + i +
- c->main_first;
- int found, cat = lprops->flags & LPROPS_CAT_MASK;
- struct ubifs_lpt_heap *heap;
- struct list_head *list = NULL;
-
- if (lnum >= c->leb_cnt)
- continue;
- if (lprops->lnum != lnum) {
- ubifs_err(c, "bad LEB number %d expected %d",
- lprops->lnum, lnum);
- return -EINVAL;
- }
- if (lprops->flags & LPROPS_TAKEN) {
- if (cat != LPROPS_UNCAT) {
- ubifs_err(c, "LEB %d taken but not uncat %d",
- lprops->lnum, cat);
- return -EINVAL;
- }
- continue;
- }
- if (lprops->flags & LPROPS_INDEX) {
- switch (cat) {
- case LPROPS_UNCAT:
- case LPROPS_DIRTY_IDX:
- case LPROPS_FRDI_IDX:
- break;
- default:
- ubifs_err(c, "LEB %d index but cat %d",
- lprops->lnum, cat);
- return -EINVAL;
- }
- } else {
- switch (cat) {
- case LPROPS_UNCAT:
- case LPROPS_DIRTY:
- case LPROPS_FREE:
- case LPROPS_EMPTY:
- case LPROPS_FREEABLE:
- break;
- default:
- ubifs_err(c, "LEB %d not index but cat %d",
- lprops->lnum, cat);
- return -EINVAL;
- }
- }
- switch (cat) {
- case LPROPS_UNCAT:
- list = &c->uncat_list;
- break;
- case LPROPS_EMPTY:
- list = &c->empty_list;
- break;
- case LPROPS_FREEABLE:
- list = &c->freeable_list;
- break;
- case LPROPS_FRDI_IDX:
- list = &c->frdi_idx_list;
- break;
- }
- found = 0;
- switch (cat) {
- case LPROPS_DIRTY:
- case LPROPS_DIRTY_IDX:
- case LPROPS_FREE:
- heap = &c->lpt_heap[cat - 1];
- if (lprops->hpos < heap->cnt &&
- heap->arr[lprops->hpos] == lprops)
- found = 1;
- break;
- case LPROPS_UNCAT:
- case LPROPS_EMPTY:
- case LPROPS_FREEABLE:
- case LPROPS_FRDI_IDX:
- list_for_each_entry(lp, list, list)
- if (lprops == lp) {
- found = 1;
- break;
- }
- break;
- }
- if (!found) {
- ubifs_err(c, "LEB %d cat %d not found in cat heap/list",
- lprops->lnum, cat);
- return -EINVAL;
- }
- switch (cat) {
- case LPROPS_EMPTY:
- if (lprops->free != c->leb_size) {
- ubifs_err(c, "LEB %d cat %d free %d dirty %d",
- lprops->lnum, cat, lprops->free,
- lprops->dirty);
- return -EINVAL;
- }
- break;
- case LPROPS_FREEABLE:
- case LPROPS_FRDI_IDX:
- if (lprops->free + lprops->dirty != c->leb_size) {
- ubifs_err(c, "LEB %d cat %d free %d dirty %d",
- lprops->lnum, cat, lprops->free,
- lprops->dirty);
- return -EINVAL;
- }
- break;
- }
- }
- return 0;
-}
-
-/**
- * dbg_check_lpt_nodes - check nnodes and pnodes.
- * @c: the UBIFS file-system description object
- * @cnode: next cnode (nnode or pnode) to check
- * @row: row of cnode (root is zero)
- * @col: column of cnode (leftmost is zero)
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int dbg_check_lpt_nodes(struct ubifs_info *c, struct ubifs_cnode *cnode,
- int row, int col)
-{
- struct ubifs_nnode *nnode, *nn;
- struct ubifs_cnode *cn;
- int num, iip = 0, err;
-
- if (!dbg_is_chk_lprops(c))
- return 0;
-
- while (cnode) {
- ubifs_assert(row >= 0);
- nnode = cnode->parent;
- if (cnode->level) {
- /* cnode is a nnode */
- num = calc_nnode_num(row, col);
- if (cnode->num != num) {
- ubifs_err(c, "nnode num %d expected %d parent num %d iip %d",
- cnode->num, num,
- (nnode ? nnode->num : 0), cnode->iip);
- return -EINVAL;
- }
- nn = (struct ubifs_nnode *)cnode;
- while (iip < UBIFS_LPT_FANOUT) {
- cn = nn->nbranch[iip].cnode;
- if (cn) {
- /* Go down */
- row += 1;
- col <<= UBIFS_LPT_FANOUT_SHIFT;
- col += iip;
- iip = 0;
- cnode = cn;
- break;
- }
- /* Go right */
- iip += 1;
- }
- if (iip < UBIFS_LPT_FANOUT)
- continue;
- } else {
- struct ubifs_pnode *pnode;
-
- /* cnode is a pnode */
- pnode = (struct ubifs_pnode *)cnode;
- err = dbg_chk_pnode(c, pnode, col);
- if (err)
- return err;
- }
- /* Go up and to the right */
- row -= 1;
- col >>= UBIFS_LPT_FANOUT_SHIFT;
- iip = cnode->iip + 1;
- cnode = (struct ubifs_cnode *)nnode;
- }
- return 0;
-}
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index 55112b38b5..7e7d645a51 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -14,2028 +14,6 @@
* subsystem.
*/
-#ifndef __BAREBOX__
-#include <linux/crc16.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#else
#include <linux/err.h>
#include "crc16.h"
-#endif
#include "ubifs.h"
-
-#ifndef __BAREBOX__
-static int dbg_populate_lsave(struct ubifs_info *c);
-#endif
-
-/**
- * first_dirty_cnode - find first dirty cnode.
- * @c: UBIFS file-system description object
- * @nnode: nnode at which to start
- *
- * This function returns the first dirty cnode or %NULL if there is not one.
- */
-static struct ubifs_cnode *first_dirty_cnode(struct ubifs_nnode *nnode)
-{
- ubifs_assert(nnode);
- while (1) {
- int i, cont = 0;
-
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- struct ubifs_cnode *cnode;
-
- cnode = nnode->nbranch[i].cnode;
- if (cnode &&
- test_bit(DIRTY_CNODE, &cnode->flags)) {
- if (cnode->level == 0)
- return cnode;
- nnode = (struct ubifs_nnode *)cnode;
- cont = 1;
- break;
- }
- }
- if (!cont)
- return (struct ubifs_cnode *)nnode;
- }
-}
-
-/**
- * next_dirty_cnode - find next dirty cnode.
- * @cnode: cnode from which to begin searching
- *
- * This function returns the next dirty cnode or %NULL if there is not one.
- */
-static struct ubifs_cnode *next_dirty_cnode(struct ubifs_cnode *cnode)
-{
- struct ubifs_nnode *nnode;
- int i;
-
- ubifs_assert(cnode);
- nnode = cnode->parent;
- if (!nnode)
- return NULL;
- for (i = cnode->iip + 1; i < UBIFS_LPT_FANOUT; i++) {
- cnode = nnode->nbranch[i].cnode;
- if (cnode && test_bit(DIRTY_CNODE, &cnode->flags)) {
- if (cnode->level == 0)
- return cnode; /* cnode is a pnode */
- /* cnode is a nnode */
- return first_dirty_cnode((struct ubifs_nnode *)cnode);
- }
- }
- return (struct ubifs_cnode *)nnode;
-}
-
-/**
- * get_cnodes_to_commit - create list of dirty cnodes to commit.
- * @c: UBIFS file-system description object
- *
- * This function returns the number of cnodes to commit.
- */
-static int get_cnodes_to_commit(struct ubifs_info *c)
-{
- struct ubifs_cnode *cnode, *cnext;
- int cnt = 0;
-
- if (!c->nroot)
- return 0;
-
- if (!test_bit(DIRTY_CNODE, &c->nroot->flags))
- return 0;
-
- c->lpt_cnext = first_dirty_cnode(c->nroot);
- cnode = c->lpt_cnext;
- if (!cnode)
- return 0;
- cnt += 1;
- while (1) {
- ubifs_assert(!test_bit(COW_CNODE, &cnode->flags));
- __set_bit(COW_CNODE, &cnode->flags);
- cnext = next_dirty_cnode(cnode);
- if (!cnext) {
- cnode->cnext = c->lpt_cnext;
- break;
- }
- cnode->cnext = cnext;
- cnode = cnext;
- cnt += 1;
- }
- dbg_cmt("committing %d cnodes", cnt);
- dbg_lp("committing %d cnodes", cnt);
- ubifs_assert(cnt == c->dirty_nn_cnt + c->dirty_pn_cnt);
- return cnt;
-}
-
-/**
- * upd_ltab - update LPT LEB properties.
- * @c: UBIFS file-system description object
- * @lnum: LEB number
- * @free: amount of free space
- * @dirty: amount of dirty space to add
- */
-static void upd_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
-{
- dbg_lp("LEB %d free %d dirty %d to %d +%d",
- lnum, c->ltab[lnum - c->lpt_first].free,
- c->ltab[lnum - c->lpt_first].dirty, free, dirty);
- ubifs_assert(lnum >= c->lpt_first && lnum <= c->lpt_last);
- c->ltab[lnum - c->lpt_first].free = free;
- c->ltab[lnum - c->lpt_first].dirty += dirty;
-}
-
-/**
- * alloc_lpt_leb - allocate an LPT LEB that is empty.
- * @c: UBIFS file-system description object
- * @lnum: LEB number is passed and returned here
- *
- * This function finds the next empty LEB in the ltab starting from @lnum. If a
- * an empty LEB is found it is returned in @lnum and the function returns %0.
- * Otherwise the function returns -ENOSPC. Note however, that LPT is designed
- * never to run out of space.
- */
-static int alloc_lpt_leb(struct ubifs_info *c, int *lnum)
-{
- int i, n;
-
- n = *lnum - c->lpt_first + 1;
- for (i = n; i < c->lpt_lebs; i++) {
- if (c->ltab[i].tgc || c->ltab[i].cmt)
- continue;
- if (c->ltab[i].free == c->leb_size) {
- c->ltab[i].cmt = 1;
- *lnum = i + c->lpt_first;
- return 0;
- }
- }
-
- for (i = 0; i < n; i++) {
- if (c->ltab[i].tgc || c->ltab[i].cmt)
- continue;
- if (c->ltab[i].free == c->leb_size) {
- c->ltab[i].cmt = 1;
- *lnum = i + c->lpt_first;
- return 0;
- }
- }
- return -ENOSPC;
-}
-
-/**
- * layout_cnodes - layout cnodes for commit.
- * @c: UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int layout_cnodes(struct ubifs_info *c)
-{
- int lnum, offs, len, alen, done_lsave, done_ltab, err;
- struct ubifs_cnode *cnode;
-
- err = dbg_chk_lpt_sz(c, 0, 0);
- if (err)
- return err;
- cnode = c->lpt_cnext;
- if (!cnode)
- return 0;
- lnum = c->nhead_lnum;
- offs = c->nhead_offs;
- /* Try to place lsave and ltab nicely */
- done_lsave = !c->big_lpt;
- done_ltab = 0;
- if (!done_lsave && offs + c->lsave_sz <= c->leb_size) {
- done_lsave = 1;
- c->lsave_lnum = lnum;
- c->lsave_offs = offs;
- offs += c->lsave_sz;
- dbg_chk_lpt_sz(c, 1, c->lsave_sz);
- }
-
- if (offs + c->ltab_sz <= c->leb_size) {
- done_ltab = 1;
- c->ltab_lnum = lnum;
- c->ltab_offs = offs;
- offs += c->ltab_sz;
- dbg_chk_lpt_sz(c, 1, c->ltab_sz);
- }
-
- do {
- if (cnode->level) {
- len = c->nnode_sz;
- c->dirty_nn_cnt -= 1;
- } else {
- len = c->pnode_sz;
- c->dirty_pn_cnt -= 1;
- }
- while (offs + len > c->leb_size) {
- alen = ALIGN(offs, c->min_io_size);
- upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
- dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
- err = alloc_lpt_leb(c, &lnum);
- if (err)
- goto no_space;
- offs = 0;
- ubifs_assert(lnum >= c->lpt_first &&
- lnum <= c->lpt_last);
- /* Try to place lsave and ltab nicely */
- if (!done_lsave) {
- done_lsave = 1;
- c->lsave_lnum = lnum;
- c->lsave_offs = offs;
- offs += c->lsave_sz;
- dbg_chk_lpt_sz(c, 1, c->lsave_sz);
- continue;
- }
- if (!done_ltab) {
- done_ltab = 1;
- c->ltab_lnum = lnum;
- c->ltab_offs = offs;
- offs += c->ltab_sz;
- dbg_chk_lpt_sz(c, 1, c->ltab_sz);
- continue;
- }
- break;
- }
- if (cnode->parent) {
- cnode->parent->nbranch[cnode->iip].lnum = lnum;
- cnode->parent->nbranch[cnode->iip].offs = offs;
- } else {
- c->lpt_lnum = lnum;
- c->lpt_offs = offs;
- }
- offs += len;
- dbg_chk_lpt_sz(c, 1, len);
- cnode = cnode->cnext;
- } while (cnode && cnode != c->lpt_cnext);
-
- /* Make sure to place LPT's save table */
- if (!done_lsave) {
- if (offs + c->lsave_sz > c->leb_size) {
- alen = ALIGN(offs, c->min_io_size);
- upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
- dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
- err = alloc_lpt_leb(c, &lnum);
- if (err)
- goto no_space;
- offs = 0;
- ubifs_assert(lnum >= c->lpt_first &&
- lnum <= c->lpt_last);
- }
- done_lsave = 1;
- c->lsave_lnum = lnum;
- c->lsave_offs = offs;
- offs += c->lsave_sz;
- dbg_chk_lpt_sz(c, 1, c->lsave_sz);
- }
-
- /* Make sure to place LPT's own lprops table */
- if (!done_ltab) {
- if (offs + c->ltab_sz > c->leb_size) {
- alen = ALIGN(offs, c->min_io_size);
- upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
- dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
- err = alloc_lpt_leb(c, &lnum);
- if (err)
- goto no_space;
- offs = 0;
- ubifs_assert(lnum >= c->lpt_first &&
- lnum <= c->lpt_last);
- }
- c->ltab_lnum = lnum;
- c->ltab_offs = offs;
- offs += c->ltab_sz;
- dbg_chk_lpt_sz(c, 1, c->ltab_sz);
- }
-
- alen = ALIGN(offs, c->min_io_size);
- upd_ltab(c, lnum, c->leb_size - alen, alen - offs);
- dbg_chk_lpt_sz(c, 4, alen - offs);
- err = dbg_chk_lpt_sz(c, 3, alen);
- if (err)
- return err;
- return 0;
-
-no_space:
- ubifs_err(c, "LPT out of space at LEB %d:%d needing %d, done_ltab %d, done_lsave %d",
- lnum, offs, len, done_ltab, done_lsave);
- ubifs_dump_lpt_info(c);
- ubifs_dump_lpt_lebs(c);
- dump_stack();
- return err;
-}
-
-#ifndef __BAREBOX__
-/**
- * realloc_lpt_leb - allocate an LPT LEB that is empty.
- * @c: UBIFS file-system description object
- * @lnum: LEB number is passed and returned here
- *
- * This function duplicates exactly the results of the function alloc_lpt_leb.
- * It is used during end commit to reallocate the same LEB numbers that were
- * allocated by alloc_lpt_leb during start commit.
- *
- * This function finds the next LEB that was allocated by the alloc_lpt_leb
- * function starting from @lnum. If a LEB is found it is returned in @lnum and
- * the function returns %0. Otherwise the function returns -ENOSPC.
- * Note however, that LPT is designed never to run out of space.
- */
-static int realloc_lpt_leb(struct ubifs_info *c, int *lnum)
-{
- int i, n;
-
- n = *lnum - c->lpt_first + 1;
- for (i = n; i < c->lpt_lebs; i++)
- if (c->ltab[i].cmt) {
- c->ltab[i].cmt = 0;
- *lnum = i + c->lpt_first;
- return 0;
- }
-
- for (i = 0; i < n; i++)
- if (c->ltab[i].cmt) {
- c->ltab[i].cmt = 0;
- *lnum = i + c->lpt_first;
- return 0;
- }
- return -ENOSPC;
-}
-
-/**
- * write_cnodes - write cnodes for commit.
- * @c: UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int write_cnodes(struct ubifs_info *c)
-{
- int lnum, offs, len, from, err, wlen, alen, done_ltab, done_lsave;
- struct ubifs_cnode *cnode;
- void *buf = c->lpt_buf;
-
- cnode = c->lpt_cnext;
- if (!cnode)
- return 0;
- lnum = c->nhead_lnum;
- offs = c->nhead_offs;
- from = offs;
- /* Ensure empty LEB is unmapped */
- if (offs == 0) {
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- return err;
- }
- /* Try to place lsave and ltab nicely */
- done_lsave = !c->big_lpt;
- done_ltab = 0;
- if (!done_lsave && offs + c->lsave_sz <= c->leb_size) {
- done_lsave = 1;
- ubifs_pack_lsave(c, buf + offs, c->lsave);
- offs += c->lsave_sz;
- dbg_chk_lpt_sz(c, 1, c->lsave_sz);
- }
-
- if (offs + c->ltab_sz <= c->leb_size) {
- done_ltab = 1;
- ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
- offs += c->ltab_sz;
- dbg_chk_lpt_sz(c, 1, c->ltab_sz);
- }
-
- /* Loop for each cnode */
- do {
- if (cnode->level)
- len = c->nnode_sz;
- else
- len = c->pnode_sz;
- while (offs + len > c->leb_size) {
- wlen = offs - from;
- if (wlen) {
- alen = ALIGN(wlen, c->min_io_size);
- memset(buf + offs, 0xff, alen - wlen);
- err = ubifs_leb_write(c, lnum, buf + from, from,
- alen);
- if (err)
- return err;
- }
- dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
- err = realloc_lpt_leb(c, &lnum);
- if (err)
- goto no_space;
- offs = from = 0;
- ubifs_assert(lnum >= c->lpt_first &&
- lnum <= c->lpt_last);
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- return err;
- /* Try to place lsave and ltab nicely */
- if (!done_lsave) {
- done_lsave = 1;
- ubifs_pack_lsave(c, buf + offs, c->lsave);
- offs += c->lsave_sz;
- dbg_chk_lpt_sz(c, 1, c->lsave_sz);
- continue;
- }
- if (!done_ltab) {
- done_ltab = 1;
- ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
- offs += c->ltab_sz;
- dbg_chk_lpt_sz(c, 1, c->ltab_sz);
- continue;
- }
- break;
- }
- if (cnode->level)
- ubifs_pack_nnode(c, buf + offs,
- (struct ubifs_nnode *)cnode);
- else
- ubifs_pack_pnode(c, buf + offs,
- (struct ubifs_pnode *)cnode);
- /*
- * The reason for the barriers is the same as in case of TNC.
- * See comment in 'write_index()'. 'dirty_cow_nnode()' and
- * 'dirty_cow_pnode()' are the functions for which this is
- * important.
- */
- clear_bit(DIRTY_CNODE, &cnode->flags);
- smp_mb__before_atomic();
- clear_bit(COW_CNODE, &cnode->flags);
- smp_mb__after_atomic();
- offs += len;
- dbg_chk_lpt_sz(c, 1, len);
- cnode = cnode->cnext;
- } while (cnode && cnode != c->lpt_cnext);
-
- /* Make sure to place LPT's save table */
- if (!done_lsave) {
- if (offs + c->lsave_sz > c->leb_size) {
- wlen = offs - from;
- alen = ALIGN(wlen, c->min_io_size);
- memset(buf + offs, 0xff, alen - wlen);
- err = ubifs_leb_write(c, lnum, buf + from, from, alen);
- if (err)
- return err;
- dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
- err = realloc_lpt_leb(c, &lnum);
- if (err)
- goto no_space;
- offs = from = 0;
- ubifs_assert(lnum >= c->lpt_first &&
- lnum <= c->lpt_last);
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- return err;
- }
- done_lsave = 1;
- ubifs_pack_lsave(c, buf + offs, c->lsave);
- offs += c->lsave_sz;
- dbg_chk_lpt_sz(c, 1, c->lsave_sz);
- }
-
- /* Make sure to place LPT's own lprops table */
- if (!done_ltab) {
- if (offs + c->ltab_sz > c->leb_size) {
- wlen = offs - from;
- alen = ALIGN(wlen, c->min_io_size);
- memset(buf + offs, 0xff, alen - wlen);
- err = ubifs_leb_write(c, lnum, buf + from, from, alen);
- if (err)
- return err;
- dbg_chk_lpt_sz(c, 2, c->leb_size - offs);
- err = realloc_lpt_leb(c, &lnum);
- if (err)
- goto no_space;
- offs = from = 0;
- ubifs_assert(lnum >= c->lpt_first &&
- lnum <= c->lpt_last);
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- return err;
- }
- ubifs_pack_ltab(c, buf + offs, c->ltab_cmt);
- offs += c->ltab_sz;
- dbg_chk_lpt_sz(c, 1, c->ltab_sz);
- }
-
- /* Write remaining data in buffer */
- wlen = offs - from;
- alen = ALIGN(wlen, c->min_io_size);
- memset(buf + offs, 0xff, alen - wlen);
- err = ubifs_leb_write(c, lnum, buf + from, from, alen);
- if (err)
- return err;
-
- dbg_chk_lpt_sz(c, 4, alen - wlen);
- err = dbg_chk_lpt_sz(c, 3, ALIGN(offs, c->min_io_size));
- if (err)
- return err;
-
- c->nhead_lnum = lnum;
- c->nhead_offs = ALIGN(offs, c->min_io_size);
-
- dbg_lp("LPT root is at %d:%d", c->lpt_lnum, c->lpt_offs);
- dbg_lp("LPT head is at %d:%d", c->nhead_lnum, c->nhead_offs);
- dbg_lp("LPT ltab is at %d:%d", c->ltab_lnum, c->ltab_offs);
- if (c->big_lpt)
- dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs);
-
- return 0;
-
-no_space:
- ubifs_err(c, "LPT out of space mismatch at LEB %d:%d needing %d, done_ltab %d, done_lsave %d",
- lnum, offs, len, done_ltab, done_lsave);
- ubifs_dump_lpt_info(c);
- ubifs_dump_lpt_lebs(c);
- dump_stack();
- return err;
-}
-#endif
-
-/**
- * next_pnode_to_dirty - find next pnode to dirty.
- * @c: UBIFS file-system description object
- * @pnode: pnode
- *
- * This function returns the next pnode to dirty or %NULL if there are no more
- * pnodes. Note that pnodes that have never been written (lnum == 0) are
- * skipped.
- */
-static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
- struct ubifs_pnode *pnode)
-{
- struct ubifs_nnode *nnode;
- int iip;
-
- /* Try to go right */
- nnode = pnode->parent;
- for (iip = pnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) {
- if (nnode->nbranch[iip].lnum)
- return ubifs_get_pnode(c, nnode, iip);
- }
-
- /* Go up while can't go right */
- do {
- iip = nnode->iip + 1;
- nnode = nnode->parent;
- if (!nnode)
- return NULL;
- for (; iip < UBIFS_LPT_FANOUT; iip++) {
- if (nnode->nbranch[iip].lnum)
- break;
- }
- } while (iip >= UBIFS_LPT_FANOUT);
-
- /* Go right */
- nnode = ubifs_get_nnode(c, nnode, iip);
- if (IS_ERR(nnode))
- return (void *)nnode;
-
- /* Go down to level 1 */
- while (nnode->level > 1) {
- for (iip = 0; iip < UBIFS_LPT_FANOUT; iip++) {
- if (nnode->nbranch[iip].lnum)
- break;
- }
- if (iip >= UBIFS_LPT_FANOUT) {
- /*
- * Should not happen, but we need to keep going
- * if it does.
- */
- iip = 0;
- }
- nnode = ubifs_get_nnode(c, nnode, iip);
- if (IS_ERR(nnode))
- return (void *)nnode;
- }
-
- for (iip = 0; iip < UBIFS_LPT_FANOUT; iip++)
- if (nnode->nbranch[iip].lnum)
- break;
- if (iip >= UBIFS_LPT_FANOUT)
- /* Should not happen, but we need to keep going if it does */
- iip = 0;
- return ubifs_get_pnode(c, nnode, iip);
-}
-
-/**
- * pnode_lookup - lookup a pnode in the LPT.
- * @c: UBIFS file-system description object
- * @i: pnode number (0 to main_lebs - 1)
- *
- * This function returns a pointer to the pnode on success or a negative
- * error code on failure.
- */
-static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i)
-{
- int err, h, iip, shft;
- struct ubifs_nnode *nnode;
-
- if (!c->nroot) {
- err = ubifs_read_nnode(c, NULL, 0);
- if (err)
- return ERR_PTR(err);
- }
- i <<= UBIFS_LPT_FANOUT_SHIFT;
- nnode = c->nroot;
- shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT;
- for (h = 1; h < c->lpt_hght; h++) {
- iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
- shft -= UBIFS_LPT_FANOUT_SHIFT;
- nnode = ubifs_get_nnode(c, nnode, iip);
- if (IS_ERR(nnode))
- return ERR_CAST(nnode);
- }
- iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1));
- return ubifs_get_pnode(c, nnode, iip);
-}
-
-/**
- * add_pnode_dirt - add dirty space to LPT LEB properties.
- * @c: UBIFS file-system description object
- * @pnode: pnode for which to add dirt
- */
-static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode)
-{
- ubifs_add_lpt_dirt(c, pnode->parent->nbranch[pnode->iip].lnum,
- c->pnode_sz);
-}
-
-/**
- * do_make_pnode_dirty - mark a pnode dirty.
- * @c: UBIFS file-system description object
- * @pnode: pnode to mark dirty
- */
-static void do_make_pnode_dirty(struct ubifs_info *c, struct ubifs_pnode *pnode)
-{
- /* Assumes cnext list is empty i.e. not called during commit */
- if (!test_and_set_bit(DIRTY_CNODE, &pnode->flags)) {
- struct ubifs_nnode *nnode;
-
- c->dirty_pn_cnt += 1;
- add_pnode_dirt(c, pnode);
- /* Mark parent and ancestors dirty too */
- nnode = pnode->parent;
- while (nnode) {
- if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
- c->dirty_nn_cnt += 1;
- ubifs_add_nnode_dirt(c, nnode);
- nnode = nnode->parent;
- } else
- break;
- }
- }
-}
-
-/**
- * make_tree_dirty - mark the entire LEB properties tree dirty.
- * @c: UBIFS file-system description object
- *
- * This function is used by the "small" LPT model to cause the entire LEB
- * properties tree to be written. The "small" LPT model does not use LPT
- * garbage collection because it is more efficient to write the entire tree
- * (because it is small).
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int make_tree_dirty(struct ubifs_info *c)
-{
- struct ubifs_pnode *pnode;
-
- pnode = pnode_lookup(c, 0);
- if (IS_ERR(pnode))
- return PTR_ERR(pnode);
-
- while (pnode) {
- do_make_pnode_dirty(c, pnode);
- pnode = next_pnode_to_dirty(c, pnode);
- if (IS_ERR(pnode))
- return PTR_ERR(pnode);
- }
- return 0;
-}
-
-/**
- * need_write_all - determine if the LPT area is running out of free space.
- * @c: UBIFS file-system description object
- *
- * This function returns %1 if the LPT area is running out of free space and %0
- * if it is not.
- */
-static int need_write_all(struct ubifs_info *c)
-{
- long long free = 0;
- int i;
-
- for (i = 0; i < c->lpt_lebs; i++) {
- if (i + c->lpt_first == c->nhead_lnum)
- free += c->leb_size - c->nhead_offs;
- else if (c->ltab[i].free == c->leb_size)
- free += c->leb_size;
- else if (c->ltab[i].free + c->ltab[i].dirty == c->leb_size)
- free += c->leb_size;
- }
- /* Less than twice the size left */
- if (free <= c->lpt_sz * 2)
- return 1;
- return 0;
-}
-
-/**
- * lpt_tgc_start - start trivial garbage collection of LPT LEBs.
- * @c: UBIFS file-system description object
- *
- * LPT trivial garbage collection is where a LPT LEB contains only dirty and
- * free space and so may be reused as soon as the next commit is completed.
- * This function is called during start commit to mark LPT LEBs for trivial GC.
- */
-static void lpt_tgc_start(struct ubifs_info *c)
-{
- int i;
-
- for (i = 0; i < c->lpt_lebs; i++) {
- if (i + c->lpt_first == c->nhead_lnum)
- continue;
- if (c->ltab[i].dirty > 0 &&
- c->ltab[i].free + c->ltab[i].dirty == c->leb_size) {
- c->ltab[i].tgc = 1;
- c->ltab[i].free = c->leb_size;
- c->ltab[i].dirty = 0;
- dbg_lp("LEB %d", i + c->lpt_first);
- }
- }
-}
-
-/**
- * lpt_tgc_end - end trivial garbage collection of LPT LEBs.
- * @c: UBIFS file-system description object
- *
- * LPT trivial garbage collection is where a LPT LEB contains only dirty and
- * free space and so may be reused as soon as the next commit is completed.
- * This function is called after the commit is completed (master node has been
- * written) and un-maps LPT LEBs that were marked for trivial GC.
- */
-static int lpt_tgc_end(struct ubifs_info *c)
-{
- int i, err;
-
- for (i = 0; i < c->lpt_lebs; i++)
- if (c->ltab[i].tgc) {
- err = ubifs_leb_unmap(c, i + c->lpt_first);
- if (err)
- return err;
- c->ltab[i].tgc = 0;
- dbg_lp("LEB %d", i + c->lpt_first);
- }
- return 0;
-}
-
-/**
- * populate_lsave - fill the lsave array with important LEB numbers.
- * @c: the UBIFS file-system description object
- *
- * This function is only called for the "big" model. It records a small number
- * of LEB numbers of important LEBs. Important LEBs are ones that are (from
- * most important to least important): empty, freeable, freeable index, dirty
- * index, dirty or free. Upon mount, we read this list of LEB numbers and bring
- * their pnodes into memory. That will stop us from having to scan the LPT
- * straight away. For the "small" model we assume that scanning the LPT is no
- * big deal.
- */
-static void populate_lsave(struct ubifs_info *c)
-{
- struct ubifs_lprops *lprops;
- struct ubifs_lpt_heap *heap;
- int i, cnt = 0;
-
- ubifs_assert(c->big_lpt);
- if (!(c->lpt_drty_flgs & LSAVE_DIRTY)) {
- c->lpt_drty_flgs |= LSAVE_DIRTY;
- ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);
- }
-
-#ifndef __BAREBOX__
- if (dbg_populate_lsave(c))
- return;
-#endif
-
- list_for_each_entry(lprops, &c->empty_list, list) {
- c->lsave[cnt++] = lprops->lnum;
- if (cnt >= c->lsave_cnt)
- return;
- }
- list_for_each_entry(lprops, &c->freeable_list, list) {
- c->lsave[cnt++] = lprops->lnum;
- if (cnt >= c->lsave_cnt)
- return;
- }
- list_for_each_entry(lprops, &c->frdi_idx_list, list) {
- c->lsave[cnt++] = lprops->lnum;
- if (cnt >= c->lsave_cnt)
- return;
- }
- heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
- for (i = 0; i < heap->cnt; i++) {
- c->lsave[cnt++] = heap->arr[i]->lnum;
- if (cnt >= c->lsave_cnt)
- return;
- }
- heap = &c->lpt_heap[LPROPS_DIRTY - 1];
- for (i = 0; i < heap->cnt; i++) {
- c->lsave[cnt++] = heap->arr[i]->lnum;
- if (cnt >= c->lsave_cnt)
- return;
- }
- heap = &c->lpt_heap[LPROPS_FREE - 1];
- for (i = 0; i < heap->cnt; i++) {
- c->lsave[cnt++] = heap->arr[i]->lnum;
- if (cnt >= c->lsave_cnt)
- return;
- }
- /* Fill it up completely */
- while (cnt < c->lsave_cnt)
- c->lsave[cnt++] = c->main_first;
-}
-
-/**
- * nnode_lookup - lookup a nnode in the LPT.
- * @c: UBIFS file-system description object
- * @i: nnode number
- *
- * This function returns a pointer to the nnode on success or a negative
- * error code on failure.
- */
-static struct ubifs_nnode *nnode_lookup(struct ubifs_info *c, int i)
-{
- int err, iip;
- struct ubifs_nnode *nnode;
-
- if (!c->nroot) {
- err = ubifs_read_nnode(c, NULL, 0);
- if (err)
- return ERR_PTR(err);
- }
- nnode = c->nroot;
- while (1) {
- iip = i & (UBIFS_LPT_FANOUT - 1);
- i >>= UBIFS_LPT_FANOUT_SHIFT;
- if (!i)
- break;
- nnode = ubifs_get_nnode(c, nnode, iip);
- if (IS_ERR(nnode))
- return nnode;
- }
- return nnode;
-}
-
-/**
- * make_nnode_dirty - find a nnode and, if found, make it dirty.
- * @c: UBIFS file-system description object
- * @node_num: nnode number of nnode to make dirty
- * @lnum: LEB number where nnode was written
- * @offs: offset where nnode was written
- *
- * This function is used by LPT garbage collection. LPT garbage collection is
- * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection
- * simply involves marking all the nodes in the LEB being garbage-collected as
- * dirty. The dirty nodes are written next commit, after which the LEB is free
- * to be reused.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int make_nnode_dirty(struct ubifs_info *c, int node_num, int lnum,
- int offs)
-{
- struct ubifs_nnode *nnode;
-
- nnode = nnode_lookup(c, node_num);
- if (IS_ERR(nnode))
- return PTR_ERR(nnode);
- if (nnode->parent) {
- struct ubifs_nbranch *branch;
-
- branch = &nnode->parent->nbranch[nnode->iip];
- if (branch->lnum != lnum || branch->offs != offs)
- return 0; /* nnode is obsolete */
- } else if (c->lpt_lnum != lnum || c->lpt_offs != offs)
- return 0; /* nnode is obsolete */
- /* Assumes cnext list is empty i.e. not called during commit */
- if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
- c->dirty_nn_cnt += 1;
- ubifs_add_nnode_dirt(c, nnode);
- /* Mark parent and ancestors dirty too */
- nnode = nnode->parent;
- while (nnode) {
- if (!test_and_set_bit(DIRTY_CNODE, &nnode->flags)) {
- c->dirty_nn_cnt += 1;
- ubifs_add_nnode_dirt(c, nnode);
- nnode = nnode->parent;
- } else
- break;
- }
- }
- return 0;
-}
-
-/**
- * make_pnode_dirty - find a pnode and, if found, make it dirty.
- * @c: UBIFS file-system description object
- * @node_num: pnode number of pnode to make dirty
- * @lnum: LEB number where pnode was written
- * @offs: offset where pnode was written
- *
- * This function is used by LPT garbage collection. LPT garbage collection is
- * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection
- * simply involves marking all the nodes in the LEB being garbage-collected as
- * dirty. The dirty nodes are written next commit, after which the LEB is free
- * to be reused.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int make_pnode_dirty(struct ubifs_info *c, int node_num, int lnum,
- int offs)
-{
- struct ubifs_pnode *pnode;
- struct ubifs_nbranch *branch;
-
- pnode = pnode_lookup(c, node_num);
- if (IS_ERR(pnode))
- return PTR_ERR(pnode);
- branch = &pnode->parent->nbranch[pnode->iip];
- if (branch->lnum != lnum || branch->offs != offs)
- return 0;
- do_make_pnode_dirty(c, pnode);
- return 0;
-}
-
-/**
- * make_ltab_dirty - make ltab node dirty.
- * @c: UBIFS file-system description object
- * @lnum: LEB number where ltab was written
- * @offs: offset where ltab was written
- *
- * This function is used by LPT garbage collection. LPT garbage collection is
- * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection
- * simply involves marking all the nodes in the LEB being garbage-collected as
- * dirty. The dirty nodes are written next commit, after which the LEB is free
- * to be reused.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int make_ltab_dirty(struct ubifs_info *c, int lnum, int offs)
-{
- if (lnum != c->ltab_lnum || offs != c->ltab_offs)
- return 0; /* This ltab node is obsolete */
- if (!(c->lpt_drty_flgs & LTAB_DIRTY)) {
- c->lpt_drty_flgs |= LTAB_DIRTY;
- ubifs_add_lpt_dirt(c, c->ltab_lnum, c->ltab_sz);
- }
- return 0;
-}
-
-/**
- * make_lsave_dirty - make lsave node dirty.
- * @c: UBIFS file-system description object
- * @lnum: LEB number where lsave was written
- * @offs: offset where lsave was written
- *
- * This function is used by LPT garbage collection. LPT garbage collection is
- * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection
- * simply involves marking all the nodes in the LEB being garbage-collected as
- * dirty. The dirty nodes are written next commit, after which the LEB is free
- * to be reused.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int make_lsave_dirty(struct ubifs_info *c, int lnum, int offs)
-{
- if (lnum != c->lsave_lnum || offs != c->lsave_offs)
- return 0; /* This lsave node is obsolete */
- if (!(c->lpt_drty_flgs & LSAVE_DIRTY)) {
- c->lpt_drty_flgs |= LSAVE_DIRTY;
- ubifs_add_lpt_dirt(c, c->lsave_lnum, c->lsave_sz);
- }
- return 0;
-}
-
-/**
- * make_node_dirty - make node dirty.
- * @c: UBIFS file-system description object
- * @node_type: LPT node type
- * @node_num: node number
- * @lnum: LEB number where node was written
- * @offs: offset where node was written
- *
- * This function is used by LPT garbage collection. LPT garbage collection is
- * used only for the "big" LPT model (c->big_lpt == 1). Garbage collection
- * simply involves marking all the nodes in the LEB being garbage-collected as
- * dirty. The dirty nodes are written next commit, after which the LEB is free
- * to be reused.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int make_node_dirty(struct ubifs_info *c, int node_type, int node_num,
- int lnum, int offs)
-{
- switch (node_type) {
- case UBIFS_LPT_NNODE:
- return make_nnode_dirty(c, node_num, lnum, offs);
- case UBIFS_LPT_PNODE:
- return make_pnode_dirty(c, node_num, lnum, offs);
- case UBIFS_LPT_LTAB:
- return make_ltab_dirty(c, lnum, offs);
- case UBIFS_LPT_LSAVE:
- return make_lsave_dirty(c, lnum, offs);
- }
- return -EINVAL;
-}
-
-/**
- * get_lpt_node_len - return the length of a node based on its type.
- * @c: UBIFS file-system description object
- * @node_type: LPT node type
- */
-static int get_lpt_node_len(const struct ubifs_info *c, int node_type)
-{
- switch (node_type) {
- case UBIFS_LPT_NNODE:
- return c->nnode_sz;
- case UBIFS_LPT_PNODE:
- return c->pnode_sz;
- case UBIFS_LPT_LTAB:
- return c->ltab_sz;
- case UBIFS_LPT_LSAVE:
- return c->lsave_sz;
- }
- return 0;
-}
-
-/**
- * get_pad_len - return the length of padding in a buffer.
- * @c: UBIFS file-system description object
- * @buf: buffer
- * @len: length of buffer
- */
-static int get_pad_len(const struct ubifs_info *c, uint8_t *buf, int len)
-{
- int offs, pad_len;
-
- if (c->min_io_size == 1)
- return 0;
- offs = c->leb_size - len;
- pad_len = ALIGN(offs, c->min_io_size) - offs;
- return pad_len;
-}
-
-/**
- * get_lpt_node_type - return type (and node number) of a node in a buffer.
- * @c: UBIFS file-system description object
- * @buf: buffer
- * @node_num: node number is returned here
- */
-static int get_lpt_node_type(const struct ubifs_info *c, uint8_t *buf,
- int *node_num)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int pos = 0, node_type;
-
- node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS);
- *node_num = ubifs_unpack_bits(&addr, &pos, c->pcnt_bits);
- return node_type;
-}
-
-/**
- * is_a_node - determine if a buffer contains a node.
- * @c: UBIFS file-system description object
- * @buf: buffer
- * @len: length of buffer
- *
- * This function returns %1 if the buffer contains a node or %0 if it does not.
- */
-static int is_a_node(const struct ubifs_info *c, uint8_t *buf, int len)
-{
- uint8_t *addr = buf + UBIFS_LPT_CRC_BYTES;
- int pos = 0, node_type, node_len;
- uint16_t crc, calc_crc;
-
- if (len < UBIFS_LPT_CRC_BYTES + (UBIFS_LPT_TYPE_BITS + 7) / 8)
- return 0;
- node_type = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_TYPE_BITS);
- if (node_type == UBIFS_LPT_NOT_A_NODE)
- return 0;
- node_len = get_lpt_node_len(c, node_type);
- if (!node_len || node_len > len)
- return 0;
- pos = 0;
- addr = buf;
- crc = ubifs_unpack_bits(&addr, &pos, UBIFS_LPT_CRC_BITS);
- calc_crc = crc16(-1, buf + UBIFS_LPT_CRC_BYTES,
- node_len - UBIFS_LPT_CRC_BYTES);
- if (crc != calc_crc)
- return 0;
- return 1;
-}
-
-/**
- * lpt_gc_lnum - garbage collect a LPT LEB.
- * @c: UBIFS file-system description object
- * @lnum: LEB number to garbage collect
- *
- * LPT garbage collection is used only for the "big" LPT model
- * (c->big_lpt == 1). Garbage collection simply involves marking all the nodes
- * in the LEB being garbage-collected as dirty. The dirty nodes are written
- * next commit, after which the LEB is free to be reused.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
-{
- int err, len = c->leb_size, node_type, node_num, node_len, offs;
- void *buf = c->lpt_buf;
-
- dbg_lp("LEB %d", lnum);
-
- err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
- if (err)
- return err;
-
- while (1) {
- if (!is_a_node(c, buf, len)) {
- int pad_len;
-
- pad_len = get_pad_len(c, buf, len);
- if (pad_len) {
- buf += pad_len;
- len -= pad_len;
- continue;
- }
- return 0;
- }
- node_type = get_lpt_node_type(c, buf, &node_num);
- node_len = get_lpt_node_len(c, node_type);
- offs = c->leb_size - len;
- ubifs_assert(node_len != 0);
- mutex_lock(&c->lp_mutex);
- err = make_node_dirty(c, node_type, node_num, lnum, offs);
- mutex_unlock(&c->lp_mutex);
- if (err)
- return err;
- buf += node_len;
- len -= node_len;
- }
- return 0;
-}
-
-/**
- * lpt_gc - LPT garbage collection.
- * @c: UBIFS file-system description object
- *
- * Select a LPT LEB for LPT garbage collection and call 'lpt_gc_lnum()'.
- * Returns %0 on success and a negative error code on failure.
- */
-static int lpt_gc(struct ubifs_info *c)
-{
- int i, lnum = -1, dirty = 0;
-
- mutex_lock(&c->lp_mutex);
- for (i = 0; i < c->lpt_lebs; i++) {
- ubifs_assert(!c->ltab[i].tgc);
- if (i + c->lpt_first == c->nhead_lnum ||
- c->ltab[i].free + c->ltab[i].dirty == c->leb_size)
- continue;
- if (c->ltab[i].dirty > dirty) {
- dirty = c->ltab[i].dirty;
- lnum = i + c->lpt_first;
- }
- }
- mutex_unlock(&c->lp_mutex);
- if (lnum == -1)
- return -ENOSPC;
- return lpt_gc_lnum(c, lnum);
-}
-
-/**
- * ubifs_lpt_start_commit - UBIFS commit starts.
- * @c: the UBIFS file-system description object
- *
- * This function has to be called when UBIFS starts the commit operation.
- * This function "freezes" all currently dirty LEB properties and does not
- * change them anymore. Further changes are saved and tracked separately
- * because they are not part of this commit. This function returns zero in case
- * of success and a negative error code in case of failure.
- */
-int ubifs_lpt_start_commit(struct ubifs_info *c)
-{
- int err, cnt;
-
- dbg_lp("");
-
- mutex_lock(&c->lp_mutex);
- err = dbg_chk_lpt_free_spc(c);
- if (err)
- goto out;
- err = dbg_check_ltab(c);
- if (err)
- goto out;
-
- if (c->check_lpt_free) {
- /*
- * We ensure there is enough free space in
- * ubifs_lpt_post_commit() by marking nodes dirty. That
- * information is lost when we unmount, so we also need
- * to check free space once after mounting also.
- */
- c->check_lpt_free = 0;
- while (need_write_all(c)) {
- mutex_unlock(&c->lp_mutex);
- err = lpt_gc(c);
- if (err)
- return err;
- mutex_lock(&c->lp_mutex);
- }
- }
-
- lpt_tgc_start(c);
-
- if (!c->dirty_pn_cnt) {
- dbg_cmt("no cnodes to commit");
- err = 0;
- goto out;
- }
-
- if (!c->big_lpt && need_write_all(c)) {
- /* If needed, write everything */
- err = make_tree_dirty(c);
- if (err)
- goto out;
- lpt_tgc_start(c);
- }
-
- if (c->big_lpt)
- populate_lsave(c);
-
- cnt = get_cnodes_to_commit(c);
- ubifs_assert(cnt != 0);
-
- err = layout_cnodes(c);
- if (err)
- goto out;
-
- /* Copy the LPT's own lprops for end commit to write */
- memcpy(c->ltab_cmt, c->ltab,
- sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs);
- c->lpt_drty_flgs &= ~(LTAB_DIRTY | LSAVE_DIRTY);
-
-out:
- mutex_unlock(&c->lp_mutex);
- return err;
-}
-
-/**
- * free_obsolete_cnodes - free obsolete cnodes for commit end.
- * @c: UBIFS file-system description object
- */
-static void free_obsolete_cnodes(struct ubifs_info *c)
-{
- struct ubifs_cnode *cnode, *cnext;
-
- cnext = c->lpt_cnext;
- if (!cnext)
- return;
- do {
- cnode = cnext;
- cnext = cnode->cnext;
- if (test_bit(OBSOLETE_CNODE, &cnode->flags))
- kfree(cnode);
- else
- cnode->cnext = NULL;
- } while (cnext != c->lpt_cnext);
- c->lpt_cnext = NULL;
-}
-
-#ifndef __BAREBOX__
-/**
- * ubifs_lpt_end_commit - finish the commit operation.
- * @c: the UBIFS file-system description object
- *
- * This function has to be called when the commit operation finishes. It
- * flushes the changes which were "frozen" by 'ubifs_lprops_start_commit()' to
- * the media. Returns zero in case of success and a negative error code in case
- * of failure.
- */
-int ubifs_lpt_end_commit(struct ubifs_info *c)
-{
- int err;
-
- dbg_lp("");
-
- if (!c->lpt_cnext)
- return 0;
-
- err = write_cnodes(c);
- if (err)
- return err;
-
- mutex_lock(&c->lp_mutex);
- free_obsolete_cnodes(c);
- mutex_unlock(&c->lp_mutex);
-
- return 0;
-}
-#endif
-
-/**
- * ubifs_lpt_post_commit - post commit LPT trivial GC and LPT GC.
- * @c: UBIFS file-system description object
- *
- * LPT trivial GC is completed after a commit. Also LPT GC is done after a
- * commit for the "big" LPT model.
- */
-int ubifs_lpt_post_commit(struct ubifs_info *c)
-{
- int err;
-
- mutex_lock(&c->lp_mutex);
- err = lpt_tgc_end(c);
- if (err)
- goto out;
- if (c->big_lpt)
- while (need_write_all(c)) {
- mutex_unlock(&c->lp_mutex);
- err = lpt_gc(c);
- if (err)
- return err;
- mutex_lock(&c->lp_mutex);
- }
-out:
- mutex_unlock(&c->lp_mutex);
- return err;
-}
-
-/**
- * first_nnode - find the first nnode in memory.
- * @c: UBIFS file-system description object
- * @hght: height of tree where nnode found is returned here
- *
- * This function returns a pointer to the nnode found or %NULL if no nnode is
- * found. This function is a helper to 'ubifs_lpt_free()'.
- */
-static struct ubifs_nnode *first_nnode(struct ubifs_info *c, int *hght)
-{
- struct ubifs_nnode *nnode;
- int h, i, found;
-
- nnode = c->nroot;
- *hght = 0;
- if (!nnode)
- return NULL;
- for (h = 1; h < c->lpt_hght; h++) {
- found = 0;
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- if (nnode->nbranch[i].nnode) {
- found = 1;
- nnode = nnode->nbranch[i].nnode;
- *hght = h;
- break;
- }
- }
- if (!found)
- break;
- }
- return nnode;
-}
-
-/**
- * next_nnode - find the next nnode in memory.
- * @c: UBIFS file-system description object
- * @nnode: nnode from which to start.
- * @hght: height of tree where nnode is, is passed and returned here
- *
- * This function returns a pointer to the nnode found or %NULL if no nnode is
- * found. This function is a helper to 'ubifs_lpt_free()'.
- */
-static struct ubifs_nnode *next_nnode(struct ubifs_info *c,
- struct ubifs_nnode *nnode, int *hght)
-{
- struct ubifs_nnode *parent;
- int iip, h, i, found;
-
- parent = nnode->parent;
- if (!parent)
- return NULL;
- if (nnode->iip == UBIFS_LPT_FANOUT - 1) {
- *hght -= 1;
- return parent;
- }
- for (iip = nnode->iip + 1; iip < UBIFS_LPT_FANOUT; iip++) {
- nnode = parent->nbranch[iip].nnode;
- if (nnode)
- break;
- }
- if (!nnode) {
- *hght -= 1;
- return parent;
- }
- for (h = *hght + 1; h < c->lpt_hght; h++) {
- found = 0;
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- if (nnode->nbranch[i].nnode) {
- found = 1;
- nnode = nnode->nbranch[i].nnode;
- *hght = h;
- break;
- }
- }
- if (!found)
- break;
- }
- return nnode;
-}
-
-/**
- * ubifs_lpt_free - free resources owned by the LPT.
- * @c: UBIFS file-system description object
- * @wr_only: free only resources used for writing
- */
-void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
-{
- struct ubifs_nnode *nnode;
- int i, hght;
-
- /* Free write-only things first */
-
- free_obsolete_cnodes(c); /* Leftover from a failed commit */
-
- vfree(c->ltab_cmt);
- c->ltab_cmt = NULL;
- vfree(c->lpt_buf);
- c->lpt_buf = NULL;
- kfree(c->lsave);
- c->lsave = NULL;
-
- if (wr_only)
- return;
-
- /* Now free the rest */
-
- nnode = first_nnode(c, &hght);
- while (nnode) {
- for (i = 0; i < UBIFS_LPT_FANOUT; i++)
- kfree(nnode->nbranch[i].nnode);
- nnode = next_nnode(c, nnode, &hght);
- }
- for (i = 0; i < LPROPS_HEAP_CNT; i++)
- kfree(c->lpt_heap[i].arr);
- kfree(c->dirty_idx.arr);
- kfree(c->nroot);
- vfree(c->ltab);
- kfree(c->lpt_nod_buf);
-}
-
-#ifndef __BAREBOX__
-/*
- * Everything below is related to debugging.
- */
-
-/**
- * dbg_is_all_ff - determine if a buffer contains only 0xFF bytes.
- * @buf: buffer
- * @len: buffer length
- */
-static int dbg_is_all_ff(uint8_t *buf, int len)
-{
- int i;
-
- for (i = 0; i < len; i++)
- if (buf[i] != 0xff)
- return 0;
- return 1;
-}
-
-/**
- * dbg_is_nnode_dirty - determine if a nnode is dirty.
- * @c: the UBIFS file-system description object
- * @lnum: LEB number where nnode was written
- * @offs: offset where nnode was written
- */
-static int dbg_is_nnode_dirty(struct ubifs_info *c, int lnum, int offs)
-{
- struct ubifs_nnode *nnode;
- int hght;
-
- /* Entire tree is in memory so first_nnode / next_nnode are OK */
- nnode = first_nnode(c, &hght);
- for (; nnode; nnode = next_nnode(c, nnode, &hght)) {
- struct ubifs_nbranch *branch;
-
- cond_resched();
- if (nnode->parent) {
- branch = &nnode->parent->nbranch[nnode->iip];
- if (branch->lnum != lnum || branch->offs != offs)
- continue;
- if (test_bit(DIRTY_CNODE, &nnode->flags))
- return 1;
- return 0;
- } else {
- if (c->lpt_lnum != lnum || c->lpt_offs != offs)
- continue;
- if (test_bit(DIRTY_CNODE, &nnode->flags))
- return 1;
- return 0;
- }
- }
- return 1;
-}
-
-/**
- * dbg_is_pnode_dirty - determine if a pnode is dirty.
- * @c: the UBIFS file-system description object
- * @lnum: LEB number where pnode was written
- * @offs: offset where pnode was written
- */
-static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs)
-{
- int i, cnt;
-
- cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
- for (i = 0; i < cnt; i++) {
- struct ubifs_pnode *pnode;
- struct ubifs_nbranch *branch;
-
- cond_resched();
- pnode = pnode_lookup(c, i);
- if (IS_ERR(pnode))
- return PTR_ERR(pnode);
- branch = &pnode->parent->nbranch[pnode->iip];
- if (branch->lnum != lnum || branch->offs != offs)
- continue;
- if (test_bit(DIRTY_CNODE, &pnode->flags))
- return 1;
- return 0;
- }
- return 1;
-}
-
-/**
- * dbg_is_ltab_dirty - determine if a ltab node is dirty.
- * @c: the UBIFS file-system description object
- * @lnum: LEB number where ltab node was written
- * @offs: offset where ltab node was written
- */
-static int dbg_is_ltab_dirty(struct ubifs_info *c, int lnum, int offs)
-{
- if (lnum != c->ltab_lnum || offs != c->ltab_offs)
- return 1;
- return (c->lpt_drty_flgs & LTAB_DIRTY) != 0;
-}
-
-/**
- * dbg_is_lsave_dirty - determine if a lsave node is dirty.
- * @c: the UBIFS file-system description object
- * @lnum: LEB number where lsave node was written
- * @offs: offset where lsave node was written
- */
-static int dbg_is_lsave_dirty(struct ubifs_info *c, int lnum, int offs)
-{
- if (lnum != c->lsave_lnum || offs != c->lsave_offs)
- return 1;
- return (c->lpt_drty_flgs & LSAVE_DIRTY) != 0;
-}
-
-/**
- * dbg_is_node_dirty - determine if a node is dirty.
- * @c: the UBIFS file-system description object
- * @node_type: node type
- * @lnum: LEB number where node was written
- * @offs: offset where node was written
- */
-static int dbg_is_node_dirty(struct ubifs_info *c, int node_type, int lnum,
- int offs)
-{
- switch (node_type) {
- case UBIFS_LPT_NNODE:
- return dbg_is_nnode_dirty(c, lnum, offs);
- case UBIFS_LPT_PNODE:
- return dbg_is_pnode_dirty(c, lnum, offs);
- case UBIFS_LPT_LTAB:
- return dbg_is_ltab_dirty(c, lnum, offs);
- case UBIFS_LPT_LSAVE:
- return dbg_is_lsave_dirty(c, lnum, offs);
- }
- return 1;
-}
-
-/**
- * dbg_check_ltab_lnum - check the ltab for a LPT LEB number.
- * @c: the UBIFS file-system description object
- * @lnum: LEB number where node was written
- * @offs: offset where node was written
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
-{
- int err, len = c->leb_size, dirty = 0, node_type, node_num, node_len;
- int ret;
- void *buf, *p;
-
- if (!dbg_is_chk_lprops(c))
- return 0;
-
- buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
- if (!buf) {
- ubifs_err(c, "cannot allocate memory for ltab checking");
- return 0;
- }
-
- dbg_lp("LEB %d", lnum);
-
- err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
- if (err)
- goto out;
-
- while (1) {
- if (!is_a_node(c, p, len)) {
- int i, pad_len;
-
- pad_len = get_pad_len(c, p, len);
- if (pad_len) {
- p += pad_len;
- len -= pad_len;
- dirty += pad_len;
- continue;
- }
- if (!dbg_is_all_ff(p, len)) {
- ubifs_err(c, "invalid empty space in LEB %d at %d",
- lnum, c->leb_size - len);
- err = -EINVAL;
- }
- i = lnum - c->lpt_first;
- if (len != c->ltab[i].free) {
- ubifs_err(c, "invalid free space in LEB %d (free %d, expected %d)",
- lnum, len, c->ltab[i].free);
- err = -EINVAL;
- }
- if (dirty != c->ltab[i].dirty) {
- ubifs_err(c, "invalid dirty space in LEB %d (dirty %d, expected %d)",
- lnum, dirty, c->ltab[i].dirty);
- err = -EINVAL;
- }
- goto out;
- }
- node_type = get_lpt_node_type(c, p, &node_num);
- node_len = get_lpt_node_len(c, node_type);
- ret = dbg_is_node_dirty(c, node_type, lnum, c->leb_size - len);
- if (ret == 1)
- dirty += node_len;
- p += node_len;
- len -= node_len;
- }
-
- err = 0;
-out:
- vfree(buf);
- return err;
-}
-
-/**
- * dbg_check_ltab - check the free and dirty space in the ltab.
- * @c: the UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int dbg_check_ltab(struct ubifs_info *c)
-{
- int lnum, err, i, cnt;
-
- if (!dbg_is_chk_lprops(c))
- return 0;
-
- /* Bring the entire tree into memory */
- cnt = DIV_ROUND_UP(c->main_lebs, UBIFS_LPT_FANOUT);
- for (i = 0; i < cnt; i++) {
- struct ubifs_pnode *pnode;
-
- pnode = pnode_lookup(c, i);
- if (IS_ERR(pnode))
- return PTR_ERR(pnode);
- cond_resched();
- }
-
- /* Check nodes */
- err = dbg_check_lpt_nodes(c, (struct ubifs_cnode *)c->nroot, 0, 0);
- if (err)
- return err;
-
- /* Check each LEB */
- for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
- err = dbg_check_ltab_lnum(c, lnum);
- if (err) {
- ubifs_err(c, "failed at LEB %d", lnum);
- return err;
- }
- }
-
- dbg_lp("succeeded");
- return 0;
-}
-
-/**
- * dbg_chk_lpt_free_spc - check LPT free space is enough to write entire LPT.
- * @c: the UBIFS file-system description object
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int dbg_chk_lpt_free_spc(struct ubifs_info *c)
-{
- long long free = 0;
- int i;
-
- if (!dbg_is_chk_lprops(c))
- return 0;
-
- for (i = 0; i < c->lpt_lebs; i++) {
- if (c->ltab[i].tgc || c->ltab[i].cmt)
- continue;
- if (i + c->lpt_first == c->nhead_lnum)
- free += c->leb_size - c->nhead_offs;
- else if (c->ltab[i].free == c->leb_size)
- free += c->leb_size;
- }
- if (free < c->lpt_sz) {
- ubifs_err(c, "LPT space error: free %lld lpt_sz %lld",
- free, c->lpt_sz);
- ubifs_dump_lpt_info(c);
- ubifs_dump_lpt_lebs(c);
- dump_stack();
- return -EINVAL;
- }
- return 0;
-}
-
-/**
- * dbg_chk_lpt_sz - check LPT does not write more than LPT size.
- * @c: the UBIFS file-system description object
- * @action: what to do
- * @len: length written
- *
- * This function returns %0 on success and a negative error code on failure.
- * The @action argument may be one of:
- * o %0 - LPT debugging checking starts, initialize debugging variables;
- * o %1 - wrote an LPT node, increase LPT size by @len bytes;
- * o %2 - switched to a different LEB and wasted @len bytes;
- * o %3 - check that we've written the right number of bytes.
- * o %4 - wasted @len bytes;
- */
-int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
-{
- struct ubifs_debug_info *d = c->dbg;
- long long chk_lpt_sz, lpt_sz;
- int err = 0;
-
- if (!dbg_is_chk_lprops(c))
- return 0;
-
- switch (action) {
- case 0:
- d->chk_lpt_sz = 0;
- d->chk_lpt_sz2 = 0;
- d->chk_lpt_lebs = 0;
- d->chk_lpt_wastage = 0;
- if (c->dirty_pn_cnt > c->pnode_cnt) {
- ubifs_err(c, "dirty pnodes %d exceed max %d",
- c->dirty_pn_cnt, c->pnode_cnt);
- err = -EINVAL;
- }
- if (c->dirty_nn_cnt > c->nnode_cnt) {
- ubifs_err(c, "dirty nnodes %d exceed max %d",
- c->dirty_nn_cnt, c->nnode_cnt);
- err = -EINVAL;
- }
- return err;
- case 1:
- d->chk_lpt_sz += len;
- return 0;
- case 2:
- d->chk_lpt_sz += len;
- d->chk_lpt_wastage += len;
- d->chk_lpt_lebs += 1;
- return 0;
- case 3:
- chk_lpt_sz = c->leb_size;
- chk_lpt_sz *= d->chk_lpt_lebs;
- chk_lpt_sz += len - c->nhead_offs;
- if (d->chk_lpt_sz != chk_lpt_sz) {
- ubifs_err(c, "LPT wrote %lld but space used was %lld",
- d->chk_lpt_sz, chk_lpt_sz);
- err = -EINVAL;
- }
- if (d->chk_lpt_sz > c->lpt_sz) {
- ubifs_err(c, "LPT wrote %lld but lpt_sz is %lld",
- d->chk_lpt_sz, c->lpt_sz);
- err = -EINVAL;
- }
- if (d->chk_lpt_sz2 && d->chk_lpt_sz != d->chk_lpt_sz2) {
- ubifs_err(c, "LPT layout size %lld but wrote %lld",
- d->chk_lpt_sz, d->chk_lpt_sz2);
- err = -EINVAL;
- }
- if (d->chk_lpt_sz2 && d->new_nhead_offs != len) {
- ubifs_err(c, "LPT new nhead offs: expected %d was %d",
- d->new_nhead_offs, len);
- err = -EINVAL;
- }
- lpt_sz = (long long)c->pnode_cnt * c->pnode_sz;
- lpt_sz += (long long)c->nnode_cnt * c->nnode_sz;
- lpt_sz += c->ltab_sz;
- if (c->big_lpt)
- lpt_sz += c->lsave_sz;
- if (d->chk_lpt_sz - d->chk_lpt_wastage > lpt_sz) {
- ubifs_err(c, "LPT chk_lpt_sz %lld + waste %lld exceeds %lld",
- d->chk_lpt_sz, d->chk_lpt_wastage, lpt_sz);
- err = -EINVAL;
- }
- if (err) {
- ubifs_dump_lpt_info(c);
- ubifs_dump_lpt_lebs(c);
- dump_stack();
- }
- d->chk_lpt_sz2 = d->chk_lpt_sz;
- d->chk_lpt_sz = 0;
- d->chk_lpt_wastage = 0;
- d->chk_lpt_lebs = 0;
- d->new_nhead_offs = len;
- return err;
- case 4:
- d->chk_lpt_sz += len;
- d->chk_lpt_wastage += len;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-/**
- * ubifs_dump_lpt_leb - dump an LPT LEB.
- * @c: UBIFS file-system description object
- * @lnum: LEB number to dump
- *
- * This function dumps an LEB from LPT area. Nodes in this area are very
- * different to nodes in the main area (e.g., they do not have common headers,
- * they do not have 8-byte alignments, etc), so we have a separate function to
- * dump LPT area LEBs. Note, LPT has to be locked by the caller.
- */
-static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
-{
- int err, len = c->leb_size, node_type, node_num, node_len, offs;
- void *buf, *p;
-
- pr_err("(pid %d) start dumping LEB %d\n", current->pid, lnum);
- buf = p = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
- if (!buf) {
- ubifs_err(c, "cannot allocate memory to dump LPT");
- return;
- }
-
- err = ubifs_leb_read(c, lnum, buf, 0, c->leb_size, 1);
- if (err)
- goto out;
-
- while (1) {
- offs = c->leb_size - len;
- if (!is_a_node(c, p, len)) {
- int pad_len;
-
- pad_len = get_pad_len(c, p, len);
- if (pad_len) {
- pr_err("LEB %d:%d, pad %d bytes\n",
- lnum, offs, pad_len);
- p += pad_len;
- len -= pad_len;
- continue;
- }
- if (len)
- pr_err("LEB %d:%d, free %d bytes\n",
- lnum, offs, len);
- break;
- }
-
- node_type = get_lpt_node_type(c, p, &node_num);
- switch (node_type) {
- case UBIFS_LPT_PNODE:
- {
- node_len = c->pnode_sz;
- if (c->big_lpt)
- pr_err("LEB %d:%d, pnode num %d\n",
- lnum, offs, node_num);
- else
- pr_err("LEB %d:%d, pnode\n", lnum, offs);
- break;
- }
- case UBIFS_LPT_NNODE:
- {
- int i;
- struct ubifs_nnode nnode;
-
- node_len = c->nnode_sz;
- if (c->big_lpt)
- pr_err("LEB %d:%d, nnode num %d, ",
- lnum, offs, node_num);
- else
- pr_err("LEB %d:%d, nnode, ",
- lnum, offs);
- err = ubifs_unpack_nnode(c, p, &nnode);
- if (err) {
- pr_err("failed to unpack_node, error %d\n",
- err);
- break;
- }
- for (i = 0; i < UBIFS_LPT_FANOUT; i++) {
- pr_cont("%d:%d", nnode.nbranch[i].lnum,
- nnode.nbranch[i].offs);
- if (i != UBIFS_LPT_FANOUT - 1)
- pr_cont(", ");
- }
- pr_cont("\n");
- break;
- }
- case UBIFS_LPT_LTAB:
- node_len = c->ltab_sz;
- pr_err("LEB %d:%d, ltab\n", lnum, offs);
- break;
- case UBIFS_LPT_LSAVE:
- node_len = c->lsave_sz;
- pr_err("LEB %d:%d, lsave len\n", lnum, offs);
- break;
- default:
- ubifs_err(c, "LPT node type %d not recognized", node_type);
- goto out;
- }
-
- p += node_len;
- len -= node_len;
- }
-
- pr_err("(pid %d) finish dumping LEB %d\n", current->pid, lnum);
-out:
- vfree(buf);
- return;
-}
-
-/**
- * ubifs_dump_lpt_lebs - dump LPT lebs.
- * @c: UBIFS file-system description object
- *
- * This function dumps all LPT LEBs. The caller has to make sure the LPT is
- * locked.
- */
-void ubifs_dump_lpt_lebs(const struct ubifs_info *c)
-{
- int i;
-
- pr_err("(pid %d) start dumping all LPT LEBs\n", current->pid);
- for (i = 0; i < c->lpt_lebs; i++)
- dump_lpt_leb(c, i + c->lpt_first);
- pr_err("(pid %d) finish dumping all LPT LEBs\n", current->pid);
-}
-
-/**
- * dbg_populate_lsave - debugging version of 'populate_lsave()'
- * @c: UBIFS file-system description object
- *
- * This is a debugging version for 'populate_lsave()' which populates lsave
- * with random LEBs instead of useful LEBs, which is good for test coverage.
- * Returns zero if lsave has not been populated (this debugging feature is
- * disabled) an non-zero if lsave has been populated.
- */
-static int dbg_populate_lsave(struct ubifs_info *c)
-{
- struct ubifs_lprops *lprops;
- struct ubifs_lpt_heap *heap;
- int i;
-
- if (!dbg_is_chk_gen(c))
- return 0;
- if (prandom_u32() & 3)
- return 0;
-
- for (i = 0; i < c->lsave_cnt; i++)
- c->lsave[i] = c->main_first;
-
- list_for_each_entry(lprops, &c->empty_list, list)
- c->lsave[prandom_u32() % c->lsave_cnt] = lprops->lnum;
- list_for_each_entry(lprops, &c->freeable_list, list)
- c->lsave[prandom_u32() % c->lsave_cnt] = lprops->lnum;
- list_for_each_entry(lprops, &c->frdi_idx_list, list)
- c->lsave[prandom_u32() % c->lsave_cnt] = lprops->lnum;
-
- heap = &c->lpt_heap[LPROPS_DIRTY_IDX - 1];
- for (i = 0; i < heap->cnt; i++)
- c->lsave[prandom_u32() % c->lsave_cnt] = heap->arr[i]->lnum;
- heap = &c->lpt_heap[LPROPS_DIRTY - 1];
- for (i = 0; i < heap->cnt; i++)
- c->lsave[prandom_u32() % c->lsave_cnt] = heap->arr[i]->lnum;
- heap = &c->lpt_heap[LPROPS_FREE - 1];
- for (i = 0; i < heap->cnt; i++)
- c->lsave[prandom_u32() % c->lsave_cnt] = heap->arr[i]->lnum;
-
- return 1;
-}
-#endif
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index 40d9ab4f35..3bf37c2b12 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -12,9 +12,7 @@
/* 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.
@@ -335,57 +333,7 @@ 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
diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
index c0597d04f2..4822dd3b92 100644
--- a/fs/ubifs/misc.h
+++ b/fs/ubifs/misc.h
@@ -133,27 +133,6 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
return err;
}
-#ifndef __BAREBOX__
-/**
- * ubifs_encode_dev - encode device node IDs.
- * @dev: UBIFS device node information
- * @rdev: device IDs to encode
- *
- * This is a helper function which encodes major/minor numbers of a device node
- * into UBIFS device node description. We use standard Linux "new" and "huge"
- * encodings.
- */
-static inline int ubifs_encode_dev(union ubifs_dev_desc *dev, dev_t rdev)
-{
- if (new_valid_dev(rdev)) {
- dev->new = cpu_to_le32(new_encode_dev(rdev));
- return sizeof(dev->new);
- } else {
- dev->huge = cpu_to_le64(huge_encode_dev(rdev));
- return sizeof(dev->huge);
- }
-}
-#endif
/**
* ubifs_add_dirt - add dirty space to LEB properties.
@@ -166,7 +145,7 @@ static inline int ubifs_encode_dev(union ubifs_dev_desc *dev, dev_t rdev)
*/
static inline int ubifs_add_dirt(struct ubifs_info *c, int lnum, int dirty)
{
- return ubifs_update_one_lp(c, lnum, LPROPS_NC, dirty, 0, 0);
+ return 0;
}
/**
@@ -180,8 +159,7 @@ static inline int ubifs_add_dirt(struct ubifs_info *c, int lnum, int dirty)
*/
static inline int ubifs_return_leb(struct ubifs_info *c, int lnum)
{
- return ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
- LPROPS_TAKEN, 0);
+ return 0;
}
/**
@@ -217,27 +195,12 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
static inline void *ubifs_idx_key(const struct ubifs_info *c,
const struct ubifs_idx_node *idx)
{
-#ifndef __BAREBOX__
- return (void *)((struct ubifs_branch *)idx->branches)->key;
-#else
struct ubifs_branch *tmp;
tmp = (struct ubifs_branch *)idx->branches;
return (void *)tmp->key;
-#endif
}
-#ifndef __BAREBOX__
-/**
- * ubifs_current_time - round current time to time granularity.
- * @inode: inode
- */
-static inline struct timespec ubifs_current_time(struct inode *inode)
-{
- return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ?
- current_fs_time(inode->i_sb) : CURRENT_TIME_SEC;
-}
-#endif
/**
* ubifs_tnc_lookup - look up a file-system node.
diff --git a/fs/ubifs/orphan.c b/fs/ubifs/orphan.c
deleted file mode 100644
index f5c8e23d0b..0000000000
--- a/fs/ubifs/orphan.c
+++ /dev/null
@@ -1,946 +0,0 @@
-/*
- * This file is part of UBIFS.
- *
- * Copyright (C) 2006-2008 Nokia Corporation.
- *
- * SPDX-License-Identifier: GPL-2.0+
- *
- * Author: Adrian Hunter
- */
-
-#include <linux/err.h>
-#include "ubifs.h"
-
-/*
- * An orphan is an inode number whose inode node has been committed to the index
- * with a link count of zero. That happens when an open file is deleted
- * (unlinked) and then a commit is run. In the normal course of events the inode
- * would be deleted when the file is closed. However in the case of an unclean
- * unmount, orphans need to be accounted for. After an unclean unmount, the
- * orphans' inodes must be deleted which means either scanning the entire index
- * looking for them, or keeping a list on flash somewhere. This unit implements
- * the latter approach.
- *
- * The orphan area is a fixed number of LEBs situated between the LPT area and
- * the main area. The number of orphan area LEBs is specified when the file
- * system is created. The minimum number is 1. The size of the orphan area
- * should be so that it can hold the maximum number of orphans that are expected
- * to ever exist at one time.
- *
- * The number of orphans that can fit in a LEB is:
- *
- * (c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64)
- *
- * For example: a 15872 byte LEB can fit 1980 orphans so 1 LEB may be enough.
- *
- * Orphans are accumulated in a rb-tree. When an inode's link count drops to
- * zero, the inode number is added to the rb-tree. It is removed from the tree
- * when the inode is deleted. Any new orphans that are in the orphan tree when
- * the commit is run, are written to the orphan area in 1 or more orphan nodes.
- * If the orphan area is full, it is consolidated to make space. There is
- * always enough space because validation prevents the user from creating more
- * than the maximum number of orphans allowed.
- */
-
-static int dbg_check_orphans(struct ubifs_info *c);
-
-/**
- * ubifs_add_orphan - add an orphan.
- * @c: UBIFS file-system description object
- * @inum: orphan inode number
- *
- * Add an orphan. This function is called when an inodes link count drops to
- * zero.
- */
-int ubifs_add_orphan(struct ubifs_info *c, ino_t inum)
-{
- struct ubifs_orphan *orphan, *o;
- struct rb_node **p, *parent = NULL;
-
- orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_NOFS);
- if (!orphan)
- return -ENOMEM;
- orphan->inum = inum;
- orphan->new = 1;
-
- spin_lock(&c->orphan_lock);
- if (c->tot_orphans >= c->max_orphans) {
- spin_unlock(&c->orphan_lock);
- kfree(orphan);
- return -ENFILE;
- }
- p = &c->orph_tree.rb_node;
- while (*p) {
- parent = *p;
- o = rb_entry(parent, struct ubifs_orphan, rb);
- if (inum < o->inum)
- p = &(*p)->rb_left;
- else if (inum > o->inum)
- p = &(*p)->rb_right;
- else {
- ubifs_err(c, "orphaned twice");
- spin_unlock(&c->orphan_lock);
- kfree(orphan);
- return 0;
- }
- }
- c->tot_orphans += 1;
- c->new_orphans += 1;
- rb_link_node(&orphan->rb, parent, p);
- rb_insert_color(&orphan->rb, &c->orph_tree);
- list_add_tail(&orphan->list, &c->orph_list);
- list_add_tail(&orphan->new_list, &c->orph_new);
- spin_unlock(&c->orphan_lock);
- dbg_gen("ino %lu", (unsigned long)inum);
- return 0;
-}
-
-/**
- * ubifs_delete_orphan - delete an orphan.
- * @c: UBIFS file-system description object
- * @inum: orphan inode number
- *
- * Delete an orphan. This function is called when an inode is deleted.
- */
-void ubifs_delete_orphan(struct ubifs_info *c, ino_t inum)
-{
- struct ubifs_orphan *o;
- struct rb_node *p;
-
- spin_lock(&c->orphan_lock);
- p = c->orph_tree.rb_node;
- while (p) {
- o = rb_entry(p, struct ubifs_orphan, rb);
- if (inum < o->inum)
- p = p->rb_left;
- else if (inum > o->inum)
- p = p->rb_right;
- else {
- if (o->del) {
- spin_unlock(&c->orphan_lock);
- dbg_gen("deleted twice ino %lu",
- (unsigned long)inum);
- return;
- }
- if (o->cmt) {
- o->del = 1;
- o->dnext = c->orph_dnext;
- c->orph_dnext = o;
- spin_unlock(&c->orphan_lock);
- dbg_gen("delete later ino %lu",
- (unsigned long)inum);
- return;
- }
- rb_erase(p, &c->orph_tree);
- list_del(&o->list);
- c->tot_orphans -= 1;
- if (o->new) {
- list_del(&o->new_list);
- c->new_orphans -= 1;
- }
- spin_unlock(&c->orphan_lock);
- kfree(o);
- dbg_gen("inum %lu", (unsigned long)inum);
- return;
- }
- }
- spin_unlock(&c->orphan_lock);
- ubifs_err(c, "missing orphan ino %lu", (unsigned long)inum);
- dump_stack();
-}
-
-/**
- * ubifs_orphan_start_commit - start commit of orphans.
- * @c: UBIFS file-system description object
- *
- * Start commit of orphans.
- */
-int ubifs_orphan_start_commit(struct ubifs_info *c)
-{
- struct ubifs_orphan *orphan, **last;
-
- spin_lock(&c->orphan_lock);
- last = &c->orph_cnext;
- list_for_each_entry(orphan, &c->orph_new, new_list) {
- ubifs_assert(orphan->new);
- ubifs_assert(!orphan->cmt);
- orphan->new = 0;
- orphan->cmt = 1;
- *last = orphan;
- last = &orphan->cnext;
- }
- *last = NULL;
- c->cmt_orphans = c->new_orphans;
- c->new_orphans = 0;
- dbg_cmt("%d orphans to commit", c->cmt_orphans);
- INIT_LIST_HEAD(&c->orph_new);
- if (c->tot_orphans == 0)
- c->no_orphs = 1;
- else
- c->no_orphs = 0;
- spin_unlock(&c->orphan_lock);
- return 0;
-}
-
-/**
- * avail_orphs - calculate available space.
- * @c: UBIFS file-system description object
- *
- * This function returns the number of orphans that can be written in the
- * available space.
- */
-static int avail_orphs(struct ubifs_info *c)
-{
- int avail_lebs, avail, gap;
-
- avail_lebs = c->orph_lebs - (c->ohead_lnum - c->orph_first) - 1;
- avail = avail_lebs *
- ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64));
- gap = c->leb_size - c->ohead_offs;
- if (gap >= UBIFS_ORPH_NODE_SZ + sizeof(__le64))
- avail += (gap - UBIFS_ORPH_NODE_SZ) / sizeof(__le64);
- return avail;
-}
-
-/**
- * tot_avail_orphs - calculate total space.
- * @c: UBIFS file-system description object
- *
- * This function returns the number of orphans that can be written in half
- * the total space. That leaves half the space for adding new orphans.
- */
-static int tot_avail_orphs(struct ubifs_info *c)
-{
- int avail_lebs, avail;
-
- avail_lebs = c->orph_lebs;
- avail = avail_lebs *
- ((c->leb_size - UBIFS_ORPH_NODE_SZ) / sizeof(__le64));
- return avail / 2;
-}
-
-/**
- * do_write_orph_node - write a node to the orphan head.
- * @c: UBIFS file-system description object
- * @len: length of node
- * @atomic: write atomically
- *
- * This function writes a node to the orphan head from the orphan buffer. If
- * %atomic is not zero, then the write is done atomically. On success, %0 is
- * returned, otherwise a negative error code is returned.
- */
-static int do_write_orph_node(struct ubifs_info *c, int len, int atomic)
-{
- int err = 0;
-
- if (atomic) {
- ubifs_assert(c->ohead_offs == 0);
- ubifs_prepare_node(c, c->orph_buf, len, 1);
- len = ALIGN(len, c->min_io_size);
- err = ubifs_leb_change(c, c->ohead_lnum, c->orph_buf, len);
- } else {
- if (c->ohead_offs == 0) {
- /* Ensure LEB has been unmapped */
- err = ubifs_leb_unmap(c, c->ohead_lnum);
- if (err)
- return err;
- }
- err = ubifs_write_node(c, c->orph_buf, len, c->ohead_lnum,
- c->ohead_offs);
- }
- return err;
-}
-
-/**
- * write_orph_node - write an orphan node.
- * @c: UBIFS file-system description object
- * @atomic: write atomically
- *
- * This function builds an orphan node from the cnext list and writes it to the
- * orphan head. On success, %0 is returned, otherwise a negative error code
- * is returned.
- */
-static int write_orph_node(struct ubifs_info *c, int atomic)
-{
- struct ubifs_orphan *orphan, *cnext;
- struct ubifs_orph_node *orph;
- int gap, err, len, cnt, i;
-
- ubifs_assert(c->cmt_orphans > 0);
- gap = c->leb_size - c->ohead_offs;
- if (gap < UBIFS_ORPH_NODE_SZ + sizeof(__le64)) {
- c->ohead_lnum += 1;
- c->ohead_offs = 0;
- gap = c->leb_size;
- if (c->ohead_lnum > c->orph_last) {
- /*
- * We limit the number of orphans so that this should
- * never happen.
- */
- ubifs_err(c, "out of space in orphan area");
- return -EINVAL;
- }
- }
- cnt = (gap - UBIFS_ORPH_NODE_SZ) / sizeof(__le64);
- if (cnt > c->cmt_orphans)
- cnt = c->cmt_orphans;
- len = UBIFS_ORPH_NODE_SZ + cnt * sizeof(__le64);
- ubifs_assert(c->orph_buf);
- orph = c->orph_buf;
- orph->ch.node_type = UBIFS_ORPH_NODE;
- spin_lock(&c->orphan_lock);
- cnext = c->orph_cnext;
- for (i = 0; i < cnt; i++) {
- orphan = cnext;
- ubifs_assert(orphan->cmt);
- orph->inos[i] = cpu_to_le64(orphan->inum);
- orphan->cmt = 0;
- cnext = orphan->cnext;
- orphan->cnext = NULL;
- }
- c->orph_cnext = cnext;
- c->cmt_orphans -= cnt;
- spin_unlock(&c->orphan_lock);
- if (c->cmt_orphans)
- orph->cmt_no = cpu_to_le64(c->cmt_no);
- else
- /* Mark the last node of the commit */
- orph->cmt_no = cpu_to_le64((c->cmt_no) | (1ULL << 63));
- ubifs_assert(c->ohead_offs + len <= c->leb_size);
- ubifs_assert(c->ohead_lnum >= c->orph_first);
- ubifs_assert(c->ohead_lnum <= c->orph_last);
- err = do_write_orph_node(c, len, atomic);
- c->ohead_offs += ALIGN(len, c->min_io_size);
- c->ohead_offs = ALIGN(c->ohead_offs, 8);
- return err;
-}
-
-/**
- * write_orph_nodes - write orphan nodes until there are no more to commit.
- * @c: UBIFS file-system description object
- * @atomic: write atomically
- *
- * This function writes orphan nodes for all the orphans to commit. On success,
- * %0 is returned, otherwise a negative error code is returned.
- */
-static int write_orph_nodes(struct ubifs_info *c, int atomic)
-{
- int err;
-
- while (c->cmt_orphans > 0) {
- err = write_orph_node(c, atomic);
- if (err)
- return err;
- }
- if (atomic) {
- int lnum;
-
- /* Unmap any unused LEBs after consolidation */
- for (lnum = c->ohead_lnum + 1; lnum <= c->orph_last; lnum++) {
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- return err;
- }
- }
- return 0;
-}
-
-/**
- * consolidate - consolidate the orphan area.
- * @c: UBIFS file-system description object
- *
- * This function enables consolidation by putting all the orphans into the list
- * to commit. The list is in the order that the orphans were added, and the
- * LEBs are written atomically in order, so at no time can orphans be lost by
- * an unclean unmount.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int consolidate(struct ubifs_info *c)
-{
- int tot_avail = tot_avail_orphs(c), err = 0;
-
- spin_lock(&c->orphan_lock);
- dbg_cmt("there is space for %d orphans and there are %d",
- tot_avail, c->tot_orphans);
- if (c->tot_orphans - c->new_orphans <= tot_avail) {
- struct ubifs_orphan *orphan, **last;
- int cnt = 0;
-
- /* Change the cnext list to include all non-new orphans */
- last = &c->orph_cnext;
- list_for_each_entry(orphan, &c->orph_list, list) {
- if (orphan->new)
- continue;
- orphan->cmt = 1;
- *last = orphan;
- last = &orphan->cnext;
- cnt += 1;
- }
- *last = NULL;
- ubifs_assert(cnt == c->tot_orphans - c->new_orphans);
- c->cmt_orphans = cnt;
- c->ohead_lnum = c->orph_first;
- c->ohead_offs = 0;
- } else {
- /*
- * We limit the number of orphans so that this should
- * never happen.
- */
- ubifs_err(c, "out of space in orphan area");
- err = -EINVAL;
- }
- spin_unlock(&c->orphan_lock);
- return err;
-}
-
-/**
- * commit_orphans - commit orphans.
- * @c: UBIFS file-system description object
- *
- * This function commits orphans to flash. On success, %0 is returned,
- * otherwise a negative error code is returned.
- */
-static int commit_orphans(struct ubifs_info *c)
-{
- int avail, atomic = 0, err;
-
- ubifs_assert(c->cmt_orphans > 0);
- avail = avail_orphs(c);
- if (avail < c->cmt_orphans) {
- /* Not enough space to write new orphans, so consolidate */
- err = consolidate(c);
- if (err)
- return err;
- atomic = 1;
- }
- err = write_orph_nodes(c, atomic);
- return err;
-}
-
-/**
- * erase_deleted - erase the orphans marked for deletion.
- * @c: UBIFS file-system description object
- *
- * During commit, the orphans being committed cannot be deleted, so they are
- * marked for deletion and deleted by this function. Also, the recovery
- * adds killed orphans to the deletion list, and therefore they are deleted
- * here too.
- */
-static void erase_deleted(struct ubifs_info *c)
-{
- struct ubifs_orphan *orphan, *dnext;
-
- spin_lock(&c->orphan_lock);
- dnext = c->orph_dnext;
- while (dnext) {
- orphan = dnext;
- dnext = orphan->dnext;
- ubifs_assert(!orphan->new);
- ubifs_assert(orphan->del);
- rb_erase(&orphan->rb, &c->orph_tree);
- list_del(&orphan->list);
- c->tot_orphans -= 1;
- dbg_gen("deleting orphan ino %lu", (unsigned long)orphan->inum);
- kfree(orphan);
- }
- c->orph_dnext = NULL;
- spin_unlock(&c->orphan_lock);
-}
-
-/**
- * ubifs_orphan_end_commit - end commit of orphans.
- * @c: UBIFS file-system description object
- *
- * End commit of orphans.
- */
-int ubifs_orphan_end_commit(struct ubifs_info *c)
-{
- int err;
-
- if (c->cmt_orphans != 0) {
- err = commit_orphans(c);
- if (err)
- return err;
- }
- erase_deleted(c);
- err = dbg_check_orphans(c);
- return err;
-}
-
-/**
- * ubifs_clear_orphans - erase all LEBs used for orphans.
- * @c: UBIFS file-system description object
- *
- * If recovery is not required, then the orphans from the previous session
- * are not needed. This function locates the LEBs used to record
- * orphans, and un-maps them.
- */
-int ubifs_clear_orphans(struct ubifs_info *c)
-{
- int lnum, err;
-
- for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- return err;
- }
- c->ohead_lnum = c->orph_first;
- c->ohead_offs = 0;
- return 0;
-}
-
-/**
- * insert_dead_orphan - insert an orphan.
- * @c: UBIFS file-system description object
- * @inum: orphan inode number
- *
- * This function is a helper to the 'do_kill_orphans()' function. The orphan
- * must be kept until the next commit, so it is added to the rb-tree and the
- * deletion list.
- */
-static int insert_dead_orphan(struct ubifs_info *c, ino_t inum)
-{
- struct ubifs_orphan *orphan, *o;
- struct rb_node **p, *parent = NULL;
-
- orphan = kzalloc(sizeof(struct ubifs_orphan), GFP_KERNEL);
- if (!orphan)
- return -ENOMEM;
- orphan->inum = inum;
-
- p = &c->orph_tree.rb_node;
- while (*p) {
- parent = *p;
- o = rb_entry(parent, struct ubifs_orphan, rb);
- if (inum < o->inum)
- p = &(*p)->rb_left;
- else if (inum > o->inum)
- p = &(*p)->rb_right;
- else {
- /* Already added - no problem */
- kfree(orphan);
- return 0;
- }
- }
- c->tot_orphans += 1;
- rb_link_node(&orphan->rb, parent, p);
- rb_insert_color(&orphan->rb, &c->orph_tree);
- list_add_tail(&orphan->list, &c->orph_list);
- orphan->del = 1;
- orphan->dnext = c->orph_dnext;
- c->orph_dnext = orphan;
- dbg_mnt("ino %lu, new %d, tot %d", (unsigned long)inum,
- c->new_orphans, c->tot_orphans);
- return 0;
-}
-
-/**
- * do_kill_orphans - remove orphan inodes from the index.
- * @c: UBIFS file-system description object
- * @sleb: scanned LEB
- * @last_cmt_no: cmt_no of last orphan node read is passed and returned here
- * @outofdate: whether the LEB is out of date is returned here
- * @last_flagged: whether the end orphan node is encountered
- *
- * This function is a helper to the 'kill_orphans()' function. It goes through
- * every orphan node in a LEB and for every inode number recorded, removes
- * all keys for that inode from the TNC.
- */
-static int do_kill_orphans(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
- unsigned long long *last_cmt_no, int *outofdate,
- int *last_flagged)
-{
- struct ubifs_scan_node *snod;
- struct ubifs_orph_node *orph;
- unsigned long long cmt_no;
- ino_t inum;
- int i, n, err, first = 1;
-
- list_for_each_entry(snod, &sleb->nodes, list) {
- if (snod->type != UBIFS_ORPH_NODE) {
- ubifs_err(c, "invalid node type %d in orphan area at %d:%d",
- snod->type, sleb->lnum, snod->offs);
- ubifs_dump_node(c, snod->node);
- return -EINVAL;
- }
-
- orph = snod->node;
-
- /* Check commit number */
- cmt_no = le64_to_cpu(orph->cmt_no) & LLONG_MAX;
- /*
- * The commit number on the master node may be less, because
- * of a failed commit. If there are several failed commits in a
- * row, the commit number written on orphan nodes will continue
- * to increase (because the commit number is adjusted here) even
- * though the commit number on the master node stays the same
- * because the master node has not been re-written.
- */
- if (cmt_no > c->cmt_no)
- c->cmt_no = cmt_no;
- if (cmt_no < *last_cmt_no && *last_flagged) {
- /*
- * The last orphan node had a higher commit number and
- * was flagged as the last written for that commit
- * number. That makes this orphan node, out of date.
- */
- if (!first) {
- ubifs_err(c, "out of order commit number %llu in orphan node at %d:%d",
- cmt_no, sleb->lnum, snod->offs);
- ubifs_dump_node(c, snod->node);
- return -EINVAL;
- }
- dbg_rcvry("out of date LEB %d", sleb->lnum);
- *outofdate = 1;
- return 0;
- }
-
- if (first)
- first = 0;
-
- n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
- for (i = 0; i < n; i++) {
- inum = le64_to_cpu(orph->inos[i]);
- dbg_rcvry("deleting orphaned inode %lu",
- (unsigned long)inum);
- err = ubifs_tnc_remove_ino(c, inum);
- if (err)
- return err;
- err = insert_dead_orphan(c, inum);
- if (err)
- return err;
- }
-
- *last_cmt_no = cmt_no;
- if (le64_to_cpu(orph->cmt_no) & (1ULL << 63)) {
- dbg_rcvry("last orph node for commit %llu at %d:%d",
- cmt_no, sleb->lnum, snod->offs);
- *last_flagged = 1;
- } else
- *last_flagged = 0;
- }
-
- return 0;
-}
-
-/**
- * kill_orphans - remove all orphan inodes from the index.
- * @c: UBIFS file-system description object
- *
- * If recovery is required, then orphan inodes recorded during the previous
- * session (which ended with an unclean unmount) must be deleted from the index.
- * This is done by updating the TNC, but since the index is not updated until
- * the next commit, the LEBs where the orphan information is recorded are not
- * erased until the next commit.
- */
-static int kill_orphans(struct ubifs_info *c)
-{
- unsigned long long last_cmt_no = 0;
- int lnum, err = 0, outofdate = 0, last_flagged = 0;
-
- c->ohead_lnum = c->orph_first;
- c->ohead_offs = 0;
- /* Check no-orphans flag and skip this if no orphans */
- if (c->no_orphs) {
- dbg_rcvry("no orphans");
- return 0;
- }
- /*
- * Orph nodes always start at c->orph_first and are written to each
- * successive LEB in turn. Generally unused LEBs will have been unmapped
- * but may contain out of date orphan nodes if the unmap didn't go
- * through. In addition, the last orphan node written for each commit is
- * marked (top bit of orph->cmt_no is set to 1). It is possible that
- * there are orphan nodes from the next commit (i.e. the commit did not
- * complete successfully). In that case, no orphans will have been lost
- * due to the way that orphans are written, and any orphans added will
- * be valid orphans anyway and so can be deleted.
- */
- for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
- struct ubifs_scan_leb *sleb;
-
- dbg_rcvry("LEB %d", lnum);
- sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);
- if (IS_ERR(sleb)) {
- if (PTR_ERR(sleb) == -EUCLEAN)
- sleb = ubifs_recover_leb(c, lnum, 0,
- c->sbuf, -1);
- if (IS_ERR(sleb)) {
- err = PTR_ERR(sleb);
- break;
- }
- }
- err = do_kill_orphans(c, sleb, &last_cmt_no, &outofdate,
- &last_flagged);
- if (err || outofdate) {
- ubifs_scan_destroy(sleb);
- break;
- }
- if (sleb->endpt) {
- c->ohead_lnum = lnum;
- c->ohead_offs = sleb->endpt;
- }
- ubifs_scan_destroy(sleb);
- }
- return err;
-}
-
-/**
- * ubifs_mount_orphans - delete orphan inodes and erase LEBs that recorded them.
- * @c: UBIFS file-system description object
- * @unclean: indicates recovery from unclean unmount
- * @read_only: indicates read only mount
- *
- * This function is called when mounting to erase orphans from the previous
- * session. If UBIFS was not unmounted cleanly, then the inodes recorded as
- * orphans are deleted.
- */
-int ubifs_mount_orphans(struct ubifs_info *c, int unclean, int read_only)
-{
- int err = 0;
-
- c->max_orphans = tot_avail_orphs(c);
-
- if (!read_only) {
- c->orph_buf = vmalloc(c->leb_size);
- if (!c->orph_buf)
- return -ENOMEM;
- }
-
- if (unclean)
- err = kill_orphans(c);
- else if (!read_only)
- err = ubifs_clear_orphans(c);
-
- return err;
-}
-
-/*
- * Everything below is related to debugging.
- */
-
-struct check_orphan {
- struct rb_node rb;
- ino_t inum;
-};
-
-struct check_info {
- unsigned long last_ino;
- unsigned long tot_inos;
- unsigned long missing;
- unsigned long long leaf_cnt;
- struct ubifs_ino_node *node;
- struct rb_root root;
-};
-
-static int dbg_find_orphan(struct ubifs_info *c, ino_t inum)
-{
- struct ubifs_orphan *o;
- struct rb_node *p;
-
- spin_lock(&c->orphan_lock);
- p = c->orph_tree.rb_node;
- while (p) {
- o = rb_entry(p, struct ubifs_orphan, rb);
- if (inum < o->inum)
- p = p->rb_left;
- else if (inum > o->inum)
- p = p->rb_right;
- else {
- spin_unlock(&c->orphan_lock);
- return 1;
- }
- }
- spin_unlock(&c->orphan_lock);
- return 0;
-}
-
-static int dbg_ins_check_orphan(struct rb_root *root, ino_t inum)
-{
- struct check_orphan *orphan, *o;
- struct rb_node **p, *parent = NULL;
-
- orphan = kzalloc(sizeof(struct check_orphan), GFP_NOFS);
- if (!orphan)
- return -ENOMEM;
- orphan->inum = inum;
-
- p = &root->rb_node;
- while (*p) {
- parent = *p;
- o = rb_entry(parent, struct check_orphan, rb);
- if (inum < o->inum)
- p = &(*p)->rb_left;
- else if (inum > o->inum)
- p = &(*p)->rb_right;
- else {
- kfree(orphan);
- return 0;
- }
- }
- rb_link_node(&orphan->rb, parent, p);
- rb_insert_color(&orphan->rb, root);
- return 0;
-}
-
-static int dbg_find_check_orphan(struct rb_root *root, ino_t inum)
-{
- struct check_orphan *o;
- struct rb_node *p;
-
- p = root->rb_node;
- while (p) {
- o = rb_entry(p, struct check_orphan, rb);
- if (inum < o->inum)
- p = p->rb_left;
- else if (inum > o->inum)
- p = p->rb_right;
- else
- return 1;
- }
- return 0;
-}
-
-static void dbg_free_check_tree(struct rb_root *root)
-{
- struct check_orphan *o, *n;
-
- rbtree_postorder_for_each_entry_safe(o, n, root, rb)
- kfree(o);
-}
-
-static int dbg_orphan_check(struct ubifs_info *c, struct ubifs_zbranch *zbr,
- void *priv)
-{
- struct check_info *ci = priv;
- ino_t inum;
- int err;
-
- inum = key_inum(c, &zbr->key);
- if (inum != ci->last_ino) {
- /* Lowest node type is the inode node, so it comes first */
- if (key_type(c, &zbr->key) != UBIFS_INO_KEY)
- ubifs_err(c, "found orphan node ino %lu, type %d",
- (unsigned long)inum, key_type(c, &zbr->key));
- ci->last_ino = inum;
- ci->tot_inos += 1;
- err = ubifs_tnc_read_node(c, zbr, ci->node);
- if (err) {
- ubifs_err(c, "node read failed, error %d", err);
- return err;
- }
- if (ci->node->nlink == 0)
- /* Must be recorded as an orphan */
- if (!dbg_find_check_orphan(&ci->root, inum) &&
- !dbg_find_orphan(c, inum)) {
- ubifs_err(c, "missing orphan, ino %lu",
- (unsigned long)inum);
- ci->missing += 1;
- }
- }
- ci->leaf_cnt += 1;
- return 0;
-}
-
-static int dbg_read_orphans(struct check_info *ci, struct ubifs_scan_leb *sleb)
-{
- struct ubifs_scan_node *snod;
- struct ubifs_orph_node *orph;
- ino_t inum;
- int i, n, err;
-
- list_for_each_entry(snod, &sleb->nodes, list) {
- cond_resched();
- if (snod->type != UBIFS_ORPH_NODE)
- continue;
- orph = snod->node;
- n = (le32_to_cpu(orph->ch.len) - UBIFS_ORPH_NODE_SZ) >> 3;
- for (i = 0; i < n; i++) {
- inum = le64_to_cpu(orph->inos[i]);
- err = dbg_ins_check_orphan(&ci->root, inum);
- if (err)
- return err;
- }
- }
- return 0;
-}
-
-static int dbg_scan_orphans(struct ubifs_info *c, struct check_info *ci)
-{
- int lnum, err = 0;
- void *buf;
-
- /* Check no-orphans flag and skip this if no orphans */
- if (c->no_orphs)
- return 0;
-
- buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
- if (!buf) {
- ubifs_err(c, "cannot allocate memory to check orphans");
- return 0;
- }
-
- for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
- struct ubifs_scan_leb *sleb;
-
- sleb = ubifs_scan(c, lnum, 0, buf, 0);
- if (IS_ERR(sleb)) {
- err = PTR_ERR(sleb);
- break;
- }
-
- err = dbg_read_orphans(ci, sleb);
- ubifs_scan_destroy(sleb);
- if (err)
- break;
- }
-
- vfree(buf);
- return err;
-}
-
-static int dbg_check_orphans(struct ubifs_info *c)
-{
- struct check_info ci;
- int err;
-
- if (!dbg_is_chk_orph(c))
- return 0;
-
- ci.last_ino = 0;
- ci.tot_inos = 0;
- ci.missing = 0;
- ci.leaf_cnt = 0;
- ci.root = RB_ROOT;
- ci.node = kmalloc(UBIFS_MAX_INO_NODE_SZ, GFP_NOFS);
- if (!ci.node) {
- ubifs_err(c, "out of memory");
- return -ENOMEM;
- }
-
- err = dbg_scan_orphans(c, &ci);
- if (err)
- goto out;
-
- err = dbg_walk_index(c, &dbg_orphan_check, NULL, &ci);
- if (err) {
- ubifs_err(c, "cannot scan TNC, error %d", err);
- goto out;
- }
-
- if (ci.missing) {
- ubifs_err(c, "%lu missing orphan(s)", ci.missing);
- err = -EINVAL;
- goto out;
- }
-
- dbg_cmt("last inode number is %lu", ci.last_ino);
- dbg_cmt("total number of inodes is %lu", ci.tot_inos);
- dbg_cmt("total number of leaf nodes is %llu", ci.leaf_cnt);
-
-out:
- dbg_free_check_tree(&ci.root);
- kfree(ci.node);
- return err;
-}
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 897fe3c788..5b3902b632 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -36,12 +36,7 @@
* refuses to mount.
*/
-#ifndef __BAREBOX__
-#include <linux/crc32.h>
-#include <linux/slab.h>
-#else
#include <linux/err.h>
-#endif
#include "ubifs.h"
/**
@@ -187,36 +182,6 @@ out_free:
return err;
}
-/**
- * write_rcvrd_mst_node - write recovered master node.
- * @c: UBIFS file-system description object
- * @mst: master node
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int write_rcvrd_mst_node(struct ubifs_info *c,
- struct ubifs_mst_node *mst)
-{
- int err = 0, lnum = UBIFS_MST_LNUM, sz = c->mst_node_alsz;
- __le32 save_flags;
-
- dbg_rcvry("recovery");
-
- save_flags = mst->flags;
- mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY);
-
- ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1);
- err = ubifs_leb_change(c, lnum, mst, sz);
- if (err)
- goto out;
- err = ubifs_leb_change(c, lnum + 1, mst, sz);
- if (err)
- goto out;
-out:
- mst->flags = save_flags;
- return err;
-}
-
/**
* ubifs_recover_master_node - recover the master node.
* @c: UBIFS file-system description object
@@ -337,14 +302,6 @@ int ubifs_recover_master_node(struct ubifs_info *c)
* dirty.
*/
c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
-#ifndef __BAREBOX__
- } else {
- /* Write the recovered master node */
- c->max_sqnum = le64_to_cpu(mst->ch.sqnum) - 1;
- err = write_rcvrd_mst_node(c, c->mst_node);
- if (err)
- goto out_free;
-#endif
}
vfree(buf2);
@@ -369,31 +326,6 @@ out_free:
return err;
}
-/**
- * ubifs_write_rcvrd_mst_node - write the recovered master node.
- * @c: UBIFS file-system description object
- *
- * This function writes the master node that was recovered during mounting in
- * read-only mode and must now be written because we are remounting rw.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
-{
- int err;
-
- if (!c->rcvrd_mst_node)
- return 0;
- c->rcvrd_mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
- c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
- err = write_rcvrd_mst_node(c, c->rcvrd_mst_node);
- if (err)
- return err;
- kfree(c->rcvrd_mst_node);
- c->rcvrd_mst_node = NULL;
- return 0;
-}
-
/**
* is_last_write - determine if an offset was in the last write to a LEB.
* @c: UBIFS file-system description object
@@ -521,41 +453,6 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
ucleb->lnum = lnum;
ucleb->endpt = endpt;
list_add_tail(&ucleb->list, &c->unclean_leb_list);
-#ifndef __BAREBOX__
- } else {
- /* Write the fixed LEB back to flash */
- int err;
-
- dbg_rcvry("fixing LEB %d start %d endpt %d",
- lnum, start, sleb->endpt);
- if (endpt == 0) {
- err = ubifs_leb_unmap(c, lnum);
- if (err)
- return err;
- } else {
- int len = ALIGN(endpt, c->min_io_size);
-
- if (start) {
- err = ubifs_leb_read(c, lnum, sleb->buf, 0,
- start, 1);
- if (err)
- return err;
- }
- /* Pad to min_io_size */
- if (len > endpt) {
- int pad_len = len - ALIGN(endpt, 8);
-
- if (pad_len > 0) {
- void *buf = sleb->buf + len - pad_len;
-
- ubifs_pad(c, buf, pad_len);
- }
- }
- err = ubifs_leb_change(c, lnum, sleb->buf, len);
- if (err)
- return err;
- }
-#endif
}
return 0;
}
@@ -907,331 +804,10 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
return ubifs_recover_leb(c, lnum, offs, sbuf, -1);
}
-/**
- * recover_head - recover a head.
- * @c: UBIFS file-system description object
- * @lnum: LEB number of head to recover
- * @offs: offset of head to recover
- * @sbuf: LEB-sized buffer to use
- *
- * This function ensures that there is no data on the flash at a head location.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
-{
- int len = c->max_write_size, err;
-
- if (offs + len > c->leb_size)
- len = c->leb_size - offs;
-
- if (!len)
- return 0;
-
- /* Read at the head location and check it is empty flash */
- err = ubifs_leb_read(c, lnum, sbuf, offs, len, 1);
- if (err || !is_empty(sbuf, len)) {
- dbg_rcvry("cleaning head at %d:%d", lnum, offs);
- if (offs == 0)
- return ubifs_leb_unmap(c, lnum);
- err = ubifs_leb_read(c, lnum, sbuf, 0, offs, 1);
- if (err)
- return err;
- return ubifs_leb_change(c, lnum, sbuf, offs);
- }
-
- return 0;
-}
-
-/**
- * ubifs_recover_inl_heads - recover index and LPT heads.
- * @c: UBIFS file-system description object
- * @sbuf: LEB-sized buffer to use
- *
- * This function ensures that there is no data on the flash at the index and
- * LPT head locations.
- *
- * This deals with the recovery of a half-completed journal commit. UBIFS is
- * careful never to overwrite the last version of the index or the LPT. Because
- * the index and LPT are wandering trees, data from a half-completed commit will
- * not be referenced anywhere in UBIFS. The data will be either in LEBs that are
- * assumed to be empty and will be unmapped anyway before use, or in the index
- * and LPT heads.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
-{
- int err;
-
- ubifs_assert(!c->ro_mount || c->remounting_rw);
-
- dbg_rcvry("checking index head at %d:%d", c->ihead_lnum, c->ihead_offs);
- err = recover_head(c, c->ihead_lnum, c->ihead_offs, sbuf);
- if (err)
- return err;
-
- dbg_rcvry("checking LPT head at %d:%d", c->nhead_lnum, c->nhead_offs);
-
- return recover_head(c, c->nhead_lnum, c->nhead_offs, sbuf);
-}
-
-/**
- * clean_an_unclean_leb - read and write a LEB to remove corruption.
- * @c: UBIFS file-system description object
- * @ucleb: unclean LEB information
- * @sbuf: LEB-sized buffer to use
- *
- * This function reads a LEB up to a point pre-determined by the mount recovery,
- * checks the nodes, and writes the result back to the flash, thereby cleaning
- * off any following corruption, or non-fatal ECC errors.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-static int clean_an_unclean_leb(struct ubifs_info *c,
- struct ubifs_unclean_leb *ucleb, void *sbuf)
-{
- int err, lnum = ucleb->lnum, offs = 0, len = ucleb->endpt, quiet = 1;
- void *buf = sbuf;
-
- dbg_rcvry("LEB %d len %d", lnum, len);
-
- if (len == 0) {
- /* Nothing to read, just unmap it */
- return ubifs_leb_unmap(c, lnum);
- }
-
- err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
- if (err && err != -EBADMSG)
- return err;
-
- while (len >= 8) {
- int ret;
-
- cond_resched();
-
- /* Scan quietly until there is an error */
- ret = ubifs_scan_a_node(c, buf, len, lnum, offs, quiet);
-
- if (ret == SCANNED_A_NODE) {
- /* A valid node, and not a padding node */
- struct ubifs_ch *ch = buf;
- int node_len;
-
- node_len = ALIGN(le32_to_cpu(ch->len), 8);
- offs += node_len;
- buf += node_len;
- len -= node_len;
- continue;
- }
-
- if (ret > 0) {
- /* Padding bytes or a valid padding node */
- offs += ret;
- buf += ret;
- len -= ret;
- continue;
- }
-
- if (ret == SCANNED_EMPTY_SPACE) {
- ubifs_err(c, "unexpected empty space at %d:%d",
- lnum, offs);
- return -EUCLEAN;
- }
-
- if (quiet) {
- /* Redo the last scan but noisily */
- quiet = 0;
- continue;
- }
-
- ubifs_scanned_corruption(c, lnum, offs, buf);
- return -EUCLEAN;
- }
-
- /* Pad to min_io_size */
- len = ALIGN(ucleb->endpt, c->min_io_size);
- if (len > ucleb->endpt) {
- int pad_len = len - ALIGN(ucleb->endpt, 8);
-
- if (pad_len > 0) {
- buf = c->sbuf + len - pad_len;
- ubifs_pad(c, buf, pad_len);
- }
- }
-
- /* Write back the LEB atomically */
- err = ubifs_leb_change(c, lnum, sbuf, len);
- if (err)
- return err;
-
- dbg_rcvry("cleaned LEB %d", lnum);
-
- return 0;
-}
-
-/**
- * ubifs_clean_lebs - clean LEBs recovered during read-only mount.
- * @c: UBIFS file-system description object
- * @sbuf: LEB-sized buffer to use
- *
- * This function cleans a LEB identified during recovery that needs to be
- * written but was not because UBIFS was mounted read-only. This happens when
- * remounting to read-write mode.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf)
-{
- dbg_rcvry("recovery");
- while (!list_empty(&c->unclean_leb_list)) {
- struct ubifs_unclean_leb *ucleb;
- int err;
-
- ucleb = list_entry(c->unclean_leb_list.next,
- struct ubifs_unclean_leb, list);
- err = clean_an_unclean_leb(c, ucleb, sbuf);
- if (err)
- return err;
- list_del(&ucleb->list);
- kfree(ucleb);
- }
- return 0;
-}
-
-#ifndef __BAREBOX__
-/**
- * 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) {
- ubifs_err(c, "could not find an empty LEB");
- ubifs_dump_lprops(c);
- ubifs_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
- *
- * Out-of-place garbage collection requires always one empty LEB with which to
- * start garbage collection. The LEB number is recorded in c->gc_lnum and is
- * written to the master node on unmounting. In the case of an unclean unmount
- * the value of gc_lnum recorded in the master node is out of date and cannot
- * be used. Instead, recovery must allocate an empty LEB for this purpose.
- * However, there may not be enough empty space, in which case it must be
- * possible to GC the dirtiest LEB into the GC head LEB.
- *
- * This function also runs the commit which causes the TNC updates from
- * size-recovery and orphans to be written to the flash. That is important to
- * ensure correct replay order for subsequent mounts.
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_rcvry_gc_commit(struct ubifs_info *c)
-{
- struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf;
- struct ubifs_lprops lp;
- int err;
-
- dbg_rcvry("GC head LEB %d, offs %d", wbuf->lnum, wbuf->offs);
-
- c->gc_lnum = -1;
- if (wbuf->lnum == -1 || wbuf->offs == c->leb_size)
- return grab_empty_leb(c);
-
- err = ubifs_find_dirty_leb(c, &lp, wbuf->offs, 2);
- if (err) {
- if (err != -ENOSPC)
- return err;
-
- dbg_rcvry("could not find a dirty LEB");
- return grab_empty_leb(c);
- }
-
- ubifs_assert(!(lp.flags & LPROPS_INDEX));
- ubifs_assert(lp.free + lp.dirty >= wbuf->offs);
-
- /*
- * We run the commit before garbage collection otherwise subsequent
- * mounts will see the GC and orphan deletion in a different order.
- */
- dbg_rcvry("committing");
- err = ubifs_run_commit(c);
- if (err)
- return err;
-
- dbg_rcvry("GC'ing LEB %d", lp.lnum);
- mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead);
- err = ubifs_garbage_collect_leb(c, &lp);
- if (err >= 0) {
- int err2 = ubifs_wbuf_sync_nolock(wbuf);
-
- if (err2)
- err = err2;
- }
- mutex_unlock(&wbuf->io_mutex);
- if (err < 0) {
- ubifs_err(c, "GC failed, error %d", err);
- if (err == -EAGAIN)
- err = -EINVAL;
- return err;
- }
-
- ubifs_assert(err == LEB_RETAINED);
- if (err != LEB_RETAINED)
- return -EINVAL;
-
- err = ubifs_leb_unmap(c, c->gc_lnum);
- if (err)
- return err;
-
- dbg_rcvry("allocated LEB %d for GC", lp.lnum);
- return 0;
-}
-#else
int ubifs_rcvry_gc_commit(struct ubifs_info *c)
{
return 0;
}
-#endif
/**
* struct size_entry - inode size information for recovery.
@@ -1411,63 +987,6 @@ int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
return 0;
}
-#ifndef __BAREBOX__
-/**
- * fix_size_in_place - fix inode size in place on flash.
- * @c: UBIFS file-system description object
- * @e: inode size information for recovery
- */
-static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
-{
- struct ubifs_ino_node *ino = c->sbuf;
- unsigned char *p;
- union ubifs_key key;
- int err, lnum, offs, len;
- loff_t i_size;
- uint32_t crc;
-
- /* Locate the inode node LEB number and offset */
- ino_key_init(c, &key, e->inum);
- err = ubifs_tnc_locate(c, &key, ino, &lnum, &offs);
- if (err)
- goto out;
- /*
- * If the size recorded on the inode node is greater than the size that
- * was calculated from nodes in the journal then don't change the inode.
- */
- i_size = le64_to_cpu(ino->size);
- if (i_size >= e->d_size)
- return 0;
- /* Read the LEB */
- err = ubifs_leb_read(c, lnum, c->sbuf, 0, c->leb_size, 1);
- if (err)
- goto out;
- /* Change the size field and recalculate the CRC */
- ino = c->sbuf + offs;
- ino->size = cpu_to_le64(e->d_size);
- len = le32_to_cpu(ino->ch.len);
- crc = crc32(UBIFS_CRC32_INIT, (void *)ino + 8, len - 8);
- ino->ch.crc = cpu_to_le32(crc);
- /* Work out where data in the LEB ends and free space begins */
- p = c->sbuf;
- len = c->leb_size - 1;
- while (p[len] == 0xff)
- len -= 1;
- len = ALIGN(len + 1, c->min_io_size);
- /* Atomically write the fixed LEB back again */
- err = ubifs_leb_change(c, lnum, c->sbuf, len);
- if (err)
- goto out;
- dbg_rcvry("inode %lu at %d:%d size %lld -> %lld",
- (unsigned long)e->inum, lnum, offs, i_size, e->d_size);
- return 0;
-
-out:
- ubifs_warn(c, "inode %lu failed to fix size %lld -> %lld error %d",
- (unsigned long)e->inum, e->i_size, e->d_size, err);
- return err;
-}
-#endif
/**
* ubifs_recover_size - recover inode size.
@@ -1534,15 +1053,6 @@ int ubifs_recover_size(struct ubifs_info *c)
continue;
}
iput(inode);
-#ifndef __BAREBOX__
- } else {
- /* Fix the size in place */
- err = fix_size_in_place(c, e);
- if (err)
- return err;
- if (e->inode)
- iput(e->inode);
-#endif
}
}
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 08b11352fa..19d0bf1f73 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -21,9 +21,7 @@
* larger is the journal, the more memory its index may consume.
*/
-#ifdef __BAREBOX__
#include <linux/err.h>
-#endif
#include "ubifs.h"
#include <linux/bug.h>
#include <linux/list_sort.h>
@@ -78,103 +76,6 @@ struct bud_entry {
int dirty;
};
-/**
- * set_bud_lprops - set free and dirty space used by a bud.
- * @c: UBIFS file-system description object
- * @b: bud entry which describes the bud
- *
- * This function makes sure the LEB properties of bud @b are set correctly
- * after the replay. Returns zero in case of success and a negative error code
- * in case of failure.
- */
-static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
-{
- const struct ubifs_lprops *lp;
- int err = 0, dirty;
-
- ubifs_get_lprops(c);
-
- lp = ubifs_lpt_lookup_dirty(c, b->bud->lnum);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- goto out;
- }
-
- dirty = lp->dirty;
- if (b->bud->start == 0 && (lp->free != c->leb_size || lp->dirty != 0)) {
- /*
- * The LEB was added to the journal with a starting offset of
- * zero which means the LEB must have been empty. The LEB
- * property values should be @lp->free == @c->leb_size and
- * @lp->dirty == 0, but that is not the case. The reason is that
- * the LEB had been garbage collected before it became the bud,
- * and there was not commit inbetween. The garbage collector
- * resets the free and dirty space without recording it
- * anywhere except lprops, so if there was no commit then
- * lprops does not have that information.
- *
- * We do not need to adjust free space because the scan has told
- * us the exact value which is recorded in the replay entry as
- * @b->free.
- *
- * However we do need to subtract from the dirty space the
- * amount of space that the garbage collector reclaimed, which
- * is the whole LEB minus the amount of space that was free.
- */
- dbg_mnt("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
- lp->free, lp->dirty);
- dbg_gc("bud LEB %d was GC'd (%d free, %d dirty)", b->bud->lnum,
- lp->free, lp->dirty);
- dirty -= c->leb_size - lp->free;
- /*
- * If the replay order was perfect the dirty space would now be
- * zero. The order is not perfect because the journal heads
- * race with each other. This is not a problem but is does mean
- * that the dirty space may temporarily exceed c->leb_size
- * during the replay.
- */
- if (dirty != 0)
- dbg_mnt("LEB %d lp: %d free %d dirty replay: %d free %d dirty",
- b->bud->lnum, lp->free, lp->dirty, b->free,
- b->dirty);
- }
- lp = ubifs_change_lp(c, lp, b->free, dirty + b->dirty,
- lp->flags | LPROPS_TAKEN, 0);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- goto out;
- }
-
- /* Make sure the journal head points to the latest bud */
- err = ubifs_wbuf_seek_nolock(&c->jheads[b->bud->jhead].wbuf,
- b->bud->lnum, c->leb_size - b->free);
-
-out:
- ubifs_release_lprops(c);
- return err;
-}
-
-/**
- * set_buds_lprops - set free and dirty space for all replayed buds.
- * @c: UBIFS file-system description object
- *
- * This function sets LEB properties for all replayed buds. Returns zero in
- * case of success and a negative error code in case of failure.
- */
-static int set_buds_lprops(struct ubifs_info *c)
-{
- struct bud_entry *b;
- int err;
-
- list_for_each_entry(b, &c->replay_buds, list) {
- err = set_bud_lprops(c, b);
- if (err)
- return err;
- }
-
- return 0;
-}
-
/**
* trun_remove_range - apply a replay entry for a truncation to the TNC.
* @c: UBIFS file-system description object
@@ -955,41 +856,6 @@ out_dump:
return -EINVAL;
}
-/**
- * take_ihead - update the status of the index head in lprops to 'taken'.
- * @c: UBIFS file-system description object
- *
- * This function returns the amount of free space in the index head LEB or a
- * negative error code.
- */
-static int take_ihead(struct ubifs_info *c)
-{
- const struct ubifs_lprops *lp;
- int err, free;
-
- ubifs_get_lprops(c);
-
- lp = ubifs_lpt_lookup_dirty(c, c->ihead_lnum);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- goto out;
- }
-
- free = lp->free;
-
- lp = ubifs_change_lp(c, lp, LPROPS_NC, LPROPS_NC,
- lp->flags | LPROPS_TAKEN, 0);
- if (IS_ERR(lp)) {
- err = PTR_ERR(lp);
- goto out;
- }
-
- err = free;
-out:
- ubifs_release_lprops(c);
- return err;
-}
-
/**
* ubifs_replay_journal - replay journal.
* @c: UBIFS file-system description object
@@ -1000,21 +866,10 @@ out:
*/
int ubifs_replay_journal(struct ubifs_info *c)
{
- int err, lnum, free;
+ int err, lnum;
BUILD_BUG_ON(UBIFS_TRUN_KEY > 5);
- /* Update the status of the index head in lprops to 'taken' */
- free = take_ihead(c);
- if (free < 0)
- return free; /* Error code */
-
- if (c->ihead_offs != c->leb_size - free) {
- ubifs_err(c, "bad index head LEB %d:%d", c->ihead_lnum,
- c->ihead_offs);
- return -EINVAL;
- }
-
dbg_mnt("start replaying the journal");
c->replaying = 1;
lnum = c->ltail_lnum = c->lhead_lnum;
@@ -1050,10 +905,6 @@ int ubifs_replay_journal(struct ubifs_info *c)
if (err)
goto out;
- err = set_buds_lprops(c);
- if (err)
- goto out;
-
/*
* UBIFS budgeting calculations use @c->bi.uncommitted_idx variable
* to roughly estimate index growth. Things like @c->bi.min_idx_lebs
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index 05655841e4..f7051c96d2 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -16,15 +16,9 @@
*/
#include "ubifs.h"
-#ifndef __BAREBOX__
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/math64.h>
-#else
#include <linux/err.h>
#include <linux/stat.h>
-#endif
/*
* Default journal size in logical eraseblocks as a percent of total
@@ -58,283 +52,6 @@
/* Default time granularity in nanoseconds */
#define DEFAULT_TIME_GRAN 1000000000
-#ifndef __BAREBOX__
-/**
- * create_default_filesystem - format empty UBI volume.
- * @c: UBIFS file-system description object
- *
- * This function creates default empty file-system. Returns zero in case of
- * success and a negative error code in case of failure.
- */
-static int create_default_filesystem(struct ubifs_info *c)
-{
- struct ubifs_sb_node *sup;
- struct ubifs_mst_node *mst;
- struct ubifs_idx_node *idx;
- struct ubifs_branch *br;
- struct ubifs_ino_node *ino;
- 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 min_leb_cnt = UBIFS_MIN_LEB_CNT;
- long long tmp64, main_bytes;
- __le64 tmp_le64;
-
- /* Some functions called from here depend on the @c->key_len filed */
- c->key_len = UBIFS_SK_LEN;
-
- /*
- * First of all, we have to calculate default file-system geometry -
- * log size, journal size, etc.
- */
- if (c->leb_cnt < 0x7FFFFFFF / DEFAULT_JNL_PERCENT)
- /* We can first multiply then divide and have no overflow */
- jnl_lebs = c->leb_cnt * DEFAULT_JNL_PERCENT / 100;
- else
- jnl_lebs = (c->leb_cnt / 100) * DEFAULT_JNL_PERCENT;
-
- if (jnl_lebs < UBIFS_MIN_JNL_LEBS)
- jnl_lebs = UBIFS_MIN_JNL_LEBS;
- if (jnl_lebs * c->leb_size > DEFAULT_MAX_JNL)
- jnl_lebs = DEFAULT_MAX_JNL / c->leb_size;
-
- /*
- * The log should be large enough to fit reference nodes for all bud
- * LEBs. Because buds do not have to start from the beginning of LEBs
- * (half of the LEB may contain committed data), the log should
- * generally be larger, make it twice as large.
- */
- tmp = 2 * (c->ref_node_alsz * jnl_lebs) + c->leb_size - 1;
- log_lebs = tmp / c->leb_size;
- /* Plus one LEB reserved for commit */
- log_lebs += 1;
- if (c->leb_cnt - min_leb_cnt > 8) {
- /* And some extra space to allow writes while committing */
- log_lebs += 1;
- min_leb_cnt += 1;
- }
-
- max_buds = jnl_lebs - log_lebs;
- if (max_buds < UBIFS_MIN_BUD_LEBS)
- max_buds = UBIFS_MIN_BUD_LEBS;
-
- /*
- * Orphan nodes are stored in a separate area. One node can store a lot
- * of orphan inode numbers, but when new orphan comes we just add a new
- * orphan node. At some point the nodes are consolidated into one
- * orphan node.
- */
- orph_lebs = UBIFS_MIN_ORPH_LEBS;
- if (c->leb_cnt - min_leb_cnt > 1)
- /*
- * For debugging purposes it is better to have at least 2
- * orphan LEBs, because the orphan subsystem would need to do
- * consolidations and would be stressed more.
- */
- orph_lebs += 1;
-
- main_lebs = c->leb_cnt - UBIFS_SB_LEBS - UBIFS_MST_LEBS - log_lebs;
- main_lebs -= orph_lebs;
-
- lpt_first = UBIFS_LOG_LNUM + log_lebs;
- c->lsave_cnt = DEFAULT_LSAVE_CNT;
- c->max_leb_cnt = c->leb_cnt;
- err = ubifs_create_dflt_lpt(c, &main_lebs, lpt_first, &lpt_lebs,
- &big_lpt);
- if (err)
- return err;
-
- dbg_gen("LEB Properties Tree created (LEBs %d-%d)", lpt_first,
- lpt_first + lpt_lebs - 1);
-
- main_first = c->leb_cnt - main_lebs;
-
- /* Create default superblock */
- tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
- sup = kzalloc(tmp, GFP_KERNEL);
- if (!sup)
- return -ENOMEM;
-
- tmp64 = (long long)max_buds * c->leb_size;
- if (big_lpt)
- sup_flags |= UBIFS_FLG_BIGLPT;
-
- sup->ch.node_type = UBIFS_SB_NODE;
- sup->key_hash = UBIFS_KEY_HASH_R5;
- sup->flags = cpu_to_le32(sup_flags);
- sup->min_io_size = cpu_to_le32(c->min_io_size);
- sup->leb_size = cpu_to_le32(c->leb_size);
- sup->leb_cnt = cpu_to_le32(c->leb_cnt);
- sup->max_leb_cnt = cpu_to_le32(c->max_leb_cnt);
- sup->max_bud_bytes = cpu_to_le64(tmp64);
- sup->log_lebs = cpu_to_le32(log_lebs);
- sup->lpt_lebs = cpu_to_le32(lpt_lebs);
- sup->orph_lebs = cpu_to_le32(orph_lebs);
- sup->jhead_cnt = cpu_to_le32(DEFAULT_JHEADS_CNT);
- sup->fanout = cpu_to_le32(DEFAULT_FANOUT);
- sup->lsave_cnt = cpu_to_le32(c->lsave_cnt);
- sup->fmt_version = cpu_to_le32(UBIFS_FORMAT_VERSION);
- sup->time_gran = cpu_to_le32(DEFAULT_TIME_GRAN);
- if (c->mount_opts.override_compr)
- sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
- else
- sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
-
- generate_random_uuid(sup->uuid);
-
- main_bytes = (long long)main_lebs * c->leb_size;
- tmp64 = div_u64(main_bytes * DEFAULT_RP_PERCENT, 100);
- if (tmp64 > DEFAULT_MAX_RP_SIZE)
- tmp64 = DEFAULT_MAX_RP_SIZE;
- sup->rp_size = cpu_to_le64(tmp64);
- sup->ro_compat_version = cpu_to_le32(UBIFS_RO_COMPAT_VERSION);
-
- err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0);
- kfree(sup);
- if (err)
- return err;
-
- dbg_gen("default superblock created at LEB 0:0");
-
- /* Create default master node */
- mst = kzalloc(c->mst_node_alsz, GFP_KERNEL);
- if (!mst)
- return -ENOMEM;
-
- mst->ch.node_type = UBIFS_MST_NODE;
- mst->log_lnum = cpu_to_le32(UBIFS_LOG_LNUM);
- mst->highest_inum = cpu_to_le64(UBIFS_FIRST_INO);
- mst->cmt_no = 0;
- mst->root_lnum = cpu_to_le32(main_first + DEFAULT_IDX_LEB);
- mst->root_offs = 0;
- tmp = ubifs_idx_node_sz(c, 1);
- mst->root_len = cpu_to_le32(tmp);
- mst->gc_lnum = cpu_to_le32(main_first + DEFAULT_GC_LEB);
- mst->ihead_lnum = cpu_to_le32(main_first + DEFAULT_IDX_LEB);
- mst->ihead_offs = cpu_to_le32(ALIGN(tmp, c->min_io_size));
- mst->index_size = cpu_to_le64(ALIGN(tmp, 8));
- mst->lpt_lnum = cpu_to_le32(c->lpt_lnum);
- mst->lpt_offs = cpu_to_le32(c->lpt_offs);
- mst->nhead_lnum = cpu_to_le32(c->nhead_lnum);
- mst->nhead_offs = cpu_to_le32(c->nhead_offs);
- mst->ltab_lnum = cpu_to_le32(c->ltab_lnum);
- mst->ltab_offs = cpu_to_le32(c->ltab_offs);
- mst->lsave_lnum = cpu_to_le32(c->lsave_lnum);
- mst->lsave_offs = cpu_to_le32(c->lsave_offs);
- mst->lscan_lnum = cpu_to_le32(main_first);
- mst->empty_lebs = cpu_to_le32(main_lebs - 2);
- mst->idx_lebs = cpu_to_le32(1);
- mst->leb_cnt = cpu_to_le32(c->leb_cnt);
-
- /* Calculate lprops statistics */
- tmp64 = main_bytes;
- tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size);
- tmp64 -= ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size);
- mst->total_free = cpu_to_le64(tmp64);
-
- tmp64 = ALIGN(ubifs_idx_node_sz(c, 1), c->min_io_size);
- ino_waste = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size) -
- UBIFS_INO_NODE_SZ;
- tmp64 += ino_waste;
- tmp64 -= ALIGN(ubifs_idx_node_sz(c, 1), 8);
- mst->total_dirty = cpu_to_le64(tmp64);
-
- /* The indexing LEB does not contribute to dark space */
- tmp64 = ((long long)(c->main_lebs - 1) * c->dark_wm);
- mst->total_dark = cpu_to_le64(tmp64);
-
- mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ);
-
- err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0);
- if (err) {
- kfree(mst);
- return err;
- }
- err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1,
- 0);
- kfree(mst);
- if (err)
- return err;
-
- dbg_gen("default master node created at LEB %d:0", UBIFS_MST_LNUM);
-
- /* Create the root indexing node */
- tmp = ubifs_idx_node_sz(c, 1);
- idx = kzalloc(ALIGN(tmp, c->min_io_size), GFP_KERNEL);
- if (!idx)
- return -ENOMEM;
-
- c->key_fmt = UBIFS_SIMPLE_KEY_FMT;
- c->key_hash = key_r5_hash;
-
- idx->ch.node_type = UBIFS_IDX_NODE;
- idx->child_cnt = cpu_to_le16(1);
- ino_key_init(c, &key, UBIFS_ROOT_INO);
- br = ubifs_idx_branch(c, idx, 0);
- key_write_idx(c, &key, &br->key);
- br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB);
- br->len = cpu_to_le32(UBIFS_INO_NODE_SZ);
- err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0);
- kfree(idx);
- if (err)
- return err;
-
- dbg_gen("default root indexing node created LEB %d:0",
- main_first + DEFAULT_IDX_LEB);
-
- /* Create default root inode */
- tmp = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size);
- ino = kzalloc(tmp, GFP_KERNEL);
- if (!ino)
- return -ENOMEM;
-
- ino_key_init_flash(c, &ino->key, UBIFS_ROOT_INO);
- ino->ch.node_type = UBIFS_INO_NODE;
- ino->creat_sqnum = cpu_to_le64(++c->max_sqnum);
- ino->nlink = cpu_to_le32(2);
- tmp_le64 = cpu_to_le64(CURRENT_TIME_SEC.tv_sec);
- ino->atime_sec = tmp_le64;
- ino->ctime_sec = tmp_le64;
- ino->mtime_sec = tmp_le64;
- ino->atime_nsec = 0;
- ino->ctime_nsec = 0;
- ino->mtime_nsec = 0;
- ino->mode = cpu_to_le32(S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO);
- ino->size = cpu_to_le64(UBIFS_INO_NODE_SZ);
-
- /* Set compression enabled by default */
- ino->flags = cpu_to_le32(UBIFS_COMPR_FL);
-
- err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ,
- main_first + DEFAULT_DATA_LEB, 0);
- kfree(ino);
- if (err)
- return err;
-
- dbg_gen("root inode created at LEB %d:0",
- main_first + DEFAULT_DATA_LEB);
-
- /*
- * The first node in the log has to be the commit start node. This is
- * always the case during normal file-system operation. Write a fake
- * commit start node to the log.
- */
- tmp = ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size);
- cs = kzalloc(tmp, GFP_KERNEL);
- if (!cs)
- return -ENOMEM;
-
- cs->ch.node_type = UBIFS_CS_NODE;
- err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM, 0);
- kfree(cs);
- if (err)
- return err;
-
- ubifs_msg(c, "default file-system created");
- return 0;
-}
-#endif
/**
* validate_sb - validate superblock node.
@@ -497,21 +214,6 @@ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
return sup;
}
-/**
- * ubifs_write_sb_node - write superblock node.
- * @c: UBIFS file-system description object
- * @sup: superblock node read with 'ubifs_read_sb_node()'
- *
- * This function returns %0 on success and a negative error code on failure.
- */
-int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup)
-{
- int len = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size);
-
- ubifs_prepare_node(c, sup, UBIFS_SB_NODE_SZ, 1);
- return ubifs_leb_change(c, UBIFS_SB_LNUM, sup, len);
-}
-
/**
* ubifs_read_superblock - read superblock.
* @c: UBIFS file-system description object
@@ -526,14 +228,8 @@ int ubifs_read_superblock(struct ubifs_info *c)
struct ubifs_sb_node *sup;
if (c->empty) {
-#ifndef __BAREBOX__
- err = create_default_filesystem(c);
- if (err)
- return err;
-#else
printf("No UBIFS filesystem found!\n");
return -1;
-#endif
}
sup = ubifs_read_sb_node(c);
@@ -612,13 +308,8 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->fanout = le32_to_cpu(sup->fanout);
c->lsave_cnt = le32_to_cpu(sup->lsave_cnt);
c->rp_size = le64_to_cpu(sup->rp_size);
-#ifndef __BAREBOX__
- c->rp_uid = make_kuid(&init_user_ns, le32_to_cpu(sup->rp_uid));
- c->rp_gid = make_kgid(&init_user_ns, le32_to_cpu(sup->rp_gid));
-#else
c->rp_uid = le32_to_cpu(sup->rp_uid);
c->rp_gid = le32_to_cpu(sup->rp_gid);
-#endif
sup_flags = le32_to_cpu(sup->flags);
if (!c->mount_opts.override_compr)
c->default_compr = le16_to_cpu(sup->default_compr);
@@ -635,17 +326,6 @@ int ubifs_read_superblock(struct ubifs_info *c)
if (c->ro_mount)
dbg_mnt("Auto resizing (ro) from %d LEBs to %d LEBs",
c->old_leb_cnt, c->leb_cnt);
-#ifndef __BAREBOX__
- else {
- dbg_mnt("Auto resizing (sb) from %d LEBs to %d LEBs",
- c->old_leb_cnt, c->leb_cnt);
- sup->leb_cnt = cpu_to_le32(c->leb_cnt);
- err = ubifs_write_sb_node(c, sup);
- if (err)
- goto out;
- c->old_leb_cnt = c->leb_cnt;
- }
-#endif
}
c->log_bytes = (long long)c->log_lebs * c->leb_size;
@@ -663,156 +343,3 @@ out:
kfree(sup);
return err;
}
-
-/**
- * fixup_leb - fixup/unmap an LEB containing free space.
- * @c: UBIFS file-system description object
- * @lnum: the LEB number to fix up
- * @len: number of used bytes in LEB (starting at offset 0)
- *
- * This function reads the contents of the given LEB number @lnum, then fixes
- * it up, so that empty min. I/O units in the end of LEB are actually erased on
- * flash (rather than being just all-0xff real data). If the LEB is completely
- * empty, it is simply unmapped.
- */
-static int fixup_leb(struct ubifs_info *c, int lnum, int len)
-{
- int err;
-
- ubifs_assert(len >= 0);
- ubifs_assert(len % c->min_io_size == 0);
- ubifs_assert(len < c->leb_size);
-
- if (len == 0) {
- dbg_mnt("unmap empty LEB %d", lnum);
- return ubifs_leb_unmap(c, lnum);
- }
-
- dbg_mnt("fixup LEB %d, data len %d", lnum, len);
- err = ubifs_leb_read(c, lnum, c->sbuf, 0, len, 1);
- if (err)
- return err;
-
- return ubifs_leb_change(c, lnum, c->sbuf, len);
-}
-
-/**
- * fixup_free_space - find & remap all LEBs containing free space.
- * @c: UBIFS file-system description object
- *
- * This function walks through all LEBs in the filesystem and fiexes up those
- * containing free/empty space.
- */
-static int fixup_free_space(struct ubifs_info *c)
-{
- int lnum, err = 0;
- struct ubifs_lprops *lprops;
-
- ubifs_get_lprops(c);
-
- /* Fixup LEBs in the master area */
- for (lnum = UBIFS_MST_LNUM; lnum < UBIFS_LOG_LNUM; lnum++) {
- err = fixup_leb(c, lnum, c->mst_offs + c->mst_node_alsz);
- if (err)
- goto out;
- }
-
- /* Unmap unused log LEBs */
- lnum = ubifs_next_log_lnum(c, c->lhead_lnum);
- while (lnum != c->ltail_lnum) {
- err = fixup_leb(c, lnum, 0);
- if (err)
- goto out;
- lnum = ubifs_next_log_lnum(c, lnum);
- }
-
- /*
- * Fixup the log head which contains the only a CS node at the
- * beginning.
- */
- err = fixup_leb(c, c->lhead_lnum,
- ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size));
- if (err)
- goto out;
-
- /* Fixup LEBs in the LPT area */
- for (lnum = c->lpt_first; lnum <= c->lpt_last; lnum++) {
- int free = c->ltab[lnum - c->lpt_first].free;
-
- if (free > 0) {
- err = fixup_leb(c, lnum, c->leb_size - free);
- if (err)
- goto out;
- }
- }
-
- /* Unmap LEBs in the orphans area */
- for (lnum = c->orph_first; lnum <= c->orph_last; lnum++) {
- err = fixup_leb(c, lnum, 0);
- if (err)
- goto out;
- }
-
- /* Fixup LEBs in the main area */
- for (lnum = c->main_first; lnum < c->leb_cnt; lnum++) {
- lprops = ubifs_lpt_lookup(c, lnum);
- if (IS_ERR(lprops)) {
- err = PTR_ERR(lprops);
- goto out;
- }
-
- if (lprops->free > 0) {
- err = fixup_leb(c, lnum, c->leb_size - lprops->free);
- if (err)
- goto out;
- }
- }
-
-out:
- ubifs_release_lprops(c);
- return err;
-}
-
-/**
- * ubifs_fixup_free_space - find & fix all LEBs with free space.
- * @c: UBIFS file-system description object
- *
- * This function fixes up LEBs containing free space on first mount, if the
- * appropriate flag was set when the FS was created. Each LEB with one or more
- * empty min. I/O unit (i.e. free-space-count > 0) is re-written, to make sure
- * the free space is actually erased. E.g., this is necessary for some NAND
- * chips, since the free space may have been programmed like real "0xff" data
- * (generating a non-0xff ECC), causing future writes to the not-really-erased
- * NAND pages to behave badly. After the space is fixed up, the superblock flag
- * is cleared, so that this is skipped for all future mounts.
- */
-int ubifs_fixup_free_space(struct ubifs_info *c)
-{
- int err;
- struct ubifs_sb_node *sup;
-
- ubifs_assert(c->space_fixup);
- ubifs_assert(!c->ro_mount);
-
- ubifs_msg(c, "start fixing up free space");
-
- err = fixup_free_space(c);
- if (err)
- return err;
-
- sup = ubifs_read_sb_node(c);
- if (IS_ERR(sup))
- return PTR_ERR(sup);
-
- /* Free-space fixup is no longer required */
- c->space_fixup = 0;
- sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP);
-
- err = ubifs_write_sb_node(c, sup);
- kfree(sup);
- if (err)
- return err;
-
- ubifs_msg(c, "free space fixup complete");
- return err;
-}
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
index 685670cfcb..1d4bdf603b 100644
--- a/fs/ubifs/scan.c
+++ b/fs/ubifs/scan.c
@@ -16,9 +16,7 @@
* debugging functions.
*/
-#ifdef __BAREBOX__
#include <linux/err.h>
-#endif
#include "ubifs.h"
/**
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index 24b2c87248..f5ddfc667b 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -15,18 +15,6 @@
* corresponding subsystems, but most of it is here.
*/
-#ifndef __BAREBOX__
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/ctype.h>
-#include <linux/kthread.h>
-#include <linux/parser.h>
-#include <linux/seq_file.h>
-#include <linux/mount.h>
-#include <linux/math64.h>
-#include <linux/writeback.h>
-#else
#include <common.h>
#include <init.h>
@@ -39,22 +27,6 @@
#include "ubifs.h"
#include <mtd/ubi-user.h>
-struct dentry;
-struct file;
-struct iattr;
-struct kstat;
-struct vfsmount;
-
-#define INODE_LOCKED_MAX 64
-
-struct super_block *ubifs_sb;
-LIST_HEAD(super_blocks);
-
-int set_anon_super(struct super_block *s, void *data)
-{
- return 0;
-}
-
int ubifs_iput(struct inode *inode)
{
list_del_init(&inode->i_sb_list);
@@ -78,7 +50,6 @@ void unlock_new_inode(struct inode *inode)
{
return;
}
-#endif
/*
* Maximum amount of memory we may 'kmalloc()' without worrying that we are
@@ -89,14 +60,6 @@ void unlock_new_inode(struct inode *inode)
/* Slab cache for UBIFS inodes */
struct kmem_cache *ubifs_inode_slab;
-#ifndef __BAREBOX__
-/* UBIFS TNC shrinker description */
-static struct shrinker ubifs_shrinker_info = {
- .scan_objects = ubifs_shrink_scan,
- .count_objects = ubifs_shrink_count,
- .seeks = DEFAULT_SEEKS,
-};
-#endif
/**
* validate_inode - validate inode.
@@ -249,9 +212,6 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
}
kfree(ino);
-#ifndef __BAREBOX__
- ubifs_set_inode_flags(inode);
-#endif
unlock_new_inode(inode);
return inode;
@@ -291,203 +251,6 @@ static void ubifs_destroy_inode(struct inode *inode)
kfree(ui);
}
-#ifndef __BAREBOX__
-/*
- * Note, Linux write-back code calls this without 'i_mutex'.
- */
-static int ubifs_write_inode(struct inode *inode, struct writeback_control *wbc)
-{
- int err = 0;
- struct ubifs_info *c = inode->i_sb->s_fs_info;
- struct ubifs_inode *ui = ubifs_inode(inode);
-
- ubifs_assert(!ui->xattr);
- if (is_bad_inode(inode))
- return 0;
-
- mutex_lock(&ui->ui_mutex);
- /*
- * Due to races between write-back forced by budgeting
- * (see 'sync_some_inodes()') and background write-back, the inode may
- * have already been synchronized, do not do this again. This might
- * also happen if it was synchronized in an VFS operation, e.g.
- * 'ubifs_link()'.
- */
- if (!ui->dirty) {
- mutex_unlock(&ui->ui_mutex);
- return 0;
- }
-
- /*
- * As an optimization, do not write orphan inodes to the media just
- * because this is not needed.
- */
- dbg_gen("inode %lu, mode %#x, nlink %u",
- inode->i_ino, (int)inode->i_mode, inode->i_nlink);
- if (inode->i_nlink) {
- err = ubifs_jnl_write_inode(c, inode);
- if (err)
- ubifs_err(c, "can't write inode %lu, error %d",
- inode->i_ino, err);
- else
- err = dbg_check_inode_size(c, inode, ui->ui_size);
- }
-
- ui->dirty = 0;
- mutex_unlock(&ui->ui_mutex);
- ubifs_release_dirty_inode_budget(c, ui);
- return err;
-}
-
-static void ubifs_evict_inode(struct inode *inode)
-{
- int err;
- struct ubifs_info *c = inode->i_sb->s_fs_info;
- struct ubifs_inode *ui = ubifs_inode(inode);
-
- if (ui->xattr)
- /*
- * Extended attribute inode deletions are fully handled in
- * 'ubifs_removexattr()'. These inodes are special and have
- * limited usage, so there is nothing to do here.
- */
- goto out;
-
- dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode);
- ubifs_assert(!atomic_read(&inode->i_count));
-
- truncate_inode_pages_final(&inode->i_data);
-
- if (inode->i_nlink)
- goto done;
-
- if (is_bad_inode(inode))
- goto out;
-
- ui->ui_size = inode->i_size = 0;
- err = ubifs_jnl_delete_inode(c, inode);
- if (err)
- /*
- * Worst case we have a lost orphan inode wasting space, so a
- * simple error message is OK here.
- */
- ubifs_err(c, "can't delete inode %lu, error %d",
- inode->i_ino, err);
-
-out:
- if (ui->dirty)
- ubifs_release_dirty_inode_budget(c, ui);
- else {
- /* We've deleted something - clean the "no space" flags */
- c->bi.nospace = c->bi.nospace_rp = 0;
- smp_wmb();
- }
-done:
- clear_inode(inode);
-}
-
-static void ubifs_dirty_inode(struct inode *inode, int flags)
-{
- struct ubifs_inode *ui = ubifs_inode(inode);
-
- ubifs_assert(mutex_is_locked(&ui->ui_mutex));
- if (!ui->dirty) {
- ui->dirty = 1;
- dbg_gen("inode %lu", inode->i_ino);
- }
-}
-
-static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf)
-{
- struct ubifs_info *c = dentry->d_sb->s_fs_info;
- unsigned long long free;
- __le32 *uuid = (__le32 *)c->uuid;
-
- free = ubifs_get_free_space(c);
- dbg_gen("free space %lld bytes (%lld blocks)",
- free, free >> UBIFS_BLOCK_SHIFT);
-
- buf->f_type = UBIFS_SUPER_MAGIC;
- buf->f_bsize = UBIFS_BLOCK_SIZE;
- buf->f_blocks = c->block_cnt;
- buf->f_bfree = free >> UBIFS_BLOCK_SHIFT;
- if (free > c->report_rp_size)
- buf->f_bavail = (free - c->report_rp_size) >> UBIFS_BLOCK_SHIFT;
- else
- buf->f_bavail = 0;
- buf->f_files = 0;
- buf->f_ffree = 0;
- buf->f_namelen = UBIFS_MAX_NLEN;
- buf->f_fsid.val[0] = le32_to_cpu(uuid[0]) ^ le32_to_cpu(uuid[2]);
- buf->f_fsid.val[1] = le32_to_cpu(uuid[1]) ^ le32_to_cpu(uuid[3]);
- ubifs_assert(buf->f_bfree <= c->block_cnt);
- return 0;
-}
-
-static int ubifs_show_options(struct seq_file *s, struct dentry *root)
-{
- struct ubifs_info *c = root->d_sb->s_fs_info;
-
- if (c->mount_opts.unmount_mode == 2)
- seq_puts(s, ",fast_unmount");
- else if (c->mount_opts.unmount_mode == 1)
- seq_puts(s, ",norm_unmount");
-
- if (c->mount_opts.bulk_read == 2)
- seq_puts(s, ",bulk_read");
- else if (c->mount_opts.bulk_read == 1)
- seq_puts(s, ",no_bulk_read");
-
- if (c->mount_opts.chk_data_crc == 2)
- seq_puts(s, ",chk_data_crc");
- else if (c->mount_opts.chk_data_crc == 1)
- seq_puts(s, ",no_chk_data_crc");
-
- if (c->mount_opts.override_compr) {
- seq_printf(s, ",compr=%s",
- ubifs_compr_name(c->mount_opts.compr_type));
- }
-
- return 0;
-}
-
-static int ubifs_sync_fs(struct super_block *sb, int wait)
-{
- int i, err;
- struct ubifs_info *c = sb->s_fs_info;
-
- /*
- * Zero @wait is just an advisory thing to help the file system shove
- * lots of data into the queues, and there will be the second
- * '->sync_fs()' call, with non-zero @wait.
- */
- if (!wait)
- return 0;
-
- /*
- * Synchronize write buffers, because 'ubifs_run_commit()' does not
- * do this if it waits for an already running commit.
- */
- for (i = 0; i < c->jhead_cnt; i++) {
- err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
- if (err)
- return err;
- }
-
- /*
- * Strictly speaking, it is not necessary to commit the journal here,
- * synchronizing write-buffers would be enough. But committing makes
- * UBIFS free space predictions much more accurate, so we want to let
- * the user be able to get more accurate results of 'statfs()' after
- * they synchronize the file system.
- */
- err = ubifs_run_commit(c);
- if (err)
- return err;
-
- return ubi_sync(c->vi.ubi_num);
-}
-#endif
/**
* init_constants_early - initialize UBIFS constants.
@@ -624,26 +387,6 @@ static int init_constants_early(struct ubifs_info *c)
return 0;
}
-/**
- * bud_wbuf_callback - bud LEB write-buffer synchronization call-back.
- * @c: UBIFS file-system description object
- * @lnum: LEB the write-buffer was synchronized to
- * @free: how many free bytes left in this LEB
- * @pad: how many bytes were padded
- *
- * This is a callback function which is called by the I/O unit when the
- * write-buffer is synchronized. We need this to correctly maintain space
- * accounting in bud logical eraseblocks. This function returns zero in case of
- * success and a negative error code in case of failure.
- *
- * This function actually belongs to the journal, but we keep it here because
- * we want to keep it static.
- */
-static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
-{
- return ubifs_update_one_lp(c, lnum, free, pad, 0, 0);
-}
-
/*
* init_constants_sb - initialize UBIFS constants.
* @c: UBIFS file-system description object
@@ -655,7 +398,7 @@ static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
*/
static int init_constants_sb(struct ubifs_info *c)
{
- int tmp, err;
+ int tmp;
long long tmp64;
c->main_bytes = (long long)c->main_lebs * c->leb_size;
@@ -726,71 +469,11 @@ static int init_constants_sb(struct ubifs_info *c)
if (c->max_bud_bytes < tmp64 + c->leb_size)
c->max_bud_bytes = tmp64 + c->leb_size;
- err = ubifs_calc_lpt_geom(c);
- if (err)
- return err;
-
/* Initialize effective LEB size used in budgeting calculations */
c->idx_leb_size = c->leb_size - c->max_idx_node_sz;
return 0;
}
-/*
- * init_constants_master - initialize UBIFS constants.
- * @c: UBIFS file-system description object
- *
- * This is a helper function which initializes various UBIFS constants after
- * the master node has been read. It also checks various UBIFS parameters and
- * makes sure they are all right.
- */
-static void init_constants_master(struct ubifs_info *c)
-{
- long long tmp64;
-
- c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
- c->report_rp_size = ubifs_reported_space(c, c->rp_size);
-
- /*
- * Calculate total amount of FS blocks. This number is not used
- * internally because it does not make much sense for UBIFS, but it is
- * necessary to report something for the 'statfs()' call.
- *
- * Subtract the LEB reserved for GC, the LEB which is reserved for
- * deletions, minimum LEBs for the index, and assume only one journal
- * head is available.
- */
- tmp64 = c->main_lebs - 1 - 1 - MIN_INDEX_LEBS - c->jhead_cnt + 1;
- tmp64 *= (long long)c->leb_size - c->leb_overhead;
- tmp64 = ubifs_reported_space(c, tmp64);
- c->block_cnt = tmp64 >> UBIFS_BLOCK_SHIFT;
-}
-
-/**
- * take_gc_lnum - reserve GC LEB.
- * @c: UBIFS file-system description object
- *
- * This function ensures that the LEB reserved for garbage collection is marked
- * as "taken" in lprops. We also have to set free space to LEB size and dirty
- * space to zero, because lprops may contain out-of-date information if the
- * file-system was un-mounted before it has been committed. This function
- * returns zero in case of success and a negative error code in case of
- * failure.
- */
-static int take_gc_lnum(struct ubifs_info *c)
-{
- int err;
-
- if (c->gc_lnum == -1) {
- ubifs_err(c, "no LEB for GC");
- return -EINVAL;
- }
-
- /* And we have to tell lprops that this LEB is taken */
- err = ubifs_change_one_lp(c, c->gc_lnum, c->leb_size, 0,
- LPROPS_TAKEN, 0, 0);
- return err;
-}
-
/**
* alloc_wbufs - allocate write-buffers.
* @c: UBIFS file-system description object
@@ -814,7 +497,6 @@ static int alloc_wbufs(struct ubifs_info *c)
if (err)
return err;
- c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
c->jheads[i].wbuf.jhead = i;
c->jheads[i].grouped = 1;
}
@@ -847,32 +529,6 @@ static void free_wbufs(struct ubifs_info *c)
}
}
-/**
- * free_orphans - free orphans.
- * @c: UBIFS file-system description object
- */
-static void free_orphans(struct ubifs_info *c)
-{
- struct ubifs_orphan *orph;
-
- while (c->orph_dnext) {
- orph = c->orph_dnext;
- c->orph_dnext = orph->dnext;
- list_del(&orph->list);
- kfree(orph);
- }
-
- while (!list_empty(&c->orph_list)) {
- orph = list_entry(c->orph_list.next, struct ubifs_orphan, list);
- list_del(&orph->list);
- kfree(orph);
- ubifs_err(c, "orphan list not empty at unmount");
- }
-
- vfree(c->orph_buf);
- c->orph_buf = NULL;
-}
-
/**
* free_buds - free per-bud objects.
* @c: UBIFS file-system description object
@@ -914,159 +570,6 @@ static int check_volume_empty(struct ubifs_info *c)
return 0;
}
-/*
- * UBIFS mount options.
- *
- * Opt_fast_unmount: do not run a journal commit before un-mounting
- * Opt_norm_unmount: run a journal commit before un-mounting
- * Opt_bulk_read: enable bulk-reads
- * Opt_no_bulk_read: disable bulk-reads
- * Opt_chk_data_crc: check CRCs when reading data nodes
- * Opt_no_chk_data_crc: do not check CRCs when reading data nodes
- * Opt_override_compr: override default compressor
- * Opt_err: just end of array marker
- */
-enum {
- Opt_fast_unmount,
- Opt_norm_unmount,
- Opt_bulk_read,
- Opt_no_bulk_read,
- Opt_chk_data_crc,
- Opt_no_chk_data_crc,
- Opt_override_compr,
- Opt_err,
-};
-
-#ifndef __BAREBOX__
-static const match_table_t tokens = {
- {Opt_fast_unmount, "fast_unmount"},
- {Opt_norm_unmount, "norm_unmount"},
- {Opt_bulk_read, "bulk_read"},
- {Opt_no_bulk_read, "no_bulk_read"},
- {Opt_chk_data_crc, "chk_data_crc"},
- {Opt_no_chk_data_crc, "no_chk_data_crc"},
- {Opt_override_compr, "compr=%s"},
- {Opt_err, NULL},
-};
-
-/**
- * parse_standard_option - parse a standard mount option.
- * @option: the option to parse
- *
- * Normally, standard mount options like "sync" are passed to file-systems as
- * flags. However, when a "rootflags=" kernel boot parameter is used, they may
- * be present in the options string. This function tries to deal with this
- * situation and parse standard options. Returns 0 if the option was not
- * recognized, and the corresponding integer flag if it was.
- *
- * UBIFS is only interested in the "sync" option, so do not check for anything
- * else.
- */
-static int parse_standard_option(const char *option)
-{
-
- pr_notice("UBIFS: parse %s\n", option);
- if (!strcmp(option, "sync"))
- return MS_SYNCHRONOUS;
- return 0;
-}
-
-/**
- * ubifs_parse_options - parse mount parameters.
- * @c: UBIFS file-system description object
- * @options: parameters to parse
- * @is_remount: non-zero if this is FS re-mount
- *
- * This function parses UBIFS mount options and returns zero in case success
- * and a negative error code in case of failure.
- */
-static int ubifs_parse_options(struct ubifs_info *c, char *options,
- int is_remount)
-{
- char *p;
- substring_t args[MAX_OPT_ARGS];
-
- if (!options)
- return 0;
-
- while ((p = strsep(&options, ","))) {
- int token;
-
- if (!*p)
- continue;
-
- token = match_token(p, tokens, args);
- switch (token) {
- /*
- * %Opt_fast_unmount and %Opt_norm_unmount options are ignored.
- * We accept them in order to be backward-compatible. But this
- * should be removed at some point.
- */
- case Opt_fast_unmount:
- c->mount_opts.unmount_mode = 2;
- break;
- case Opt_norm_unmount:
- c->mount_opts.unmount_mode = 1;
- break;
- case Opt_bulk_read:
- c->mount_opts.bulk_read = 2;
- c->bulk_read = 1;
- break;
- case Opt_no_bulk_read:
- c->mount_opts.bulk_read = 1;
- c->bulk_read = 0;
- break;
- case Opt_chk_data_crc:
- c->mount_opts.chk_data_crc = 2;
- c->no_chk_data_crc = 0;
- break;
- case Opt_no_chk_data_crc:
- c->mount_opts.chk_data_crc = 1;
- c->no_chk_data_crc = 1;
- break;
- case Opt_override_compr:
- {
- char *name = match_strdup(&args[0]);
-
- if (!name)
- return -ENOMEM;
- if (!strcmp(name, "none"))
- c->mount_opts.compr_type = UBIFS_COMPR_NONE;
- else if (!strcmp(name, "lzo"))
- c->mount_opts.compr_type = UBIFS_COMPR_LZO;
- else if (!strcmp(name, "zlib"))
- c->mount_opts.compr_type = UBIFS_COMPR_ZLIB;
- else {
- ubifs_err(c, "unknown compressor \"%s\"", name); //FIXME: is c ready?
- kfree(name);
- return -EINVAL;
- }
- kfree(name);
- c->mount_opts.override_compr = 1;
- c->default_compr = c->mount_opts.compr_type;
- break;
- }
- default:
- {
- unsigned long flag;
- struct super_block *sb = c->vfs_sb;
-
- flag = parse_standard_option(p);
- if (!flag) {
- ubifs_err(c, "unrecognized mount option \"%s\" or missing value",
- p);
- return -EINVAL;
- }
- sb->s_flags |= flag;
- break;
- }
- }
- }
-
- return 0;
-}
-#endif
-
/**
* destroy_journal - destroy journal data structures.
* @c: UBIFS file-system description object
@@ -1091,61 +594,11 @@ static void destroy_journal(struct ubifs_info *c)
list_del(&bud->list);
kfree(bud);
}
- ubifs_destroy_idx_gc(c);
ubifs_destroy_size_tree(c);
ubifs_tnc_close(c);
free_buds(c);
}
-/**
- * bu_init - initialize bulk-read information.
- * @c: UBIFS file-system description object
- */
-static void bu_init(struct ubifs_info *c)
-{
- ubifs_assert(c->bulk_read == 1);
-
- if (c->bu.buf)
- return; /* Already initialized */
-
-again:
- c->bu.buf = kmalloc(c->max_bu_buf_len, GFP_KERNEL | __GFP_NOWARN);
- if (!c->bu.buf) {
- if (c->max_bu_buf_len > UBIFS_KMALLOC_OK) {
- c->max_bu_buf_len = UBIFS_KMALLOC_OK;
- goto again;
- }
-
- /* Just disable bulk-read */
- ubifs_warn(c, "cannot allocate %d bytes of memory for bulk-read, disabling it",
- c->max_bu_buf_len);
- c->mount_opts.bulk_read = 1;
- c->bulk_read = 0;
- return;
- }
-}
-
-#ifndef __BAREBOX__
-/**
- * check_free_space - check if there is enough free space to mount.
- * @c: UBIFS file-system description object
- *
- * This function makes sure UBIFS has enough free space to be mounted in
- * read/write mode. UBIFS must always have some free space to allow deletions.
- */
-static int check_free_space(struct ubifs_info *c)
-{
- ubifs_assert(c->dark_wm > 0);
- if (c->lst.total_free + c->lst.total_dirty < c->dark_wm) {
- ubifs_err(c, "insufficient free space to mount in R/W mode");
- ubifs_dump_budg(c, &c->bi);
- ubifs_dump_lprops(c);
- return -ENOSPC;
- }
- return 0;
-}
-#endif
-
/**
* mount_ubifs - mount UBIFS file-system.
* @c: UBIFS file-system description object
@@ -1206,25 +659,6 @@ static int mount_ubifs(struct ubifs_info *c)
if (!c->sbuf)
goto out_free;
-#ifndef __BAREBOX__
- if (!c->ro_mount) {
- c->ileb_buf = vmalloc(c->leb_size);
- if (!c->ileb_buf)
- goto out_free;
- }
-#endif
-
- if (c->bulk_read == 1)
- bu_init(c);
-
-#ifndef __BAREBOX__
- if (!c->ro_mount) {
- c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ,
- GFP_KERNEL);
- if (!c->write_reserve_buf)
- goto out_free;
- }
-#endif
c->mounting = 1;
@@ -1262,143 +696,27 @@ static int mount_ubifs(struct ubifs_info *c)
goto out_cbuf;
sprintf(c->bgt_name, BGT_NAME_PATTERN, c->vi.ubi_num, c->vi.vol_id);
-#ifndef __BAREBOX__
- if (!c->ro_mount) {
- /* Create background thread */
- c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
- if (IS_ERR(c->bgt)) {
- err = PTR_ERR(c->bgt);
- c->bgt = NULL;
- ubifs_err(c, "cannot spawn \"%s\", error %d",
- c->bgt_name, err);
- goto out_wbufs;
- }
- wake_up_process(c->bgt);
- }
-#endif
err = ubifs_read_master(c);
if (err)
goto out_master;
- init_constants_master(c);
-
if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
ubifs_msg(c, "recovery needed");
c->need_recovery = 1;
}
-#ifndef __BAREBOX__
- if (c->need_recovery && !c->ro_mount) {
- err = ubifs_recover_inl_heads(c, c->sbuf);
- if (err)
- goto out_master;
- }
-#endif
-
- err = ubifs_lpt_init(c, 1, !c->ro_mount);
- if (err)
- goto out_master;
-
-#ifndef __BAREBOX__
- if (!c->ro_mount && c->space_fixup) {
- err = ubifs_fixup_free_space(c);
- if (err)
- goto out_lpt;
- }
-
- if (!c->ro_mount && !c->need_recovery) {
- /*
- * Set the "dirty" flag so that if we reboot uncleanly we
- * will notice this immediately on the next mount.
- */
- c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
- err = ubifs_write_master(c);
- if (err)
- goto out_lpt;
- }
-#endif
-
- err = dbg_check_idx_size(c, c->bi.old_idx_sz);
- if (err)
- goto out_lpt;
-
err = ubifs_replay_journal(c);
if (err)
goto out_journal;
- /* Calculate 'min_idx_lebs' after journal replay */
- c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
-
- err = ubifs_mount_orphans(c, c->need_recovery, c->ro_mount);
- if (err)
- goto out_orphans;
-
if (!c->ro_mount) {
-#ifndef __BAREBOX__
- int lnum;
-
- err = check_free_space(c);
- if (err)
- goto out_orphans;
-
- /* Check for enough log space */
- lnum = c->lhead_lnum + 1;
- if (lnum >= UBIFS_LOG_LNUM + c->log_lebs)
- lnum = UBIFS_LOG_LNUM;
- if (lnum == c->ltail_lnum) {
- err = ubifs_consolidate_log(c);
- if (err)
- goto out_orphans;
- }
-
- if (c->need_recovery) {
- err = ubifs_recover_size(c);
- if (err)
- goto out_orphans;
- err = ubifs_rcvry_gc_commit(c);
- if (err)
- goto out_orphans;
- } else {
- err = take_gc_lnum(c);
- if (err)
- goto out_orphans;
-
- /*
- * GC LEB may contain garbage if there was an unclean
- * reboot, and it should be un-mapped.
- */
- err = ubifs_leb_unmap(c, c->gc_lnum);
- if (err)
- goto out_orphans;
- }
-
- err = dbg_check_lprops(c);
- if (err)
- goto out_orphans;
-#endif
} else if (c->need_recovery) {
err = ubifs_recover_size(c);
if (err)
goto out_orphans;
- } else {
- /*
- * Even if we mount read-only, we have to set space in GC LEB
- * to proper value because this affects UBIFS free space
- * reporting. We do not want to have a situation when
- * re-mounting from R/O to R/W changes amount of free space.
- */
- err = take_gc_lnum(c);
- if (err)
- goto out_orphans;
}
-#ifndef __BAREBOX__
- spin_lock(&ubifs_infos_lock);
- list_add_tail(&c->infos_list, &ubifs_infos);
- spin_unlock(&ubifs_infos_lock);
-#endif
-
if (c->need_recovery) {
if (c->ro_mount)
ubifs_msg(c, "recovery deferred");
@@ -1412,8 +730,7 @@ static int mount_ubifs(struct ubifs_info *c)
*/
ubifs_assert(c->lst.taken_empty_lebs > 0);
}
- } else
- ubifs_assert(c->lst.taken_empty_lebs > 0);
+ }
err = dbg_check_filesystem(c);
if (err)
@@ -1496,19 +813,13 @@ out_infos:
list_del(&c->infos_list);
spin_unlock(&ubifs_infos_lock);
out_orphans:
- free_orphans(c);
out_journal:
destroy_journal(c);
-out_lpt:
- ubifs_lpt_free(c, 0);
out_master:
kfree(c->mst_node);
kfree(c->rcvrd_mst_node);
if (c->bgt)
kthread_stop(c->bgt);
-#ifndef __BAREBOX__
-out_wbufs:
-#endif
free_wbufs(c);
out_cbuf:
kfree(c->cbuf);
@@ -1531,11 +842,7 @@ out_free:
* through mounting (error path cleanup function). So it has to make sure the
* resource was actually allocated before freeing it.
*/
-#ifndef __BAREBOX__
-static void ubifs_umount(struct ubifs_info *c)
-#else
void ubifs_umount(struct ubifs_info *c)
-#endif
{
dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num,
c->vi.vol_id);
@@ -1545,15 +852,7 @@ void ubifs_umount(struct ubifs_info *c)
list_del(&c->infos_list);
spin_unlock(&ubifs_infos_lock);
-#ifndef __BAREBOX__
- if (c->bgt)
- kthread_stop(c->bgt);
-
- destroy_journal(c);
-#endif
free_wbufs(c);
- free_orphans(c);
- ubifs_lpt_free(c, 0);
kfree(c->cbuf);
kfree(c->rcvrd_mst_node);
@@ -1564,375 +863,11 @@ void ubifs_umount(struct ubifs_info *c)
vfree(c->sbuf);
kfree(c->bottom_up_buf);
ubifs_debugging_exit(c);
-#ifdef __BAREBOX__
- /* Finally free U-Boot's global copy of superblock */
- if (ubifs_sb != NULL) {
- free(ubifs_sb->s_fs_info);
- free(ubifs_sb);
- }
-#endif
-}
-
-#ifndef __BAREBOX__
-/**
- * ubifs_remount_rw - re-mount in read-write mode.
- * @c: UBIFS file-system description object
- *
- * UBIFS avoids allocating many unnecessary resources when mounted in read-only
- * mode. This function allocates the needed resources and re-mounts UBIFS in
- * read-write mode.
- */
-static int ubifs_remount_rw(struct ubifs_info *c)
-{
- int err, lnum;
-
- if (c->rw_incompat) {
- ubifs_err(c, "the file-system is not R/W-compatible");
- ubifs_msg(c, "on-flash format version is w%d/r%d, but software only supports up to version w%d/r%d",
- c->fmt_version, c->ro_compat_version,
- UBIFS_FORMAT_VERSION, UBIFS_RO_COMPAT_VERSION);
- return -EROFS;
- }
-
- mutex_lock(&c->umount_mutex);
- dbg_save_space_info(c);
- c->remounting_rw = 1;
- c->ro_mount = 0;
-
- if (c->space_fixup) {
- err = ubifs_fixup_free_space(c);
- if (err)
- goto out;
- }
-
- err = check_free_space(c);
- if (err)
- goto out;
-
- if (c->old_leb_cnt != c->leb_cnt) {
- struct ubifs_sb_node *sup;
-
- sup = ubifs_read_sb_node(c);
- if (IS_ERR(sup)) {
- err = PTR_ERR(sup);
- goto out;
- }
- sup->leb_cnt = cpu_to_le32(c->leb_cnt);
- err = ubifs_write_sb_node(c, sup);
- kfree(sup);
- if (err)
- goto out;
- }
-
- if (c->need_recovery) {
- ubifs_msg(c, "completing deferred recovery");
- err = ubifs_write_rcvrd_mst_node(c);
- if (err)
- goto out;
- err = ubifs_recover_size(c);
- if (err)
- goto out;
- err = ubifs_clean_lebs(c, c->sbuf);
- if (err)
- goto out;
- err = ubifs_recover_inl_heads(c, c->sbuf);
- if (err)
- goto out;
- } else {
- /* A readonly mount is not allowed to have orphans */
- ubifs_assert(c->tot_orphans == 0);
- err = ubifs_clear_orphans(c);
- if (err)
- goto out;
- }
-
- if (!(c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY))) {
- c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
- err = ubifs_write_master(c);
- if (err)
- goto out;
- }
-
- c->ileb_buf = vmalloc(c->leb_size);
- if (!c->ileb_buf) {
- err = -ENOMEM;
- goto out;
- }
-
- c->write_reserve_buf = kmalloc(COMPRESSED_DATA_NODE_BUF_SZ, GFP_KERNEL);
- if (!c->write_reserve_buf) {
- err = -ENOMEM;
- goto out;
- }
-
- err = ubifs_lpt_init(c, 0, 1);
- if (err)
- goto out;
-
- /* Create background thread */
- c->bgt = kthread_create(ubifs_bg_thread, c, "%s", c->bgt_name);
- if (IS_ERR(c->bgt)) {
- err = PTR_ERR(c->bgt);
- c->bgt = NULL;
- ubifs_err(c, "cannot spawn \"%s\", error %d",
- c->bgt_name, err);
- goto out;
- }
- wake_up_process(c->bgt);
-
- c->orph_buf = vmalloc(c->leb_size);
- if (!c->orph_buf) {
- err = -ENOMEM;
- goto out;
- }
-
- /* Check for enough log space */
- lnum = c->lhead_lnum + 1;
- if (lnum >= UBIFS_LOG_LNUM + c->log_lebs)
- lnum = UBIFS_LOG_LNUM;
- if (lnum == c->ltail_lnum) {
- err = ubifs_consolidate_log(c);
- if (err)
- goto out;
- }
-
- if (c->need_recovery)
- err = ubifs_rcvry_gc_commit(c);
- else
- err = ubifs_leb_unmap(c, c->gc_lnum);
- if (err)
- goto out;
-
- dbg_gen("re-mounted read-write");
- c->remounting_rw = 0;
-
- if (c->need_recovery) {
- c->need_recovery = 0;
- ubifs_msg(c, "deferred recovery completed");
- } else {
- /*
- * Do not run the debugging space check if the were doing
- * recovery, because when we saved the information we had the
- * file-system in a state where the TNC and lprops has been
- * modified in memory, but all the I/O operations (including a
- * commit) were deferred. So the file-system was in
- * "non-committed" state. Now the file-system is in committed
- * state, and of course the amount of free space will change
- * because, for example, the old index size was imprecise.
- */
- err = dbg_check_space_info(c);
- }
-
- mutex_unlock(&c->umount_mutex);
- return err;
-
-out:
- c->ro_mount = 1;
- vfree(c->orph_buf);
- c->orph_buf = NULL;
- if (c->bgt) {
- kthread_stop(c->bgt);
- c->bgt = NULL;
- }
- free_wbufs(c);
- kfree(c->write_reserve_buf);
- c->write_reserve_buf = NULL;
- vfree(c->ileb_buf);
- c->ileb_buf = NULL;
- ubifs_lpt_free(c, 1);
- c->remounting_rw = 0;
- mutex_unlock(&c->umount_mutex);
- return err;
-}
-
-/**
- * ubifs_remount_ro - re-mount in read-only mode.
- * @c: UBIFS file-system description object
- *
- * We assume VFS has stopped writing. Possibly the background thread could be
- * running a commit, however kthread_stop will wait in that case.
- */
-static void ubifs_remount_ro(struct ubifs_info *c)
-{
- int i, err;
-
- ubifs_assert(!c->need_recovery);
- ubifs_assert(!c->ro_mount);
-
- mutex_lock(&c->umount_mutex);
- if (c->bgt) {
- kthread_stop(c->bgt);
- c->bgt = NULL;
- }
-
- dbg_save_space_info(c);
-
- for (i = 0; i < c->jhead_cnt; i++)
- ubifs_wbuf_sync(&c->jheads[i].wbuf);
-
- c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
- c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
- c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum);
- err = ubifs_write_master(c);
- if (err)
- ubifs_ro_mode(c, err);
-
- vfree(c->orph_buf);
- c->orph_buf = NULL;
- kfree(c->write_reserve_buf);
- c->write_reserve_buf = NULL;
- vfree(c->ileb_buf);
- c->ileb_buf = NULL;
- ubifs_lpt_free(c, 1);
- c->ro_mount = 1;
- err = dbg_check_space_info(c);
- if (err)
- ubifs_ro_mode(c, err);
- mutex_unlock(&c->umount_mutex);
-}
-
-static void ubifs_put_super(struct super_block *sb)
-{
- int i;
- struct ubifs_info *c = sb->s_fs_info;
-
- ubifs_msg(c, "un-mount UBI device %d", c->vi.ubi_num);
-
- /*
- * The following asserts are only valid if there has not been a failure
- * of the media. For example, there will be dirty inodes if we failed
- * to write them back because of I/O errors.
- */
- if (!c->ro_error) {
- ubifs_assert(c->bi.idx_growth == 0);
- ubifs_assert(c->bi.dd_growth == 0);
- ubifs_assert(c->bi.data_growth == 0);
- }
-
- /*
- * The 'c->umount_lock' prevents races between UBIFS memory shrinker
- * and file system un-mount. Namely, it prevents the shrinker from
- * picking this superblock for shrinking - it will be just skipped if
- * the mutex is locked.
- */
- mutex_lock(&c->umount_mutex);
- if (!c->ro_mount) {
- /*
- * First of all kill the background thread to make sure it does
- * not interfere with un-mounting and freeing resources.
- */
- if (c->bgt) {
- kthread_stop(c->bgt);
- c->bgt = NULL;
- }
-
- /*
- * On fatal errors c->ro_error is set to 1, in which case we do
- * not write the master node.
- */
- if (!c->ro_error) {
- int err;
-
- /* Synchronize write-buffers */
- for (i = 0; i < c->jhead_cnt; i++)
- ubifs_wbuf_sync(&c->jheads[i].wbuf);
-
- /*
- * We are being cleanly unmounted which means the
- * orphans were killed - indicate this in the master
- * node. Also save the reserved GC LEB number.
- */
- c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_DIRTY);
- c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
- c->mst_node->gc_lnum = cpu_to_le32(c->gc_lnum);
- err = ubifs_write_master(c);
- if (err)
- /*
- * Recovery will attempt to fix the master area
- * next mount, so we just print a message and
- * continue to unmount normally.
- */
- ubifs_err(c, "failed to write master node, error %d",
- err);
- } else {
-#ifndef __BAREBOX__
- for (i = 0; i < c->jhead_cnt; i++)
- /* Make sure write-buffer timers are canceled */
- hrtimer_cancel(&c->jheads[i].wbuf.timer);
-#endif
- }
- }
-
- ubifs_umount(c);
-#ifndef __BAREBOX__
- bdi_destroy(&c->bdi);
-#endif
- ubi_close_volume(c->ubi);
- mutex_unlock(&c->umount_mutex);
}
-#endif
-
-#ifndef __BAREBOX__
-static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
-{
- int err;
- struct ubifs_info *c = sb->s_fs_info;
-
- sync_filesystem(sb);
- dbg_gen("old flags %#lx, new flags %#x", sb->s_flags, *flags);
-
- err = ubifs_parse_options(c, data, 1);
- if (err) {
- ubifs_err(c, "invalid or unknown remount parameter");
- return err;
- }
-
- if (c->ro_mount && !(*flags & MS_RDONLY)) {
- if (c->ro_error) {
- ubifs_msg(c, "cannot re-mount R/W due to prior errors");
- return -EROFS;
- }
- if (c->ro_media) {
- ubifs_msg(c, "cannot re-mount R/W - UBI volume is R/O");
- return -EROFS;
- }
- err = ubifs_remount_rw(c);
- if (err)
- return err;
- } else if (!c->ro_mount && (*flags & MS_RDONLY)) {
- if (c->ro_error) {
- ubifs_msg(c, "cannot re-mount R/O due to prior errors");
- return -EROFS;
- }
- ubifs_remount_ro(c);
- }
-
- if (c->bulk_read == 1)
- bu_init(c);
- else {
- dbg_gen("disable bulk-read");
- kfree(c->bu.buf);
- c->bu.buf = NULL;
- }
-
- ubifs_assert(c->lst.taken_empty_lebs > 0);
- return 0;
-}
-#endif
const struct super_operations ubifs_super_operations = {
.alloc_inode = ubifs_alloc_inode,
.destroy_inode = ubifs_destroy_inode,
-#ifndef __BAREBOX__
- .put_super = ubifs_put_super,
- .write_inode = ubifs_write_inode,
- .evict_inode = ubifs_evict_inode,
- .statfs = ubifs_statfs,
- .dirty_inode = ubifs_dirty_inode,
- .remount_fs = ubifs_remount_fs,
- .show_options = ubifs_show_options,
- .sync_fs = ubifs_sync_fs,
-#endif
};
/**
@@ -1954,54 +889,6 @@ const struct super_operations ubifs_super_operations = {
* returns UBI volume description object in case of success and a negative
* error code in case of failure.
*/
-#ifndef __BAREBOX__
-static struct ubi_volume_desc *open_ubi(const char *name, int mode)
-{
-#ifndef __BAREBOX__
- struct ubi_volume_desc *ubi;
-#endif
- int dev, vol;
- char *endptr;
-
-#ifndef __BAREBOX__
- /* First, try to open using the device node path method */
- ubi = ubi_open_volume_path(name, mode);
- if (!IS_ERR(ubi))
- return ubi;
-#endif
-
- /* Try the "nodev" method */
- if (name[0] != 'u' || name[1] != 'b' || name[2] != 'i')
- return ERR_PTR(-EINVAL);
-
- /* ubi:NAME method */
- if ((name[3] == ':' || name[3] == '!') && name[4] != '\0')
- return ubi_open_volume_nm(0, name + 4, mode);
-
- if (!isdigit(name[3]))
- return ERR_PTR(-EINVAL);
-
- dev = simple_strtoul(name + 3, &endptr, 0);
-
- /* ubiY method */
- if (*endptr == '\0')
- return ubi_open_volume(0, dev, mode);
-
- /* ubiX_Y method */
- if (*endptr == '_' && isdigit(endptr[1])) {
- vol = simple_strtoul(endptr + 1, &endptr, 0);
- if (*endptr != '\0')
- return ERR_PTR(-EINVAL);
- return ubi_open_volume(dev, vol, mode);
- }
-
- /* ubiX:NAME method */
- if ((*endptr == ':' || *endptr == '!') && endptr[1] != '\0')
- return ubi_open_volume_nm(dev, ++endptr, mode);
-
- return ERR_PTR(-EINVAL);
-}
-#endif
static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
{
@@ -2056,45 +943,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
int err;
c->vfs_sb = sb;
-#ifndef __BAREBOX__ /* ubi_open_volume_cdev is already called in ubifs_probe */
-#ifndef __BAREBOX__
- /* Re-open the UBI device in read-write mode */
- c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READWRITE);
-#else
- /* U-Boot read only mode */
- c->ubi = ubi_open_volume(c->vi.ubi_num, c->vi.vol_id, UBI_READONLY);
-#endif
-
- if (IS_ERR(c->ubi)) {
- err = PTR_ERR(c->ubi);
- goto out;
- }
-#endif
-#ifndef __BAREBOX__
- /*
- * UBIFS provides 'backing_dev_info' in order to disable read-ahead. For
- * UBIFS, I/O is not deferred, it is done immediately in readpage,
- * which means the user would have to wait not just for their own I/O
- * but the read-ahead I/O as well i.e. completely pointless.
- *
- * Read-ahead will be disabled because @c->bdi.ra_pages is 0.
- */
- c->bdi.name = "ubifs",
- c->bdi.capabilities = 0;
- err = bdi_init(&c->bdi);
- if (err)
- goto out_close;
- err = bdi_register(&c->bdi, NULL, "ubifs_%d_%d",
- c->vi.ubi_num, c->vi.vol_id);
- if (err)
- goto out_bdi;
-
- err = ubifs_parse_options(c, data, 0);
- if (err)
- goto out_bdi;
-
- sb->s_bdi = &c->bdi;
-#endif
sb->s_fs_info = c;
sb->s_magic = UBIFS_SUPER_MAGIC;
sb->s_blocksize = UBIFS_BLOCK_SIZE;
@@ -2103,9 +951,6 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
if (c->max_inode_sz > MAX_LFS_FILESIZE)
sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
sb->s_op = &ubifs_super_operations;
-#ifndef __BAREBOX__
- sb->s_xattr = ubifs_xattr_handlers;
-#endif
mutex_lock(&c->umount_mutex);
err = mount_ubifs(c);
@@ -2134,225 +979,9 @@ out_umount:
ubifs_umount(c);
out_unlock:
mutex_unlock(&c->umount_mutex);
-#ifndef __BAREBOX__
-out_bdi:
- bdi_destroy(&c->bdi);
-out_close:
-#endif
-#ifndef __BAREBOX__ /* This will be called in ubifs_probe error path */
- ubi_close_volume(c->ubi);
-out:
-#endif
return err;
}
-#ifndef __BAREBOX__
-static int sb_test(struct super_block *sb, void *data)
-{
- struct ubifs_info *c1 = data;
- struct ubifs_info *c = sb->s_fs_info;
-
- return c->vi.cdev == c1->vi.cdev;
-}
-
-static int sb_set(struct super_block *sb, void *data)
-{
- sb->s_fs_info = data;
- return set_anon_super(sb, NULL);
-}
-#endif
-
-static struct super_block *alloc_super(struct file_system_type *type, int flags)
-{
- struct super_block *s;
- int err;
-
- s = kzalloc(sizeof(struct super_block), GFP_USER);
- if (!s) {
- err = -ENOMEM;
- return ERR_PTR(err);
- }
-
- INIT_HLIST_NODE(&s->s_instances);
- INIT_LIST_HEAD(&s->s_inodes);
- s->s_time_gran = 1000000000;
- s->s_flags = flags;
-
- return s;
-}
-
-/**
- * sget - find or create a superblock
- * @type: filesystem type superblock should belong to
- * @test: comparison callback
- * @set: setup callback
- * @flags: mount flags
- * @data: argument to each of them
- */
-struct super_block *sget(struct file_system_type *type,
- int (*test)(struct super_block *,void *),
- int (*set)(struct super_block *,void *),
- int flags,
- void *data)
-{
- struct super_block *s = NULL;
-#ifndef __BAREBOX__
- struct super_block *old;
-#endif
- int err;
-
-#ifndef __BAREBOX__
-retry:
- spin_lock(&sb_lock);
- if (test) {
- hlist_for_each_entry(old, &type->fs_supers, s_instances) {
- if (!test(old, data))
- continue;
- if (!grab_super(old))
- goto retry;
- if (s) {
- up_write(&s->s_umount);
- destroy_super(s);
- s = NULL;
- }
- return old;
- }
- }
-#endif
- if (!s) {
- spin_unlock(&sb_lock);
- s = alloc_super(type, flags);
- if (!s)
- return ERR_PTR(-ENOMEM);
-#ifndef __BAREBOX__
- goto retry;
-#endif
- }
-
- err = set(s, data);
- if (err) {
-#ifndef __BAREBOX__
- spin_unlock(&sb_lock);
- up_write(&s->s_umount);
- destroy_super(s);
-#endif
- return ERR_PTR(err);
- }
- s->s_type = type;
-#ifndef __BAREBOX__
- strlcpy(s->s_id, type->name, sizeof(s->s_id));
-#else
- strncpy(s->s_id, type->name, sizeof(s->s_id));
-#endif
- list_add_tail(&s->s_list, &super_blocks);
- hlist_add_head(&s->s_instances, &type->fs_supers);
-#ifndef __BAREBOX__
- spin_unlock(&sb_lock);
- get_filesystem(type);
- register_shrinker(&s->s_shrink);
-#endif
- return s;
-}
-
-EXPORT_SYMBOL(sget);
-
-#ifndef __BAREBOX__
-static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
- const char *name, void *data)
-{
- struct ubi_volume_desc *ubi;
- struct ubifs_info *c;
- struct super_block *sb;
- int err;
-
- dbg_gen("name %s, flags %#x", name, flags);
-
- /*
- * Get UBI device number and volume ID. Mount it read-only so far
- * because this might be a new mount point, and UBI allows only one
- * read-write user at a time.
- */
- ubi = open_ubi(name, UBI_READONLY);
- if (IS_ERR(ubi)) {
- pr_err("UBIFS error (pid: %d): cannot open \"%s\", error %d",
- 0, name, (int)PTR_ERR(ubi));
- return ERR_CAST(ubi);
- }
-
- c = alloc_ubifs_info(ubi);
- if (!c) {
- err = -ENOMEM;
- goto out_close;
- }
-
- dbg_gen("opened ubi%d_%d", c->vi.ubi_num, c->vi.vol_id);
-
- sb = sget(fs_type, sb_test, sb_set, flags, c);
- if (IS_ERR(sb)) {
- err = PTR_ERR(sb);
- kfree(c);
- goto out_close;
- }
-
- if (sb->s_root) {
- struct ubifs_info *c1 = sb->s_fs_info;
- kfree(c);
- /* A new mount point for already mounted UBIFS */
- dbg_gen("this ubi volume is already mounted");
- if (!!(flags & MS_RDONLY) != c1->ro_mount) {
- err = -EBUSY;
- goto out_deact;
- }
- } else {
- err = ubifs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
- if (err)
- goto out_deact;
- /* We do not support atime */
- sb->s_flags |= MS_ACTIVE | MS_NOATIME;
- }
-
- /* 'fill_super()' opens ubi again so we must close it here */
- ubi_close_volume(ubi);
-
-#ifdef __BAREBOX__
- ubifs_sb = sb;
- return 0;
-#else
- return dget(sb->s_root);
-#endif
-
-out_deact:
-#ifndef __BAREBOX__
- deactivate_locked_super(sb);
-#endif
-out_close:
- ubi_close_volume(ubi);
- return ERR_PTR(err);
-}
-
-static void kill_ubifs_super(struct super_block *s)
-{
- struct ubifs_info *c = s->s_fs_info;
-#ifndef __BAREBOX__
- kill_anon_super(s);
-#endif
- kfree(c);
-}
-
-static struct file_system_type ubifs_fs_type = {
- .name = "ubifs",
- .owner = THIS_MODULE,
-#ifndef __BAREBOX__
- .mount = ubifs_mount,
-#endif
- .kill_sb = kill_ubifs_super,
-};
-#endif
-
-#ifndef __BAREBOX__
-MODULE_ALIAS_FS("ubifs");
-#endif
-
/*
* Inode slab cache constructor.
*/
@@ -2428,72 +1057,19 @@ static int __init ubifs_init(void)
if (!ubifs_inode_slab)
return -ENOMEM;
-#ifndef __BAREBOX__
- err = register_shrinker(&ubifs_shrinker_info);
- if (err)
- goto out_slab;
-#endif
-
err = ubifs_compressors_init();
if (err)
goto out_shrinker;
-#ifndef __BAREBOX__
- err = dbg_debugfs_init();
- if (err)
- goto out_compr;
-
- err = register_filesystem(&ubifs_fs_type);
- if (err) {
- pr_err("UBIFS error (pid %d): cannot register file system, error %d",
- current->pid, err);
- goto out_dbg;
- }
-#endif
return 0;
-#ifndef __BAREBOX__
-out_dbg:
- dbg_debugfs_exit();
-out_compr:
- ubifs_compressors_exit();
-#endif
out_shrinker:
-#ifndef __BAREBOX__
- unregister_shrinker(&ubifs_shrinker_info);
-out_slab:
-#endif
kmem_cache_destroy(ubifs_inode_slab);
return err;
}
/* late_initcall to let compressors initialize first */
late_initcall(ubifs_init);
-#ifndef __BAREBOX__
-static void __exit ubifs_exit(void)
-{
- ubifs_assert(list_empty(&ubifs_infos));
- ubifs_assert(atomic_long_read(&ubifs_clean_zn_cnt) == 0);
-
- dbg_debugfs_exit();
- ubifs_compressors_exit();
- unregister_shrinker(&ubifs_shrinker_info);
-
- /*
- * Make sure all delayed rcu free inodes are flushed before we
- * destroy cache.
- */
- rcu_barrier();
- kmem_cache_destroy(ubifs_inode_slab);
- unregister_filesystem(&ubifs_fs_type);
-}
-module_exit(ubifs_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_VERSION(__stringify(UBIFS_VERSION));
-MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter");
-MODULE_DESCRIPTION("UBIFS - UBI File System");
-#endif
int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent)
{
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 73abece321..0f93051bac 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -19,13 +19,8 @@
* the mutex locked.
*/
-#ifndef __BAREBOX__
-#include <linux/crc32.h>
-#include <linux/slab.h>
-#else
#include <linux/err.h>
#include <linux/stat.h>
-#endif
#include "ubifs.h"
/*
@@ -180,61 +175,6 @@ void destroy_old_idx(struct ubifs_info *c)
c->old_idx = RB_ROOT;
}
-/**
- * copy_znode - copy a dirty znode.
- * @c: UBIFS file-system description object
- * @znode: znode to copy
- *
- * A dirty znode being committed may not be changed, so it is copied.
- */
-static struct ubifs_znode *copy_znode(struct ubifs_info *c,
- struct ubifs_znode *znode)
-{
- struct ubifs_znode *zn;
-
- zn = kmalloc(c->max_znode_sz, GFP_NOFS);
- if (unlikely(!zn))
- return ERR_PTR(-ENOMEM);
-
- memcpy(zn, znode, c->max_znode_sz);
- zn->cnext = NULL;
- __set_bit(DIRTY_ZNODE, &zn->flags);
- __clear_bit(COW_ZNODE, &zn->flags);
-
- ubifs_assert(!ubifs_zn_obsolete(znode));
- __set_bit(OBSOLETE_ZNODE, &znode->flags);
-
- if (znode->level != 0) {
- int i;
- const int n = zn->child_cnt;
-
- /* The children now have new parent */
- for (i = 0; i < n; i++) {
- struct ubifs_zbranch *zbr = &zn->zbranch[i];
-
- if (zbr->znode)
- zbr->znode->parent = zn;
- }
- }
-
- atomic_long_inc(&c->dirty_zn_cnt);
- return zn;
-}
-
-/**
- * add_idx_dirt - add dirt due to a dirty znode.
- * @c: UBIFS file-system description object
- * @lnum: LEB number of index node
- * @dirt: size of index node
- *
- * This function updates lprops dirty space and the new size of the index.
- */
-static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt)
-{
- c->calc_idx_sz -= ALIGN(dirt, 8);
- return ubifs_add_dirt(c, lnum, dirt);
-}
-
/**
* dirty_cow_znode - ensure a znode is not being committed.
* @c: UBIFS file-system description object
@@ -245,43 +185,7 @@ static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt)
static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
struct ubifs_zbranch *zbr)
{
- struct ubifs_znode *znode = zbr->znode;
- struct ubifs_znode *zn;
- int err;
-
- if (!ubifs_zn_cow(znode)) {
- /* znode is not being committed */
- if (!test_and_set_bit(DIRTY_ZNODE, &znode->flags)) {
- atomic_long_inc(&c->dirty_zn_cnt);
- atomic_long_dec(&c->clean_zn_cnt);
- atomic_long_dec(&ubifs_clean_zn_cnt);
- err = add_idx_dirt(c, zbr->lnum, zbr->len);
- if (unlikely(err))
- return ERR_PTR(err);
- }
- return znode;
- }
-
- zn = copy_znode(c, znode);
- if (IS_ERR(zn))
- return zn;
-
- if (zbr->len) {
- err = insert_old_idx(c, zbr->lnum, zbr->offs);
- if (unlikely(err))
- return ERR_PTR(err);
- err = add_idx_dirt(c, zbr->lnum, zbr->len);
- } else
- err = 0;
-
- zbr->znode = zn;
- zbr->lnum = 0;
- zbr->offs = 0;
- zbr->len = 0;
-
- if (unlikely(err))
- return ERR_PTR(err);
- return zn;
+ return zbr->znode;
}
/**
@@ -981,153 +885,6 @@ static int fallible_resolve_collision(struct ubifs_info *c,
return 1;
}
-/**
- * matches_position - determine if a zbranch matches a given position.
- * @zbr: zbranch of dent
- * @lnum: LEB number of dent to match
- * @offs: offset of dent to match
- *
- * This function returns %1 if @lnum:@offs matches, and %0 otherwise.
- */
-static int matches_position(struct ubifs_zbranch *zbr, int lnum, int offs)
-{
- if (zbr->lnum == lnum && zbr->offs == offs)
- return 1;
- else
- return 0;
-}
-
-/**
- * resolve_collision_directly - resolve a collision directly.
- * @c: UBIFS file-system description object
- * @key: key of directory entry
- * @zn: znode is passed and returned here
- * @n: zbranch number is passed and returned here
- * @lnum: LEB number of dent node to match
- * @offs: offset of dent node to match
- *
- * This function is used for "hashed" keys to make sure the found directory or
- * extended attribute entry node is what was looked for. It is used when the
- * flash address of the right node is known (@lnum:@offs) which makes it much
- * easier to resolve collisions (no need to read entries and match full
- * names). This function returns %1 and sets @zn and @n if the collision is
- * resolved, %0 if @lnum:@offs is not found and @zn and @n are set to the
- * previous directory entry. Otherwise a negative error code is returned.
- */
-static int resolve_collision_directly(struct ubifs_info *c,
- const union ubifs_key *key,
- struct ubifs_znode **zn, int *n,
- int lnum, int offs)
-{
- struct ubifs_znode *znode;
- int nn, err;
-
- znode = *zn;
- nn = *n;
- if (matches_position(&znode->zbranch[nn], lnum, offs))
- return 1;
-
- /* Look left */
- while (1) {
- err = tnc_prev(c, &znode, &nn);
- if (err == -ENOENT)
- break;
- if (err < 0)
- return err;
- if (keys_cmp(c, &znode->zbranch[nn].key, key))
- break;
- if (matches_position(&znode->zbranch[nn], lnum, offs)) {
- *zn = znode;
- *n = nn;
- return 1;
- }
- }
-
- /* Look right */
- znode = *zn;
- nn = *n;
- while (1) {
- err = tnc_next(c, &znode, &nn);
- if (err == -ENOENT)
- return 0;
- if (err < 0)
- return err;
- if (keys_cmp(c, &znode->zbranch[nn].key, key))
- return 0;
- *zn = znode;
- *n = nn;
- if (matches_position(&znode->zbranch[nn], lnum, offs))
- return 1;
- }
-}
-
-/**
- * dirty_cow_bottom_up - dirty a znode and its ancestors.
- * @c: UBIFS file-system description object
- * @znode: znode to dirty
- *
- * If we do not have a unique key that resides in a znode, then we cannot
- * dirty that znode from the top down (i.e. by using lookup_level0_dirty)
- * This function records the path back to the last dirty ancestor, and then
- * dirties the znodes on that path.
- */
-static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
- struct ubifs_znode *znode)
-{
- struct ubifs_znode *zp;
- int *path = c->bottom_up_buf, p = 0;
-
- ubifs_assert(c->zroot.znode);
- ubifs_assert(znode);
- if (c->zroot.znode->level > BOTTOM_UP_HEIGHT) {
- kfree(c->bottom_up_buf);
- c->bottom_up_buf = kmalloc(c->zroot.znode->level * sizeof(int),
- GFP_NOFS);
- if (!c->bottom_up_buf)
- return ERR_PTR(-ENOMEM);
- path = c->bottom_up_buf;
- }
- if (c->zroot.znode->level) {
- /* Go up until parent is dirty */
- while (1) {
- int n;
-
- zp = znode->parent;
- if (!zp)
- break;
- n = znode->iip;
- ubifs_assert(p < c->zroot.znode->level);
- path[p++] = n;
- if (!zp->cnext && ubifs_zn_dirty(znode))
- break;
- znode = zp;
- }
- }
-
- /* Come back down, dirtying as we go */
- while (1) {
- struct ubifs_zbranch *zbr;
-
- zp = znode->parent;
- if (zp) {
- ubifs_assert(path[p - 1] >= 0);
- ubifs_assert(path[p - 1] < zp->child_cnt);
- zbr = &zp->zbranch[path[--p]];
- znode = dirty_cow_znode(c, zbr);
- } else {
- ubifs_assert(znode == c->zroot.znode);
- znode = dirty_cow_znode(c, &c->zroot);
- }
- if (IS_ERR(znode) || !p)
- break;
- ubifs_assert(path[p - 1] >= 0);
- ubifs_assert(path[p - 1] < znode->child_cnt);
- znode = znode->zbranch[path[p - 1]].znode;
- }
-
- return znode;
-}
-
/**
* ubifs_lookup_level0 - search for zero-level znode.
* @c: UBIFS file-system description object
@@ -1361,12 +1118,6 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
return 0;
}
- if (znode->cnext || !ubifs_zn_dirty(znode)) {
- znode = dirty_cow_bottom_up(c, znode);
- if (IS_ERR(znode))
- return PTR_ERR(znode);
- }
-
dbg_tnc("found 1, lvl %d, n %d", znode->level, *n);
*zn = znode;
return 1;
@@ -1384,31 +1135,7 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
*/
static int maybe_leb_gced(struct ubifs_info *c, int lnum, int gc_seq1)
{
-#ifndef __BAREBOX__
- int gc_seq2, gced_lnum;
-
- gced_lnum = c->gced_lnum;
- smp_rmb();
- gc_seq2 = c->gc_seq;
- /* Same seq means no GC */
- if (gc_seq1 == gc_seq2)
- return 0;
- /* Different by more than 1 means we don't know */
- if (gc_seq1 + 1 != gc_seq2)
- return 1;
- /*
- * We have seen the sequence number has increased by 1. Now we need to
- * be sure we read the right LEB number, so read it again.
- */
- smp_rmb();
- if (gced_lnum != c->gced_lnum)
- return 1;
- /* Finally we can check lnum */
- if (gced_lnum == lnum)
- return 1;
-#else
/* No garbage collection in the read-only U-Boot implementation */
-#endif
return 0;
}
@@ -1464,12 +1191,6 @@ again:
gc_seq1 = c->gc_seq;
mutex_unlock(&c->tnc_mutex);
- if (ubifs_get_wbuf(c, zbr.lnum)) {
- /* We do not GC journal heads */
- err = ubifs_tnc_read_node(c, &zbr, node);
- return err;
- }
-
err = fallible_read_node(c, key, &zbr, node);
if (err <= 0 || maybe_leb_gced(c, zbr.lnum, gc_seq1)) {
/*
@@ -1486,294 +1207,6 @@ out:
return err;
}
-/**
- * ubifs_tnc_get_bu_keys - lookup keys for bulk-read.
- * @c: UBIFS file-system description object
- * @bu: bulk-read parameters and results
- *
- * Lookup consecutive data node keys for the same inode that reside
- * consecutively in the same LEB. This function returns zero in case of success
- * and a negative error code in case of failure.
- *
- * Note, if the bulk-read buffer length (@bu->buf_len) is known, this function
- * makes sure bulk-read nodes fit the buffer. Otherwise, this function prepares
- * maximum possible amount of nodes for bulk-read.
- */
-int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu)
-{
- int n, err = 0, lnum = -1, uninitialized_var(offs);
- int uninitialized_var(len);
- unsigned int block = key_block(c, &bu->key);
- struct ubifs_znode *znode;
-
- bu->cnt = 0;
- bu->blk_cnt = 0;
- bu->eof = 0;
-
- mutex_lock(&c->tnc_mutex);
- /* Find first key */
- err = ubifs_lookup_level0(c, &bu->key, &znode, &n);
- if (err < 0)
- goto out;
- if (err) {
- /* Key found */
- len = znode->zbranch[n].len;
- /* The buffer must be big enough for at least 1 node */
- if (len > bu->buf_len) {
- err = -EINVAL;
- goto out;
- }
- /* Add this key */
- bu->zbranch[bu->cnt++] = znode->zbranch[n];
- bu->blk_cnt += 1;
- lnum = znode->zbranch[n].lnum;
- offs = ALIGN(znode->zbranch[n].offs + len, 8);
- }
- while (1) {
- struct ubifs_zbranch *zbr;
- union ubifs_key *key;
- unsigned int next_block;
-
- /* Find next key */
- err = tnc_next(c, &znode, &n);
- if (err)
- goto out;
- zbr = &znode->zbranch[n];
- key = &zbr->key;
- /* See if there is another data key for this file */
- if (key_inum(c, key) != key_inum(c, &bu->key) ||
- key_type(c, key) != UBIFS_DATA_KEY) {
- err = -ENOENT;
- goto out;
- }
- if (lnum < 0) {
- /* First key found */
- lnum = zbr->lnum;
- offs = ALIGN(zbr->offs + zbr->len, 8);
- len = zbr->len;
- if (len > bu->buf_len) {
- err = -EINVAL;
- goto out;
- }
- } else {
- /*
- * The data nodes must be in consecutive positions in
- * the same LEB.
- */
- if (zbr->lnum != lnum || zbr->offs != offs)
- goto out;
- offs += ALIGN(zbr->len, 8);
- len = ALIGN(len, 8) + zbr->len;
- /* Must not exceed buffer length */
- if (len > bu->buf_len)
- goto out;
- }
- /* Allow for holes */
- next_block = key_block(c, key);
- bu->blk_cnt += (next_block - block - 1);
- if (bu->blk_cnt >= UBIFS_MAX_BULK_READ)
- goto out;
- block = next_block;
- /* Add this key */
- bu->zbranch[bu->cnt++] = *zbr;
- bu->blk_cnt += 1;
- /* See if we have room for more */
- if (bu->cnt >= UBIFS_MAX_BULK_READ)
- goto out;
- if (bu->blk_cnt >= UBIFS_MAX_BULK_READ)
- goto out;
- }
-out:
- if (err == -ENOENT) {
- bu->eof = 1;
- err = 0;
- }
- bu->gc_seq = c->gc_seq;
- mutex_unlock(&c->tnc_mutex);
- if (err)
- return err;
- /*
- * An enormous hole could cause bulk-read to encompass too many
- * page cache pages, so limit the number here.
- */
- if (bu->blk_cnt > UBIFS_MAX_BULK_READ)
- bu->blk_cnt = UBIFS_MAX_BULK_READ;
- /*
- * Ensure that bulk-read covers a whole number of page cache
- * pages.
- */
- if (UBIFS_BLOCKS_PER_PAGE == 1 ||
- !(bu->blk_cnt & (UBIFS_BLOCKS_PER_PAGE - 1)))
- return 0;
- if (bu->eof) {
- /* At the end of file we can round up */
- bu->blk_cnt += UBIFS_BLOCKS_PER_PAGE - 1;
- return 0;
- }
- /* Exclude data nodes that do not make up a whole page cache page */
- block = key_block(c, &bu->key) + bu->blk_cnt;
- block &= ~(UBIFS_BLOCKS_PER_PAGE - 1);
- while (bu->cnt) {
- if (key_block(c, &bu->zbranch[bu->cnt - 1].key) < block)
- break;
- bu->cnt -= 1;
- }
- return 0;
-}
-
-/**
- * read_wbuf - bulk-read from a LEB with a wbuf.
- * @wbuf: wbuf that may overlap the read
- * @buf: buffer into which to read
- * @len: read length
- * @lnum: LEB number from which to read
- * @offs: offset from which to read
- *
- * This functions returns %0 on success or a negative error code on failure.
- */
-static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
- int offs)
-{
- const struct ubifs_info *c = wbuf->c;
- int rlen, overlap;
-
- dbg_io("LEB %d:%d, length %d", lnum, offs, len);
- ubifs_assert(wbuf && lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
- ubifs_assert(!(offs & 7) && offs < c->leb_size);
- ubifs_assert(offs + len <= c->leb_size);
-
- spin_lock(&wbuf->lock);
- overlap = (lnum == wbuf->lnum && offs + len > wbuf->offs);
- if (!overlap) {
- /* We may safely unlock the write-buffer and read the data */
- spin_unlock(&wbuf->lock);
- return ubifs_leb_read(c, lnum, buf, offs, len, 0);
- }
-
- /* Don't read under wbuf */
- rlen = wbuf->offs - offs;
- if (rlen < 0)
- rlen = 0;
-
- /* Copy the rest from the write-buffer */
- memcpy(buf + rlen, wbuf->buf + offs + rlen - wbuf->offs, len - rlen);
- spin_unlock(&wbuf->lock);
-
- if (rlen > 0)
- /* Read everything that goes before write-buffer */
- return ubifs_leb_read(c, lnum, buf, offs, rlen, 0);
-
- return 0;
-}
-
-/**
- * validate_data_node - validate data nodes for bulk-read.
- * @c: UBIFS file-system description object
- * @buf: buffer containing data node to validate
- * @zbr: zbranch of data node to validate
- *
- * This functions returns %0 on success or a negative error code on failure.
- */
-static int validate_data_node(struct ubifs_info *c, void *buf,
- struct ubifs_zbranch *zbr)
-{
- union ubifs_key key1;
- struct ubifs_ch *ch = buf;
- int err, len;
-
- if (ch->node_type != UBIFS_DATA_NODE) {
- ubifs_err(c, "bad node type (%d but expected %d)",
- ch->node_type, UBIFS_DATA_NODE);
- goto out_err;
- }
-
- err = ubifs_check_node(c, buf, zbr->lnum, zbr->offs, 0, 0);
- if (err) {
- ubifs_err(c, "expected node type %d", UBIFS_DATA_NODE);
- goto out;
- }
-
- len = le32_to_cpu(ch->len);
- if (len != zbr->len) {
- ubifs_err(c, "bad node length %d, expected %d", len, zbr->len);
- goto out_err;
- }
-
- /* Make sure the key of the read node is correct */
- key_read(c, buf + UBIFS_KEY_OFFSET, &key1);
- if (!keys_eq(c, &zbr->key, &key1)) {
- ubifs_err(c, "bad key in node at LEB %d:%d",
- zbr->lnum, zbr->offs);
- dbg_tnck(&zbr->key, "looked for key ");
- dbg_tnck(&key1, "found node's key ");
- goto out_err;
- }
-
- return 0;
-
-out_err:
- err = -EINVAL;
-out:
- ubifs_err(c, "bad node at LEB %d:%d", zbr->lnum, zbr->offs);
- ubifs_dump_node(c, buf);
- dump_stack();
- return err;
-}
-
-/**
- * ubifs_tnc_bulk_read - read a number of data nodes in one go.
- * @c: UBIFS file-system description object
- * @bu: bulk-read parameters and results
- *
- * This functions reads and validates the data nodes that were identified by the
- * 'ubifs_tnc_get_bu_keys()' function. This functions returns %0 on success,
- * -EAGAIN to indicate a race with GC, or another negative error code on
- * failure.
- */
-int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
-{
- int lnum = bu->zbranch[0].lnum, offs = bu->zbranch[0].offs, len, err, i;
- struct ubifs_wbuf *wbuf;
- void *buf;
-
- len = bu->zbranch[bu->cnt - 1].offs;
- len += bu->zbranch[bu->cnt - 1].len - offs;
- if (len > bu->buf_len) {
- ubifs_err(c, "buffer too small %d vs %d", bu->buf_len, len);
- return -EINVAL;
- }
-
- /* Do the read */
- wbuf = ubifs_get_wbuf(c, lnum);
- if (wbuf)
- err = read_wbuf(wbuf, bu->buf, len, lnum, offs);
- else
- err = ubifs_leb_read(c, lnum, bu->buf, offs, len, 0);
-
- /* Check for a race with GC */
- if (maybe_leb_gced(c, lnum, bu->gc_seq))
- return -EAGAIN;
-
- if (err && err != -EBADMSG) {
- ubifs_err(c, "failed to read from LEB %d:%d, error %d",
- lnum, offs, err);
- dump_stack();
- dbg_tnck(&bu->key, "key ");
- return err;
- }
-
- /* Validate the nodes read */
- buf = bu->buf;
- for (i = 0; i < bu->cnt; i++) {
- err = validate_data_node(c, buf, &bu->zbranch[i]);
- if (err)
- return err;
- buf = buf + ALIGN(bu->zbranch[i].len, 8);
- }
-
- return 0;
-}
-
/**
* do_lookup_nm- look up a "hashed" node.
* @c: UBIFS file-system description object
@@ -1906,8 +1339,6 @@ static void insert_zbranch(struct ubifs_znode *znode,
{
int i;
- ubifs_assert(ubifs_zn_dirty(znode));
-
if (znode->level) {
for (i = znode->child_cnt; i > n; i--) {
znode->zbranch[i] = znode->zbranch[i - 1];
@@ -2180,91 +1611,6 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
return err;
}
-/**
- * ubifs_tnc_replace - replace a node in the TNC only if the old node is found.
- * @c: UBIFS file-system description object
- * @key: key to add
- * @old_lnum: LEB number of old node
- * @old_offs: old node offset
- * @lnum: LEB number of node
- * @offs: node offset
- * @len: node length
- *
- * This function replaces a node with key @key in the TNC only if the old node
- * is found. This function is called by garbage collection when node are moved.
- * Returns %0 on success or negative error code on failure.
- */
-int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
- int old_lnum, int old_offs, int lnum, int offs, int len)
-{
- int found, n, err = 0;
- struct ubifs_znode *znode;
-
- mutex_lock(&c->tnc_mutex);
- dbg_tnck(key, "old LEB %d:%d, new LEB %d:%d, len %d, key ", old_lnum,
- old_offs, lnum, offs, len);
- found = lookup_level0_dirty(c, key, &znode, &n);
- if (found < 0) {
- err = found;
- goto out_unlock;
- }
-
- if (found == 1) {
- struct ubifs_zbranch *zbr = &znode->zbranch[n];
-
- found = 0;
- if (zbr->lnum == old_lnum && zbr->offs == old_offs) {
- lnc_free(zbr);
- err = ubifs_add_dirt(c, zbr->lnum, zbr->len);
- if (err)
- goto out_unlock;
- zbr->lnum = lnum;
- zbr->offs = offs;
- zbr->len = len;
- found = 1;
- } else if (is_hash_key(c, key)) {
- found = resolve_collision_directly(c, key, &znode, &n,
- old_lnum, old_offs);
- dbg_tnc("rc returned %d, znode %p, n %d, LEB %d:%d",
- found, znode, n, old_lnum, old_offs);
- if (found < 0) {
- err = found;
- goto out_unlock;
- }
-
- if (found) {
- /* Ensure the znode is dirtied */
- if (znode->cnext || !ubifs_zn_dirty(znode)) {
- znode = dirty_cow_bottom_up(c, znode);
- if (IS_ERR(znode)) {
- err = PTR_ERR(znode);
- goto out_unlock;
- }
- }
- zbr = &znode->zbranch[n];
- lnc_free(zbr);
- err = ubifs_add_dirt(c, zbr->lnum,
- zbr->len);
- if (err)
- goto out_unlock;
- zbr->lnum = lnum;
- zbr->offs = offs;
- zbr->len = len;
- }
- }
- }
-
- if (!found)
- err = ubifs_add_dirt(c, lnum, len);
-
- if (!err)
- err = dbg_check_tnc(c, 0);
-
-out_unlock:
- mutex_unlock(&c->tnc_mutex);
- return err;
-}
-
/**
* ubifs_tnc_add_nm - add a "hashed" node to TNC.
* @c: UBIFS file-system description object
@@ -2304,15 +1650,6 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
goto out_unlock;
}
- /* Ensure the znode is dirtied */
- if (znode->cnext || !ubifs_zn_dirty(znode)) {
- znode = dirty_cow_bottom_up(c, znode);
- if (IS_ERR(znode)) {
- err = PTR_ERR(znode);
- goto out_unlock;
- }
- }
-
if (found == 1) {
struct ubifs_zbranch *zbr = &znode->zbranch[n];
@@ -2533,17 +1870,8 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
if (err < 0)
goto out_unlock;
- if (err) {
- /* Ensure the znode is dirtied */
- if (znode->cnext || !ubifs_zn_dirty(znode)) {
- znode = dirty_cow_bottom_up(c, znode);
- if (IS_ERR(znode)) {
- err = PTR_ERR(znode);
- goto out_unlock;
- }
- }
+ if (err)
err = tnc_delete(c, znode, n);
- }
}
out_unlock:
@@ -2613,15 +1941,6 @@ int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
}
}
- /* Ensure the znode is dirtied */
- if (znode->cnext || !ubifs_zn_dirty(znode)) {
- znode = dirty_cow_bottom_up(c, znode);
- if (IS_ERR(znode)) {
- err = PTR_ERR(znode);
- goto out_unlock;
- }
- }
-
/* Remove all keys in range except the first */
for (i = n + 1, k = 0; i < znode->child_cnt; i++, k++) {
key = &znode->zbranch[i].key;
@@ -2868,458 +2187,3 @@ void ubifs_tnc_close(struct ubifs_info *c)
kfree(c->ilebs);
destroy_old_idx(c);
}
-
-/**
- * left_znode - get the znode to the left.
- * @c: UBIFS file-system description object
- * @znode: znode
- *
- * This function returns a pointer to the znode to the left of @znode or NULL if
- * there is not one. A negative error code is returned on failure.
- */
-static struct ubifs_znode *left_znode(struct ubifs_info *c,
- struct ubifs_znode *znode)
-{
- int level = znode->level;
-
- while (1) {
- int n = znode->iip - 1;
-
- /* Go up until we can go left */
- znode = znode->parent;
- if (!znode)
- return NULL;
- if (n >= 0) {
- /* Now go down the rightmost branch to 'level' */
- znode = get_znode(c, znode, n);
- if (IS_ERR(znode))
- return znode;
- while (znode->level != level) {
- n = znode->child_cnt - 1;
- znode = get_znode(c, znode, n);
- if (IS_ERR(znode))
- return znode;
- }
- break;
- }
- }
- return znode;
-}
-
-/**
- * right_znode - get the znode to the right.
- * @c: UBIFS file-system description object
- * @znode: znode
- *
- * This function returns a pointer to the znode to the right of @znode or NULL
- * if there is not one. A negative error code is returned on failure.
- */
-static struct ubifs_znode *right_znode(struct ubifs_info *c,
- struct ubifs_znode *znode)
-{
- int level = znode->level;
-
- while (1) {
- int n = znode->iip + 1;
-
- /* Go up until we can go right */
- znode = znode->parent;
- if (!znode)
- return NULL;
- if (n < znode->child_cnt) {
- /* Now go down the leftmost branch to 'level' */
- znode = get_znode(c, znode, n);
- if (IS_ERR(znode))
- return znode;
- while (znode->level != level) {
- znode = get_znode(c, znode, 0);
- if (IS_ERR(znode))
- return znode;
- }
- break;
- }
- }
- return znode;
-}
-
-/**
- * lookup_znode - find a particular indexing node from TNC.
- * @c: UBIFS file-system description object
- * @key: index node key to lookup
- * @level: index node level
- * @lnum: index node LEB number
- * @offs: index node offset
- *
- * This function searches an indexing node by its first key @key and its
- * address @lnum:@offs. It looks up the indexing tree by pulling all indexing
- * nodes it traverses to TNC. This function is called for indexing nodes which
- * were found on the media by scanning, for example when garbage-collecting or
- * when doing in-the-gaps commit. This means that the indexing node which is
- * looked for does not have to have exactly the same leftmost key @key, because
- * the leftmost key may have been changed, in which case TNC will contain a
- * dirty znode which still refers the same @lnum:@offs. This function is clever
- * enough to recognize such indexing nodes.
- *
- * Note, if a znode was deleted or changed too much, then this function will
- * not find it. For situations like this UBIFS has the old index RB-tree
- * (indexed by @lnum:@offs).
- *
- * This function returns a pointer to the znode found or %NULL if it is not
- * found. A negative error code is returned on failure.
- */
-static struct ubifs_znode *lookup_znode(struct ubifs_info *c,
- union ubifs_key *key, int level,
- int lnum, int offs)
-{
- struct ubifs_znode *znode, *zn;
- int n, nn;
-
- ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
-
- /*
- * The arguments have probably been read off flash, so don't assume
- * they are valid.
- */
- if (level < 0)
- return ERR_PTR(-EINVAL);
-
- /* Get the root znode */
- znode = c->zroot.znode;
- if (!znode) {
- znode = ubifs_load_znode(c, &c->zroot, NULL, 0);
- if (IS_ERR(znode))
- return znode;
- }
- /* Check if it is the one we are looking for */
- if (c->zroot.lnum == lnum && c->zroot.offs == offs)
- return znode;
- /* Descend to the parent level i.e. (level + 1) */
- if (level >= znode->level)
- return NULL;
- while (1) {
- ubifs_search_zbranch(c, znode, key, &n);
- if (n < 0) {
- /*
- * We reached a znode where the leftmost key is greater
- * than the key we are searching for. This is the same
- * situation as the one described in a huge comment at
- * the end of the 'ubifs_lookup_level0()' function. And
- * for exactly the same reasons we have to try to look
- * left before giving up.
- */
- znode = left_znode(c, znode);
- if (!znode)
- return NULL;
- if (IS_ERR(znode))
- return znode;
- ubifs_search_zbranch(c, znode, key, &n);
- ubifs_assert(n >= 0);
- }
- if (znode->level == level + 1)
- break;
- znode = get_znode(c, znode, n);
- if (IS_ERR(znode))
- return znode;
- }
- /* Check if the child is the one we are looking for */
- if (znode->zbranch[n].lnum == lnum && znode->zbranch[n].offs == offs)
- return get_znode(c, znode, n);
- /* If the key is unique, there is nowhere else to look */
- if (!is_hash_key(c, key))
- return NULL;
- /*
- * The key is not unique and so may be also in the znodes to either
- * side.
- */
- zn = znode;
- nn = n;
- /* Look left */
- while (1) {
- /* Move one branch to the left */
- if (n)
- n -= 1;
- else {
- znode = left_znode(c, znode);
- if (!znode)
- break;
- if (IS_ERR(znode))
- return znode;
- n = znode->child_cnt - 1;
- }
- /* Check it */
- if (znode->zbranch[n].lnum == lnum &&
- znode->zbranch[n].offs == offs)
- return get_znode(c, znode, n);
- /* Stop if the key is less than the one we are looking for */
- if (keys_cmp(c, &znode->zbranch[n].key, key) < 0)
- break;
- }
- /* Back to the middle */
- znode = zn;
- n = nn;
- /* Look right */
- while (1) {
- /* Move one branch to the right */
- if (++n >= znode->child_cnt) {
- znode = right_znode(c, znode);
- if (!znode)
- break;
- if (IS_ERR(znode))
- return znode;
- n = 0;
- }
- /* Check it */
- if (znode->zbranch[n].lnum == lnum &&
- znode->zbranch[n].offs == offs)
- return get_znode(c, znode, n);
- /* Stop if the key is greater than the one we are looking for */
- if (keys_cmp(c, &znode->zbranch[n].key, key) > 0)
- break;
- }
- return NULL;
-}
-
-/**
- * is_idx_node_in_tnc - determine if an index node is in the TNC.
- * @c: UBIFS file-system description object
- * @key: key of index node
- * @level: index node level
- * @lnum: LEB number of index node
- * @offs: offset of index node
- *
- * This function returns %0 if the index node is not referred to in the TNC, %1
- * if the index node is referred to in the TNC and the corresponding znode is
- * dirty, %2 if an index node is referred to in the TNC and the corresponding
- * znode is clean, and a negative error code in case of failure.
- *
- * Note, the @key argument has to be the key of the first child. Also note,
- * this function relies on the fact that 0:0 is never a valid LEB number and
- * offset for a main-area node.
- */
-int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level,
- int lnum, int offs)
-{
- struct ubifs_znode *znode;
-
- znode = lookup_znode(c, key, level, lnum, offs);
- if (!znode)
- return 0;
- if (IS_ERR(znode))
- return PTR_ERR(znode);
-
- return ubifs_zn_dirty(znode) ? 1 : 2;
-}
-
-/**
- * is_leaf_node_in_tnc - determine if a non-indexing not is in the TNC.
- * @c: UBIFS file-system description object
- * @key: node key
- * @lnum: node LEB number
- * @offs: node offset
- *
- * This function returns %1 if the node is referred to in the TNC, %0 if it is
- * not, and a negative error code in case of failure.
- *
- * Note, this function relies on the fact that 0:0 is never a valid LEB number
- * and offset for a main-area node.
- */
-static int is_leaf_node_in_tnc(struct ubifs_info *c, union ubifs_key *key,
- int lnum, int offs)
-{
- struct ubifs_zbranch *zbr;
- struct ubifs_znode *znode, *zn;
- int n, found, err, nn;
- const int unique = !is_hash_key(c, key);
-
- found = ubifs_lookup_level0(c, key, &znode, &n);
- if (found < 0)
- return found; /* Error code */
- if (!found)
- return 0;
- zbr = &znode->zbranch[n];
- if (lnum == zbr->lnum && offs == zbr->offs)
- return 1; /* Found it */
- if (unique)
- return 0;
- /*
- * Because the key is not unique, we have to look left
- * and right as well
- */
- zn = znode;
- nn = n;
- /* Look left */
- while (1) {
- err = tnc_prev(c, &znode, &n);
- if (err == -ENOENT)
- break;
- if (err)
- return err;
- if (keys_cmp(c, key, &znode->zbranch[n].key))
- break;
- zbr = &znode->zbranch[n];
- if (lnum == zbr->lnum && offs == zbr->offs)
- return 1; /* Found it */
- }
- /* Look right */
- znode = zn;
- n = nn;
- while (1) {
- err = tnc_next(c, &znode, &n);
- if (err) {
- if (err == -ENOENT)
- return 0;
- return err;
- }
- if (keys_cmp(c, key, &znode->zbranch[n].key))
- break;
- zbr = &znode->zbranch[n];
- if (lnum == zbr->lnum && offs == zbr->offs)
- return 1; /* Found it */
- }
- return 0;
-}
-
-/**
- * ubifs_tnc_has_node - determine whether a node is in the TNC.
- * @c: UBIFS file-system description object
- * @key: node key
- * @level: index node level (if it is an index node)
- * @lnum: node LEB number
- * @offs: node offset
- * @is_idx: non-zero if the node is an index node
- *
- * This function returns %1 if the node is in the TNC, %0 if it is not, and a
- * negative error code in case of failure. For index nodes, @key has to be the
- * key of the first child. An index node is considered to be in the TNC only if
- * the corresponding znode is clean or has not been loaded.
- */
-int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
- int lnum, int offs, int is_idx)
-{
- int err;
-
- mutex_lock(&c->tnc_mutex);
- if (is_idx) {
- err = is_idx_node_in_tnc(c, key, level, lnum, offs);
- if (err < 0)
- goto out_unlock;
- if (err == 1)
- /* The index node was found but it was dirty */
- err = 0;
- else if (err == 2)
- /* The index node was found and it was clean */
- err = 1;
- else
- BUG_ON(err != 0);
- } else
- err = is_leaf_node_in_tnc(c, key, lnum, offs);
-
-out_unlock:
- mutex_unlock(&c->tnc_mutex);
- return err;
-}
-
-/**
- * ubifs_dirty_idx_node - dirty an index node.
- * @c: UBIFS file-system description object
- * @key: index node key
- * @level: index node level
- * @lnum: index node LEB number
- * @offs: index node offset
- *
- * This function loads and dirties an index node so that it can be garbage
- * collected. The @key argument has to be the key of the first child. This
- * function relies on the fact that 0:0 is never a valid LEB number and offset
- * for a main-area node. Returns %0 on success and a negative error code on
- * failure.
- */
-int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level,
- int lnum, int offs)
-{
- struct ubifs_znode *znode;
- int err = 0;
-
- mutex_lock(&c->tnc_mutex);
- znode = lookup_znode(c, key, level, lnum, offs);
- if (!znode)
- goto out_unlock;
- if (IS_ERR(znode)) {
- err = PTR_ERR(znode);
- goto out_unlock;
- }
- znode = dirty_cow_bottom_up(c, znode);
- if (IS_ERR(znode)) {
- err = PTR_ERR(znode);
- goto out_unlock;
- }
-
-out_unlock:
- mutex_unlock(&c->tnc_mutex);
- return err;
-}
-
-/**
- * dbg_check_inode_size - check if inode size is correct.
- * @c: UBIFS file-system description object
- * @inum: inode number
- * @size: inode size
- *
- * This function makes sure that the inode size (@size) is correct and it does
- * not have any pages beyond @size. Returns zero if the inode is OK, %-EINVAL
- * if it has a data page beyond @size, and other negative error code in case of
- * other errors.
- */
-int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
- loff_t size)
-{
- int err, n;
- union ubifs_key from_key, to_key, *key;
- struct ubifs_znode *znode;
- unsigned int block;
-
- if (!S_ISREG(inode->i_mode))
- return 0;
- if (!dbg_is_chk_gen(c))
- return 0;
-
- block = (size + UBIFS_BLOCK_SIZE - 1) >> UBIFS_BLOCK_SHIFT;
- data_key_init(c, &from_key, inode->i_ino, block);
- highest_data_key(c, &to_key, inode->i_ino);
-
- mutex_lock(&c->tnc_mutex);
- err = ubifs_lookup_level0(c, &from_key, &znode, &n);
- if (err < 0)
- goto out_unlock;
-
- if (err) {
- key = &from_key;
- goto out_dump;
- }
-
- err = tnc_next(c, &znode, &n);
- if (err == -ENOENT) {
- err = 0;
- goto out_unlock;
- }
- if (err < 0)
- goto out_unlock;
-
- ubifs_assert(err == 0);
- key = &znode->zbranch[n].key;
- if (!key_in_range(c, key, &from_key, &to_key))
- goto out_unlock;
-
-out_dump:
- block = key_block(c, key);
- ubifs_err(c, "inode %lu has size %lld, but there are data at offset %lld",
- (unsigned long)inode->i_ino, size,
- ((loff_t)block) << UBIFS_BLOCK_SHIFT);
- mutex_unlock(&c->tnc_mutex);
- ubifs_dump_inode(c, inode);
- dump_stack();
- return -EINVAL;
-
-out_unlock:
- mutex_unlock(&c->tnc_mutex);
- return err;
-}
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
index 21da709bac..1619d08be8 100644
--- a/fs/ubifs/tnc_misc.c
+++ b/fs/ubifs/tnc_misc.c
@@ -16,9 +16,7 @@
* putting it all in one file would make that file too big and unreadable.
*/
-#ifdef __BAREBOX__
#include <linux/err.h>
-#endif
#include "ubifs.h"
/**
@@ -452,19 +450,9 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
{
union ubifs_key key1, *key = &zbr->key;
int err, type = key_type(c, key);
- struct ubifs_wbuf *wbuf;
- /*
- * 'zbr' has to point to on-flash node. The node may sit in a bud and
- * may even be in a write buffer, so we have to take care about this.
- */
- wbuf = ubifs_get_wbuf(c, zbr->lnum);
- if (wbuf)
- err = ubifs_read_node_wbuf(wbuf, node, type, zbr->len,
- zbr->lnum, zbr->offs);
- else
- err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum,
- zbr->offs);
+ err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum,
+ zbr->offs);
if (err) {
dbg_tnck(key, "key ");
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index 2ccd149b7a..3462249848 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -524,11 +524,7 @@ struct ubifs_dent_node {
__u8 type;
__le16 nlen;
__u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
-#ifndef __BAREBOX__
- __u8 name[];
-#else
char name[];
-#endif
} __packed;
/**
@@ -735,11 +731,7 @@ struct ubifs_branch {
__le32 lnum;
__le32 offs;
__le32 len;
-#ifndef __BAREBOX__
- __u8 key[];
-#else
char key[];
-#endif
} __packed;
/**
@@ -753,11 +745,7 @@ struct ubifs_idx_node {
struct ubifs_ch ch;
__le16 child_cnt;
__le16 level;
-#ifndef __BAREBOX__
- __u8 branches[];
-#else
char branches[];
-#endif
} __packed;
/**
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index 97cbe4991f..99612732dd 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -56,9 +56,6 @@ static struct ubifs_compressor none_compr = {
static struct ubifs_compressor lzo_compr = {
.compr_type = UBIFS_COMPR_LZO,
-#ifndef __BAREBOX__
- .comp_mutex = &lzo_mutex,
-#endif
.name = "lzo",
#ifdef CONFIG_LZO_DECOMPRESS
.capi_name = "lzo",
@@ -68,10 +65,6 @@ static struct ubifs_compressor lzo_compr = {
static struct ubifs_compressor zlib_compr = {
.compr_type = UBIFS_COMPR_ZLIB,
-#ifndef __BAREBOX__
- .comp_mutex = &deflate_mutex,
- .decomp_mutex = &inflate_mutex,
-#endif
.name = "zlib",
#ifdef CONFIG_ZLIB
.capi_name = "deflate",
@@ -83,7 +76,6 @@ static struct ubifs_compressor zlib_compr = {
struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
-#ifdef __BAREBOX__
/* from mm/util.c */
struct crypto_comp {
@@ -146,7 +138,6 @@ crypto_comp_decompress(const struct ubifs_info *c, struct crypto_comp *tfm,
/* Global clean znode counter (for all mounted UBIFS instances) */
atomic_long_t ubifs_clean_zn_cnt;
-#endif
/**
* ubifs_decompress - decompress data.
@@ -254,11 +245,6 @@ int __init ubifs_compressors_init(void)
/* file.c */
-static inline void *kmap(struct page *page)
-{
- return page->addr;
-}
-
static int read_block(struct inode *inode, void *addr, unsigned int block,
struct ubifs_data_node *dn)
{
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index d11f213c06..b3ad054ba7 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -15,23 +15,6 @@
#ifndef __UBIFS_H__
#define __UBIFS_H__
-#ifndef __BAREBOX__
-#include <asm/div64.h>
-#include <linux/statfs.h>
-#include <linux/fs.h>
-#include <linux/err.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/rwsem.h>
-#include <linux/mtd/ubi.h>
-#include <linux/pagemap.h>
-#include <linux/backing-dev.h>
-#include <linux/security.h>
-#include "ubifs-media.h"
-#else
#include <common.h>
#include <lzo.h>
#include <crc.h>
@@ -53,23 +36,7 @@
struct file;
struct iattr;
struct kstat;
-
-extern struct super_block *ubifs_sb;
-
-extern unsigned int ubifs_msg_flags;
-extern unsigned int ubifs_chk_flags;
-extern unsigned int ubifs_tst_flags;
-
-#define pgoff_t unsigned long
-
-/*
- * We "simulate" the Linux page struct much simpler here
- */
-struct page {
- pgoff_t index;
- void *addr;
- struct inode *inode;
-};
+struct page;
/* uapi/linux/limits.h */
#define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */
@@ -81,11 +48,6 @@ struct page {
/* debug.c */
-#define module_param_named(...)
-
-/* misc.h */
-#endif
-
/* Version of this UBIFS implementation */
#define UBIFS_VERSION 1
@@ -94,17 +56,6 @@ struct page {
pr_notice("UBIFS (ubi%d:%d): " fmt "\n", \
(c)->vi.ubi_num, (c)->vi.vol_id, ##__VA_ARGS__)
/* UBIFS error messages */
-#ifndef __BAREBOX__
-#define ubifs_err(c, fmt, ...) \
- pr_err("UBIFS error (ubi%d:%d pid %d): %s: " fmt "\n", \
- (c)->vi.ubi_num, (c)->vi.vol_id, current->pid, \
- __func__, ##__VA_ARGS__)
-/* UBIFS warning messages */
-#define ubifs_warn(c, fmt, ...) \
- pr_warn("UBIFS warning (ubi%d:%d pid %d): %s: " fmt "\n", \
- (c)->vi.ubi_num, (c)->vi.vol_id, current->pid, \
- __func__, ##__VA_ARGS__)
-#else
#define ubifs_err(c, fmt, ...) \
pr_err("UBIFS error (ubi%d:%d pid %d): %s: " fmt "\n", \
(c)->vi.ubi_num, (c)->vi.vol_id, 0, \
@@ -114,7 +65,6 @@ struct page {
pr_warn("UBIFS warning (ubi%d:%d pid %d): %s: " fmt "\n", \
(c)->vi.ubi_num, (c)->vi.vol_id, 0, \
__func__, ##__VA_ARGS__)
-#endif
/*
* A variant of 'ubifs_err()' which takes the UBIFS file-sytem description
@@ -903,10 +853,8 @@ struct ubifs_compressor {
struct mutex *decomp_mutex;
const char *name;
const char *capi_name;
-#ifdef __BAREBOX__
int (*decompress)(const unsigned char *in, size_t in_len,
unsigned char *out, size_t *out_len);
-#endif
};
/**
@@ -1301,9 +1249,6 @@ struct ubifs_debug_info;
*/
struct ubifs_info {
struct super_block *vfs_sb;
-#ifndef __BAREBOX__
- struct backing_dev_info bdi;
-#endif
ino_t highest_inum;
unsigned long long max_sqnum;
unsigned long long cmt_no;
@@ -1527,12 +1472,7 @@ struct ubifs_info {
struct rb_root size_tree;
struct ubifs_mount_opts mount_opts;
-#ifndef __BAREBOX__
- struct ubifs_debug_info *dbg;
-#endif
-#ifdef __BAREBOX__
struct device_d *dev;
-#endif
};
extern struct list_head ubifs_infos;
@@ -1706,13 +1646,6 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot);
int ubifs_tnc_end_commit(struct ubifs_info *c);
-#ifndef __BAREBOX__
-/* shrinker.c */
-unsigned long ubifs_shrink_scan(struct shrinker *shrink,
- struct shrink_control *sc);
-unsigned long ubifs_shrink_count(struct shrinker *shrink,
- struct shrink_control *sc);
-#endif
/* commit.c */
int ubifs_bg_thread(void *info);
@@ -1873,9 +1806,7 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
#include "misc.h"
#include "key.h"
-#ifdef __BAREBOX__
void ubifs_umount(struct ubifs_info *c);
int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent);
-#endif
#endif /* !__UBIFS_H__ */
--
2.19.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 18+ messages in thread
* [PATCH 13/14] ubifs: Update to v4.18-rc6
2018-10-02 14:03 [PATCH 00/14] UBIFS update Sascha Hauer
` (11 preceding siblings ...)
2018-10-02 14:04 ` [PATCH 12/14] vsprintf: implement %pV Sascha Hauer
@ 2018-10-02 14:04 ` Sascha Hauer
2018-10-02 14:04 ` [PATCH 14/14] fs: ubifs: optionally allow to mount UBIFS images with encrypted files Sascha Hauer
2018-10-03 20:50 ` [PATCH 00/14] UBIFS update Sam Ravnborg
14 siblings, 0 replies; 18+ messages in thread
From: Sascha Hauer @ 2018-10-02 14:04 UTC (permalink / raw)
To: Barebox List
This syncs the UBIFS code with Linux-4.19-rc6.
There are many functions in the Linux UBIFS codebase that we do not need
for a readonly implementation. These are missing here, but all removed
functions are annotated as such so it should be relatively easy to copy
a newer codebase over the current one and to see which functions shall
be removed from the newer version.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
fs/ubifs/Makefile | 2 +-
fs/ubifs/debug.c | 429 ++++++++++++++++++++++++++++-------------
fs/ubifs/debug.h | 50 +++--
fs/ubifs/dir.c | 298 +++++++++++++++++++++++-----
fs/ubifs/io.c | 129 ++++++++++++-
fs/ubifs/key.h | 53 +++--
fs/ubifs/log.c | 81 +++++++-
fs/ubifs/lpt_commit.c | 269 +++++++++++++++++++++++++-
fs/ubifs/master.c | 19 +-
fs/ubifs/misc.c | 69 +++++++
fs/ubifs/misc.h | 41 ++--
fs/ubifs/recovery.c | 81 ++++++--
fs/ubifs/replay.c | 65 +++++--
fs/ubifs/sb.c | 81 +++++++-
fs/ubifs/scan.c | 17 +-
fs/ubifs/super.c | 254 +++++++++++++++++-------
fs/ubifs/tnc.c | 410 +++++++++++++++++++++++++++++++--------
fs/ubifs/tnc_misc.c | 54 ++++--
fs/ubifs/ubifs-media.h | 48 +++--
fs/ubifs/ubifs.c | 4 +-
fs/ubifs/ubifs.h | 243 +++++++++++++++--------
21 files changed, 2147 insertions(+), 550 deletions(-)
create mode 100644 fs/ubifs/misc.c
diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile
index b8f47e77f2..7d376dab0d 100644
--- a/fs/ubifs/Makefile
+++ b/fs/ubifs/Makefile
@@ -1,4 +1,4 @@
obj-y += ubifs.o io.o super.o sb.o master.o
-obj-y += lpt_commit.o scan.o dir.o
+obj-y += scan.o dir.o misc.o
obj-y += tnc.o tnc_misc.o debug.o crc16.o
obj-y += log.o recovery.o replay.o
diff --git a/fs/ubifs/debug.c b/fs/ubifs/debug.c
index 3077339773..4e3f32898f 100644
--- a/fs/ubifs/debug.c
+++ b/fs/ubifs/debug.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -19,7 +30,6 @@
#include <linux/err.h>
#include "ubifs.h"
-
static const char *get_key_fmt(int fmt)
{
switch (fmt) {
@@ -60,6 +70,10 @@ static const char *get_key_type(int type)
}
}
+/*
+ * removed in barebox
+static const char *get_dent_type(int type)
+ */
const char *dbg_snprintf_key(const struct ubifs_info *c,
const union ubifs_key *key, char *buffer, int len)
@@ -96,7 +110,7 @@ const char *dbg_snprintf_key(const struct ubifs_info *c,
}
} else
len -= snprintf(p, len, "bad key format %d", c->key_fmt);
- ubifs_assert(len > 0);
+ ubifs_assert(c, len > 0);
return p;
}
@@ -195,6 +209,7 @@ static void dump_ch(const struct ubifs_ch *ch)
void ubifs_dump_inode(struct ubifs_info *c, const struct inode *inode)
{
+ /* removed in barebox */
}
void ubifs_dump_node(const struct ubifs_info *c, const void *node)
@@ -363,7 +378,8 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node)
pr_err("(bad name length, not printing, bad or corrupted node)");
else {
for (i = 0; i < nlen && dent->name[i]; i++)
- pr_cont("%c", dent->name[i]);
+ pr_cont("%c", isprint(dent->name[i]) ?
+ dent->name[i] : '?');
}
pr_cont("\n");
@@ -444,171 +460,310 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node)
spin_unlock(&dbg_lock);
}
+/*
+ * removed in barebox
+void ubifs_dump_budget_req(const struct ubifs_budget_req *req)
+ */
+
+/*
+ * removed in barebox
+void ubifs_dump_lstats(const struct ubifs_lp_stats *lst)
+ */
+
+/*
+ * removed in barebox
void ubifs_dump_budg(struct ubifs_info *c, const struct ubifs_budg_info *bi)
-{
-}
+ */
+
+/*
+ * removed in barebox
+void ubifs_dump_lprop(const struct ubifs_info *c, const struct ubifs_lprops *lp)
+ */
+
+/*
+ * removed in barebox
+void ubifs_dump_lprops(struct ubifs_info *c)
+ */
+/*
+ * removed in barebox
+void ubifs_dump_lpt_info(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
void ubifs_dump_sleb(const struct ubifs_info *c,
const struct ubifs_scan_leb *sleb, int offs)
-{
- struct ubifs_scan_node *snod;
+ */
- pr_err("(pid %d) start dumping scanned data from LEB %d:%d\n",
- 0, sleb->lnum, offs);
+/*
+ * removed in barebox
+void ubifs_dump_leb(const struct ubifs_info *c, int lnum)
+ */
- list_for_each_entry(snod, &sleb->nodes, list) {
- cond_resched();
- pr_err("Dumping node at LEB %d:%d len %d\n",
- sleb->lnum, snod->offs, snod->len);
- ubifs_dump_node(c, snod->node);
- }
-}
+/*
+ * removed in barebox
+void ubifs_dump_znode(const struct ubifs_info *c,
+ const struct ubifs_znode *znode)
+ */
-void ubifs_dump_leb(const struct ubifs_info *c, int lnum)
-{
- struct ubifs_scan_leb *sleb;
- struct ubifs_scan_node *snod;
- void *buf;
- pr_err("(pid %d) start dumping LEB %d\n", 0, lnum);
+/*
+ * removed in barebox
+void ubifs_dump_heap(struct ubifs_info *c, struct ubifs_lpt_heap *heap, int cat)
+ */
- buf = __vmalloc(c->leb_size, GFP_NOFS, PAGE_KERNEL);
- if (!buf) {
- ubifs_err(c, "cannot allocate memory for dumping LEB %d", lnum);
- return;
- }
+/*
+ * removed in barebox
+void ubifs_dump_pnode(struct ubifs_info *c, struct ubifs_pnode *pnode,
+ struct ubifs_nnode *parent, int iip)
+ */
- sleb = ubifs_scan(c, lnum, 0, buf, 0);
- if (IS_ERR(sleb)) {
- ubifs_err(c, "scan error %d", (int)PTR_ERR(sleb));
- goto out;
- }
+/*
+ * removed in barebox
+void ubifs_dump_tnc(struct ubifs_info *c)
+ */
- pr_err("LEB %d has %d nodes ending at %d\n", lnum,
- sleb->nodes_cnt, sleb->endpt);
- list_for_each_entry(snod, &sleb->nodes, list) {
- cond_resched();
- pr_err("Dumping node at LEB %d:%d len %d\n", lnum,
- snod->offs, snod->len);
- ubifs_dump_node(c, snod->node);
- }
+/*
+ * removed in barebox
+static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
+ void *priv)
+ */
- pr_err("(pid %d) finish dumping LEB %d\n", 0, lnum);
- ubifs_scan_destroy(sleb);
+/*
+ * removed in barebox
+void ubifs_dump_index(struct ubifs_info *c)
+ */
-out:
- vfree(buf);
- return;
-}
+/*
+ * removed in barebox
+void dbg_save_space_info(struct ubifs_info *c)
+ */
-void ubifs_dump_znode(const struct ubifs_info *c,
- const struct ubifs_znode *znode)
-{
- int n;
- const struct ubifs_zbranch *zbr;
- char key_buf[DBG_KEY_BUF_LEN];
+/*
+ * removed in barebox
+int dbg_check_space_info(struct ubifs_info *c)
+ */
- spin_lock(&dbg_lock);
- if (znode->parent)
- zbr = &znode->parent->zbranch[znode->iip];
- else
- zbr = &c->zroot;
+/*
+ * removed in barebox
+int dbg_check_synced_i_size(const struct ubifs_info *c, struct inode *inode)
+ */
- pr_err("znode %p, LEB %d:%d len %d parent %p iip %d level %d child_cnt %d flags %lx\n",
- znode, zbr->lnum, zbr->offs, zbr->len, znode->parent, znode->iip,
- znode->level, znode->child_cnt, znode->flags);
+/*
+ * removed in barebox
+int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
+ */
- if (znode->child_cnt <= 0 || znode->child_cnt > c->fanout) {
- spin_unlock(&dbg_lock);
- return;
- }
+/*
+ * removed in barebox
+static int dbg_check_key_order(struct ubifs_info *c, struct ubifs_zbranch *zbr1,
+ struct ubifs_zbranch *zbr2)
+ */
- pr_err("zbranches:\n");
- for (n = 0; n < znode->child_cnt; n++) {
- zbr = &znode->zbranch[n];
- if (znode->level > 0)
- pr_err("\t%d: znode %p LEB %d:%d len %d key %s\n",
- n, zbr->znode, zbr->lnum, zbr->offs, zbr->len,
- dbg_snprintf_key(c, &zbr->key, key_buf,
- DBG_KEY_BUF_LEN));
- else
- pr_err("\t%d: LNC %p LEB %d:%d len %d key %s\n",
- n, zbr->znode, zbr->lnum, zbr->offs, zbr->len,
- dbg_snprintf_key(c, &zbr->key, key_buf,
- DBG_KEY_BUF_LEN));
- }
- spin_unlock(&dbg_lock);
-}
+/*
+ * removed in barebox
+static int dbg_check_znode(struct ubifs_info *c, struct ubifs_zbranch *zbr)
+ */
-void ubifs_dump_tnc(struct ubifs_info *c)
+int dbg_check_tnc(struct ubifs_info *c, int extra)
{
- struct ubifs_znode *znode;
- int level;
-
- pr_err("\n");
- pr_err("(pid %d) start dumping TNC tree\n", 0);
- znode = ubifs_tnc_levelorder_next(c->zroot.znode, NULL);
- level = znode->level;
- pr_err("== Level %d ==\n", level);
- while (znode) {
- if (level != znode->level) {
- level = znode->level;
- pr_err("== Level %d ==\n", level);
- }
- ubifs_dump_znode(c, znode);
- znode = ubifs_tnc_levelorder_next(c->zroot.znode, znode);
- }
- pr_err("(pid %d) finish dumping TNC tree\n", 0);
+ return 0;
}
-static int dump_znode(struct ubifs_info *c, struct ubifs_znode *znode,
+/*
+ * removed in barebox
+int dbg_walk_index(struct ubifs_info *c, dbg_leaf_callback leaf_cb,
+ dbg_znode_callback znode_cb, void *priv)
+ */
+
+/*
+ * removed in barebox
+static int add_size(struct ubifs_info *c, struct ubifs_znode *znode, void *priv)
+ */
+
+/*
+ * removed in barebox
+int dbg_check_idx_size(struct ubifs_info *c, long long idx_size)
+ */
+
+/*
+ * removed in barebox
+static struct fsck_inode *add_inode(struct ubifs_info *c,
+ struct fsck_data *fsckd,
+ struct ubifs_ino_node *ino)
+ */
+
+/*
+ * removed in barebox
+static struct fsck_inode *search_inode(struct fsck_data *fsckd, ino_t inum)
+ */
+
+/*
+ * removed in barebox
+static struct fsck_inode *read_add_inode(struct ubifs_info *c,
+ struct fsck_data *fsckd, ino_t inum)
+ */
+
+/*
+ * removed in barebox
+static int check_leaf(struct ubifs_info *c, struct ubifs_zbranch *zbr,
void *priv)
-{
- ubifs_dump_znode(c, znode);
- return 0;
-}
+ */
-/**
- * ubifs_dump_index - dump the on-flash index.
- * @c: UBIFS file-system description object
- *
- * This function dumps whole UBIFS indexing B-tree, unlike 'ubifs_dump_tnc()'
- * which dumps only in-memory znodes and does not read znodes which from flash.
+/*
+ * removed in barebox
+static void free_inodes(struct fsck_data *fsckd)
*/
-void ubifs_dump_index(struct ubifs_info *c)
-{
- dbg_walk_index(c, NULL, dump_znode, NULL);
-}
-int dbg_check_dir(struct ubifs_info *c, const struct inode *dir)
-{
- return 0;
-}
+/*
+ * removed in barebox
+static int check_inodes(struct ubifs_info *c, struct fsck_data *fsckd)
+ */
+
+/*
+ * removed in barebox
+int dbg_check_filesystem(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int dbg_check_data_nodes_order(struct ubifs_info *c, struct list_head *head)
+ */
+
+/*
+ * removed in barebox
+int dbg_check_nondata_nodes_order(struct ubifs_info *c, struct list_head *head)
+ */
+
+/*
+ * removed in barebox
+static inline int chance(unsigned int n, unsigned int out_of)
+ */
+
+/*
+ * removed in barebox
+static int power_cut_emulated(struct ubifs_info *c, int lnum, int write)
+ */
+
+/*
+ * removed in barebox
+static int corrupt_data(const struct ubifs_info *c, const void *buf,
+ unsigned int len)
+ */
+
+/*
+ * removed in barebox
+ int dbg_leb_write(struct ubifs_info *c, int lnum, const void *buf,
+ int offs, int len)
+ */
+
+/*
+ * removed in barebox
+int dbg_leb_change(struct ubifs_info *c, int lnum, const void *buf,
+ int len)
+ */
+
+/*
+ * removed in barebox
+int dbg_leb_unmap(struct ubifs_info *c, int lnum)
+ */
+
+/*
+ * removed in barebox
+int dbg_leb_map(struct ubifs_info *c, int lnum)
+ */
+
+/*
+ * removed in barebox
+static int dfs_file_open(struct inode *inode, struct file *file)
+ */
+
+/*
+ * removed in barebox
+static int provide_user_output(int val, char __user *u, size_t count,
+ loff_t *ppos)
+ */
+
+/*
+ * removed in barebox
+static ssize_t dfs_file_read(struct file *file, char __user *u, size_t count,
+ loff_t *ppos)
+ */
+
+/*
+ * removed in barebox
+static int interpret_user_input(const char __user *u, size_t count)
+ */
+/*
+ * removed in barebox
+static ssize_t dfs_file_write(struct file *file, const char __user *u,
+ size_t count, loff_t *ppos)
+ */
+
+/*
+ * removed in barebox
+int dbg_debugfs_init_fs(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
void dbg_debugfs_exit_fs(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static ssize_t dfs_global_file_read(struct file *file, char __user *u,
+ size_t count, loff_t *ppos)
+ */
+
+/*
+ * removed in barebox
+static ssize_t dfs_global_file_write(struct file *file, const char __user *u,
+ size_t count, loff_t *ppos)
+ */
+
+/*
+ * removed in barebox
+int dbg_debugfs_init(void)
+ */
+
+/*
+ * removed in barebox
+void dbg_debugfs_exit(void)
+ */
+
+void ubifs_assert_failed(struct ubifs_info *c, const char *expr,
+ const char *file, int line)
{
- return;
+ ubifs_err(c, "UBIFS assert failed: %s, in %s:%u", expr, file, line);
+
+ switch (c->assert_action) {
+ case ASSACT_PANIC:
+ BUG();
+ break;
+
+ case ASSACT_RO:
+ ubifs_ro_mode(c, -EINVAL);
+ break;
+
+ case ASSACT_REPORT:
+ default:
+ dump_stack();
+ break;
+
+ }
}
+/*
+ * removed in barebox
int ubifs_debugging_init(struct ubifs_info *c)
-{
- return 0;
-}
-void ubifs_debugging_exit(struct ubifs_info *c)
-{
-}
-int dbg_check_filesystem(struct ubifs_info *c)
-{
- return 0;
-}
-int dbg_debugfs_init_fs(struct ubifs_info *c)
-{
- return 0;
-}
+ */
-int dbg_check_tnc(struct ubifs_info *c, int extra)
-{
- return 0;
-}
+/*
+ * removed in barebox
+void ubifs_debugging_exit(struct ubifs_info *c)
+ */
diff --git a/fs/ubifs/debug.h b/fs/ubifs/debug.h
index 9afb16d897..a1df0681a8 100644
--- a/fs/ubifs/debug.h
+++ b/fs/ubifs/debug.h
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -137,41 +148,34 @@ struct ubifs_global_debug_info {
unsigned int tst_rcvry:1;
};
-#define ubifs_assert(expr) do { \
- if (0 && unlikely(!(expr))) { \
- pr_crit("UBIFS assert failed in %s at %u\n", \
- __func__, __LINE__); \
- dump_stack(); \
+void ubifs_assert_failed(struct ubifs_info *c, const char *expr,
+ const char *file, int line);
+
+#define ubifs_assert(c, expr) do { \
+ if (unlikely(!(expr))) { \
+ ubifs_assert_failed((struct ubifs_info *)c, #expr, __FILE__, \
+ __LINE__); \
} \
} while (0)
#define ubifs_assert_cmt_locked(c) do { \
if (unlikely(down_write_trylock(&(c)->commit_sem))) { \
up_write(&(c)->commit_sem); \
- pr_crit("commit lock is not locked!\n"); \
- ubifs_assert(0); \
+ ubifs_err(c, "commit lock is not locked!\n"); \
+ ubifs_assert(c, 0); \
} \
} while (0)
#define ubifs_dbg_msg(type, fmt, ...) \
- pr_debug("UBIFS DBG " type ": " fmt "\n", \
- ##__VA_ARGS__)
+ pr_debug("UBIFS DBG " type ": " fmt "\n", ##__VA_ARGS__)
#define DBG_KEY_BUF_LEN 48
-#if defined CONFIG_MTD_DEBUG
#define ubifs_dbg_msg_key(type, key, fmt, ...) do { \
char __tmp_key_buf[DBG_KEY_BUF_LEN]; \
pr_debug("UBIFS DBG " type ": " fmt "%s\n", \
##__VA_ARGS__, \
dbg_snprintf_key(c, key, __tmp_key_buf, DBG_KEY_BUF_LEN)); \
} while (0)
-#else
-#define ubifs_dbg_msg_key(type, key, fmt, ...) do { \
- pr_debug("UBIFS DBG\n"); \
-} while (0)
-
-#endif
-
/* General messages */
#define dbg_gen(fmt, ...) ubifs_dbg_msg("gen", fmt, ##__VA_ARGS__)
@@ -206,39 +210,47 @@ struct ubifs_global_debug_info {
/* Additional recovery messages */
#define dbg_rcvry(fmt, ...) ubifs_dbg_msg("rcvry", fmt, ##__VA_ARGS__)
+extern struct ubifs_global_debug_info ubifs_dbg;
+
static inline int dbg_is_chk_gen(const struct ubifs_info *c)
{
+ /* not present in barebox */
return 0;
}
static inline int dbg_is_chk_index(const struct ubifs_info *c)
{
+ /* not present in barebox */
return 0;
}
static inline int dbg_is_chk_orph(const struct ubifs_info *c)
{
+ /* not present in barebox */
return 0;
}
static inline int dbg_is_chk_lprops(const struct ubifs_info *c)
{
+ /* not present in barebox */
return 0;
}
static inline int dbg_is_chk_fs(const struct ubifs_info *c)
{
+ /* not present in barebox */
return 0;
}
static inline int dbg_is_tst_rcvry(const struct ubifs_info *c)
{
+ /* not present in barebox */
return 0;
}
static inline int dbg_is_power_cut(const struct ubifs_info *c)
{
+ /* not present in barebox */
return 0;
}
int ubifs_debugging_init(struct ubifs_info *c);
void ubifs_debugging_exit(struct ubifs_info *c);
-
/* Dump functions */
const char *dbg_ntype(int type);
const char *dbg_cstate(int cmt_state);
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 8c230da8f3..a16546e615 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -42,15 +42,26 @@
#include "ubifs.h"
+/*
+ * removed in barebox
+static int inherit_flags(const struct inode *dir, umode_t mode)
+ */
+
+/*
+ * removed in barebox
+struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
+ umode_t mode)
+ */
+
static int dbg_check_name(const struct ubifs_info *c,
const struct ubifs_dent_node *dent,
- const struct qstr *nm)
+ const struct fscrypt_name *nm)
{
if (!dbg_is_chk_gen(c))
return 0;
- if (le16_to_cpu(dent->nlen) != nm->len)
+ if (le16_to_cpu(dent->nlen) != fname_len(nm))
return -EINVAL;
- if (memcmp(dent->name, nm->name, nm->len))
+ if (memcmp(dent->name, fname_name(nm), fname_len(nm)))
return -EINVAL;
return 0;
}
@@ -61,32 +72,52 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
int err;
union ubifs_key key;
struct inode *inode = NULL;
- struct ubifs_dent_node *dent;
+ struct ubifs_dent_node *dent = NULL;
struct ubifs_info *c = dir->i_sb->s_fs_info;
+ struct fscrypt_name nm;
dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino);
- if (dentry->d_name.len > UBIFS_MAX_NLEN)
- return ERR_PTR(-ENAMETOOLONG);
+ err = fscrypt_prepare_lookup(dir, dentry, flags);
+ if (err)
+ return ERR_PTR(err);
+
+ err = fscrypt_setup_filename(dir, &dentry->d_name, 1, &nm);
+ if (err)
+ return ERR_PTR(err);
+
+ if (fname_len(&nm) > UBIFS_MAX_NLEN) {
+ inode = ERR_PTR(-ENAMETOOLONG);
+ goto done;
+ }
dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS);
- if (!dent)
- return ERR_PTR(-ENOMEM);
+ if (!dent) {
+ inode = ERR_PTR(-ENOMEM);
+ goto done;
+ }
- dent_key_init(c, &key, dir->i_ino, &dentry->d_name);
+ if (nm.hash) {
+ ubifs_assert(c, fname_len(&nm) == 0);
+ ubifs_assert(c, fname_name(&nm) == NULL);
+ dent_key_init_hash(c, &key, dir->i_ino, nm.hash);
+ err = ubifs_tnc_lookup_dh(c, &key, dent, nm.minor_hash);
+ } else {
+ dent_key_init(c, &key, dir->i_ino, &nm);
+ err = ubifs_tnc_lookup_nm(c, &key, dent, &nm);
+ }
- err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name);
if (err) {
- if (err == -ENOENT) {
+ if (err == -ENOENT)
dbg_gen("not found");
- goto done;
- }
- goto out;
+ else
+ inode = ERR_PTR(err);
+ goto done;
}
- if (dbg_check_name(c, dent, &dentry->d_name)) {
- err = -EINVAL;
- goto out;
+ if (dbg_check_name(c, dent, &nm)) {
+ inode = ERR_PTR(-EINVAL);
+ goto done;
}
inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum));
@@ -97,25 +128,45 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,
*/
err = PTR_ERR(inode);
ubifs_err(c, "dead directory entry '%pd', error %d",
- dentry, err);
+ dentry, err);
ubifs_ro_mode(c, err);
- goto out;
+ goto done;
+ }
+
+ if (ubifs_crypt_is_encrypted(dir) &&
+ (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) &&
+ !fscrypt_has_permitted_context(dir, inode)) {
+ ubifs_warn(c, "Inconsistent encryption contexts: %lu/%lu",
+ dir->i_ino, inode->i_ino);
+ iput(inode);
+ inode = ERR_PTR(-EPERM);
}
done:
kfree(dent);
- /*
- * Note, d_splice_alias() would be required instead if we supported
- * NFS.
- */
+ fscrypt_free_filename(&nm);
d_add(dentry, inode);
return NULL;
-
-out:
- kfree(dent);
- return ERR_PTR(err);
}
+/*
+ * removed in barebox
+static int ubifs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
+ bool excl)
+ */
+
+/*
+ * removed in barebox
+static int do_tmpfile(struct inode *dir, struct dentry *dentry,
+ umode_t mode, struct inode **whiteout)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_tmpfile(struct inode *dir, struct dentry *dentry,
+ umode_t mode)
+ */
+
/**
* vfs_dent_type - get VFS directory entry type.
* @type: UBIFS directory entry type
@@ -165,13 +216,14 @@ static unsigned int vfs_dent_type(uint8_t type)
*/
static int ubifs_readdir(struct file *file, struct dir_context *ctx)
{
- int err = 0;
- struct qstr nm;
+ int fstr_real_len = 0, err = 0;
+ struct fscrypt_name nm;
+ struct fscrypt_str fstr = {0};
union ubifs_key key;
struct ubifs_dent_node *dent;
- struct dentry *dentry = file->f_path.dentry;
- struct inode *dir = d_inode(dentry);
+ struct inode *dir = file_inode(file);
struct ubifs_info *c = dir->i_sb->s_fs_info;
+ bool encrypted = ubifs_crypt_is_encrypted(dir);
dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos);
@@ -182,6 +234,18 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
*/
return 0;
+ if (encrypted) {
+ err = fscrypt_get_encryption_info(dir);
+ if (err && err != -ENOKEY)
+ return err;
+
+ err = fscrypt_fname_alloc_buffer(dir, UBIFS_MAX_NLEN, &fstr);
+ if (err)
+ return err;
+
+ fstr_real_len = fstr.len;
+ }
+
if (file->f_version == 0) {
/*
* The file was seek'ed, which means that @file->private_data
@@ -202,12 +266,16 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
/* File positions 0 and 1 correspond to "." and ".." */
if (ctx->pos < 2) {
- ubifs_assert(!file->private_data);
- dir_emit_dots(file, ctx);
+ ubifs_assert(c, !file->private_data);
+ if (!dir_emit_dots(file, ctx)) {
+ if (encrypted)
+ fscrypt_fname_free_buffer(&fstr);
+ return 0;
+ }
/* Find the first entry in TNC and save it */
lowest_dent_key(c, &key, dir->i_ino);
- nm.name = NULL;
+ fname_len(&nm) = 0;
dent = ubifs_tnc_next_ent(c, &key, &nm);
if (IS_ERR(dent)) {
err = PTR_ERR(dent);
@@ -225,7 +293,7 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
* Find the entry corresponding to @ctx->pos or the closest one.
*/
dent_key_init_hash(c, &key, dir->i_ino, ctx->pos);
- nm.name = NULL;
+ fname_len(&nm) = 0;
dent = ubifs_tnc_next_ent(c, &key, &nm);
if (IS_ERR(dent)) {
err = PTR_ERR(dent);
@@ -236,20 +304,39 @@ static int ubifs_readdir(struct file *file, struct dir_context *ctx)
}
while (1) {
- dbg_gen("feed '%s', ino %llu, new f_pos %#x",
- dent->name, (unsigned long long)le64_to_cpu(dent->inum),
+ dbg_gen("ino %llu, new f_pos %#x",
+ (unsigned long long)le64_to_cpu(dent->inum),
key_hash_flash(c, &dent->key));
- ubifs_assert(le64_to_cpu(dent->ch.sqnum) >
+ ubifs_assert(c, le64_to_cpu(dent->ch.sqnum) >
ubifs_inode(dir)->creat_sqnum);
- nm.len = le16_to_cpu(dent->nlen);
- dir_emit(ctx, dent->name, nm.len,
+ fname_len(&nm) = le16_to_cpu(dent->nlen);
+ fname_name(&nm) = dent->name;
+
+ if (encrypted) {
+ fstr.len = fstr_real_len;
+
+ err = fscrypt_fname_disk_to_usr(dir, key_hash_flash(c,
+ &dent->key),
+ le32_to_cpu(dent->cookie),
+ &nm.disk_name, &fstr);
+ if (err)
+ goto out;
+ } else {
+ fstr.len = fname_len(&nm);
+ fstr.name = fname_name(&nm);
+ }
+
+ if (!dir_emit(ctx, fstr.name, fstr.len,
le64_to_cpu(dent->inum),
- vfs_dent_type(dent->type));
+ vfs_dent_type(dent->type))) {
+ if (encrypted)
+ fscrypt_fname_free_buffer(&fstr);
+ return 0;
+ }
/* Switch to the next entry */
key_read(c, &dent->key, &key);
- nm.name = dent->name;
dent = ubifs_tnc_next_ent(c, &key, &nm);
if (IS_ERR(dent)) {
err = PTR_ERR(dent);
@@ -266,6 +353,9 @@ out:
kfree(file->private_data);
file->private_data = NULL;
+ if (encrypted)
+ fscrypt_fname_free_buffer(&fstr);
+
if (err != -ENOENT)
ubifs_err(c, "cannot find next direntry, error %d", err);
else
@@ -282,10 +372,132 @@ out:
return err;
}
+/*
+ * removed in barebox
+static int ubifs_dir_release(struct inode *dir, struct file *file)
+ */
+
+/*
+ * removed in barebox
+static void lock_2_inodes(struct inode *inode1, struct inode *inode2)
+ */
+
+/*
+ * removed in barebox
+static void unlock_2_inodes(struct inode *inode1, struct inode *inode2)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_unlink(struct inode *dir, struct dentry *dentry)
+ */
+
+/*
+ * removed in barebox
+int ubifs_check_dir_empty(struct inode *dir)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_mknod(struct inode *dir, struct dentry *dentry,
+ umode_t mode, dev_t rdev)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
+ */
+
+/*
+ * removed in barebox
+static void lock_4_inodes(struct inode *inode1, struct inode *inode2,
+ struct inode *inode3, struct inode *inode4)
+ */
+
+/*
+ * removed in barebox
+static void unlock_4_inodes(struct inode *inode1, struct inode *inode2,
+ struct inode *inode3, struct inode *inode4)
+ */
+
+/*
+ * removed in barebox
+static int do_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry,
+ unsigned int flags)
+ */
+
+/*
+ * removed in barebox
+int ubifs_getattr(const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int flags)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_dir_open(struct inode *dir, struct file *file)
+ */
+
const struct inode_operations ubifs_dir_inode_operations = {
.lookup = ubifs_lookup,
+ .create = NULL, /* not present in barebox */
+ .link = NULL, /* not present in barebox */
+ .symlink = NULL, /* not present in barebox */
+ .unlink = NULL, /* not present in barebox */
+ .mkdir = NULL, /* not present in barebox */
+ .rmdir = NULL, /* not present in barebox */
+/* .mknod = NULL, not present in barebox */
+ .rename = NULL, /* not present in barebox */
+/* .setattr = NULL, not present in barebox */
+/* .getattr = NULL, not present in barebox */
+#ifdef CONFIG_UBIFS_FS_XATTR
+ .listxattr = NULL, /* not present in barebox */
+#endif
+#ifdef CONFIG_UBIFS_ATIME_SUPPORT
+ .update_time = NULL, /* not present in barebox */
+#endif
+/* .tmpfile = NULL, not present in barebox */
};
const struct file_operations ubifs_dir_operations = {
- .iterate = ubifs_readdir,
+/* .llseek = NULL, not present in barebox */
+/* .release = NULL, not present in barebox */
+ .read = NULL, /* not present in barebox */
+ .iterate = ubifs_readdir,
+/* .fsync = NULL, not present in barebox */
+/* .unlocked_ioctl = NULL, not present in barebox */
+/* .open = NULL, not present in barebox */
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = NULL, /* not present in barebox */
+#endif
};
diff --git a/fs/ubifs/io.c b/fs/ubifs/io.c
index 08d4e20bda..0d5fd58c9f 100644
--- a/fs/ubifs/io.c
+++ b/fs/ubifs/io.c
@@ -4,7 +4,18 @@
* Copyright (C) 2006-2008 Nokia Corporation.
* Copyright (C) 2006, 2007 University of Szeged, Hungary
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -72,7 +83,7 @@ void ubifs_ro_mode(struct ubifs_info *c, int err)
if (!c->ro_error) {
c->ro_error = 1;
c->no_chk_data_crc = 0;
- c->vfs_sb->s_flags |= MS_RDONLY;
+ c->vfs_sb->s_flags |= SB_RDONLY;
ubifs_warn(c, "switched to read-only mode, error %d", err);
dump_stack();
}
@@ -102,6 +113,27 @@ int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs,
return err;
}
+/*
+ * removed in barebox
+int ubifs_leb_write(struct ubifs_info *c, int lnum, const void *buf, int offs,
+ int len)
+ */
+
+/*
+ * removed in barebox
+int ubifs_leb_change(struct ubifs_info *c, int lnum, const void *buf, int len)
+ */
+
+/*
+ * removed in barebox
+int ubifs_leb_unmap(struct ubifs_info *c, int lnum)
+ */
+
+/*
+ * removed in barebox
+int ubifs_leb_map(struct ubifs_info *c, int lnum)
+ */
+
int ubifs_is_mapped(const struct ubifs_info *c, int lnum)
{
int err;
@@ -150,8 +182,8 @@ int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum,
uint32_t crc, node_crc, magic;
const struct ubifs_ch *ch = buf;
- ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
- ubifs_assert(!(offs & 7) && offs < c->leb_size);
+ ubifs_assert(c, lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+ ubifs_assert(c, !(offs & 7) && offs < c->leb_size);
magic = le32_to_cpu(ch->magic);
if (magic != UBIFS_NODE_MAGIC) {
@@ -228,7 +260,7 @@ void ubifs_pad(const struct ubifs_info *c, void *buf, int pad)
{
uint32_t crc;
- ubifs_assert(pad >= 0 && !(pad & 7));
+ ubifs_assert(c, pad >= 0 && !(pad & 7));
if (pad >= UBIFS_PAD_NODE_SZ) {
struct ubifs_ch *ch = buf;
@@ -250,6 +282,68 @@ void ubifs_pad(const struct ubifs_info *c, void *buf, int pad)
memset(buf, UBIFS_PADDING_BYTE, pad);
}
+/*
+ * removed in barebox
+static unsigned long long next_sqnum(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad)
+ */
+
+/*
+ * removed in barebox
+void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last)
+ */
+
+/*
+ * removed in barebox
+static enum hrtimer_restart wbuf_timer_callback_nolock(struct hrtimer *timer)
+ */
+
+/*
+ * removed in barebox
+static void new_wbuf_timer_nolock(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
+ */
+
+/*
+ * removed in barebox
+static void cancel_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
+ */
+
+/*
+ * removed in barebox
+int ubifs_wbuf_sync_nolock(struct ubifs_wbuf *wbuf)
+ */
+
+/*
+ * removed in barebox
+int ubifs_wbuf_seek_nolock(struct ubifs_wbuf *wbuf, int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+int ubifs_bg_wbufs_sync(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
+ */
+
+/*
+ * removed in barebox
+int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
+ int offs)
+ */
+
+/*
+ * removed in barebox
+int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len,
+ int lnum, int offs)
+ */
+
/**
* ubifs_read_node - read node.
* @c: UBIFS file-system description object
@@ -270,10 +364,10 @@ int ubifs_read_node(const struct ubifs_info *c, void *buf, int type, int len,
struct ubifs_ch *ch = buf;
dbg_io("LEB %d:%d, %s, length %d", lnum, offs, dbg_ntype(type), len);
- ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
- ubifs_assert(len >= UBIFS_CH_SZ && offs + len <= c->leb_size);
- ubifs_assert(!(offs & 7) && offs < c->leb_size);
- ubifs_assert(type >= 0 && type < UBIFS_NODE_TYPES_CNT);
+ ubifs_assert(c, lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
+ ubifs_assert(c, len >= UBIFS_CH_SZ && offs + len <= c->leb_size);
+ ubifs_assert(c, !(offs & 7) && offs < c->leb_size);
+ ubifs_assert(c, type >= 0 && type < UBIFS_NODE_TYPES_CNT);
err = ubifs_leb_read(c, lnum, buf, offs, len, 0);
if (err && err != -EBADMSG)
@@ -349,5 +443,22 @@ int ubifs_wbuf_init(struct ubifs_info *c, struct ubifs_wbuf *wbuf)
wbuf->c = c;
wbuf->next_ino = 0;
+ /* hrtimer not needed in barebox */
+
return 0;
}
+
+/*
+ * removed in barebox
+void ubifs_wbuf_add_ino_nolock(struct ubifs_wbuf *wbuf, ino_t inum)
+ */
+
+/*
+ * removed in barebox
+static int wbuf_has_ino(struct ubifs_wbuf *wbuf, ino_t inum)
+ */
+
+/*
+ * removed in barebox
+int ubifs_sync_wbufs_by_inode(struct ubifs_info *c, struct inode *inode)
+ */
diff --git a/fs/ubifs/key.h b/fs/ubifs/key.h
index b5c4884e30..2feff6cbbb 100644
--- a/fs/ubifs/key.h
+++ b/fs/ubifs/key.h
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -23,6 +34,12 @@
* node. We use "r5" hash borrowed from reiserfs.
*/
+/*
+ * Lot's of the key helpers require a struct ubifs_info *c as the first parameter.
+ * But we are not using it at all currently. That's designed for future extensions of
+ * different c->key_format. But right now, there is only one key type, UBIFS_SIMPLE_KEY_FMT.
+ */
+
#ifndef __UBIFS_KEY_H__
#define __UBIFS_KEY_H__
@@ -52,7 +69,7 @@ static inline uint32_t key_r5_hash(const char *s, int len)
uint32_t a = 0;
const signed char *str = (const signed char *)s;
- while (*str) {
+ while (len--) {
a += *str << 4;
a += *str >> 4;
a *= 11;
@@ -136,15 +153,16 @@ static inline void highest_ino_key(const struct ubifs_info *c,
* @c: UBIFS file-system description object
* @key: key to initialize
* @inum: parent inode number
- * @nm: direntry name and length
+ * @nm: direntry name and length. Not a string when encrypted!
*/
static inline void dent_key_init(const struct ubifs_info *c,
union ubifs_key *key, ino_t inum,
- const struct qstr *nm)
+ const struct fscrypt_name *nm)
{
- uint32_t hash = c->key_hash(nm->name, nm->len);
+ uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
- ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ ubifs_assert(c, !(hash & ~UBIFS_S_KEY_HASH_MASK));
+ ubifs_assert(c, !nm->hash && !nm->minor_hash);
key->u32[0] = inum;
key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
}
@@ -161,7 +179,7 @@ static inline void dent_key_init_hash(const struct ubifs_info *c,
union ubifs_key *key, ino_t inum,
uint32_t hash)
{
- ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ ubifs_assert(c, !(hash & ~UBIFS_S_KEY_HASH_MASK));
key->u32[0] = inum;
key->u32[1] = hash | (UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS);
}
@@ -174,12 +192,13 @@ static inline void dent_key_init_hash(const struct ubifs_info *c,
* @nm: direntry name and length
*/
static inline void dent_key_init_flash(const struct ubifs_info *c, void *k,
- ino_t inum, const struct qstr *nm)
+ ino_t inum,
+ const struct fscrypt_name *nm)
{
union ubifs_key *key = k;
- uint32_t hash = c->key_hash(nm->name, nm->len);
+ uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
- ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ ubifs_assert(c, !(hash & ~UBIFS_S_KEY_HASH_MASK));
key->j32[0] = cpu_to_le32(inum);
key->j32[1] = cpu_to_le32(hash |
(UBIFS_DENT_KEY << UBIFS_S_KEY_HASH_BITS));
@@ -208,11 +227,11 @@ static inline void lowest_dent_key(const struct ubifs_info *c,
*/
static inline void xent_key_init(const struct ubifs_info *c,
union ubifs_key *key, ino_t inum,
- const struct qstr *nm)
+ const struct fscrypt_name *nm)
{
- uint32_t hash = c->key_hash(nm->name, nm->len);
+ uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
- ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ ubifs_assert(c, !(hash & ~UBIFS_S_KEY_HASH_MASK));
key->u32[0] = inum;
key->u32[1] = hash | (UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS);
}
@@ -225,12 +244,12 @@ static inline void xent_key_init(const struct ubifs_info *c,
* @nm: extended attribute entry name and length
*/
static inline void xent_key_init_flash(const struct ubifs_info *c, void *k,
- ino_t inum, const struct qstr *nm)
+ ino_t inum, const struct fscrypt_name *nm)
{
union ubifs_key *key = k;
- uint32_t hash = c->key_hash(nm->name, nm->len);
+ uint32_t hash = c->key_hash(fname_name(nm), fname_len(nm));
- ubifs_assert(!(hash & ~UBIFS_S_KEY_HASH_MASK));
+ ubifs_assert(c, !(hash & ~UBIFS_S_KEY_HASH_MASK));
key->j32[0] = cpu_to_le32(inum);
key->j32[1] = cpu_to_le32(hash |
(UBIFS_XENT_KEY << UBIFS_S_KEY_HASH_BITS));
@@ -261,7 +280,7 @@ static inline void data_key_init(const struct ubifs_info *c,
union ubifs_key *key, ino_t inum,
unsigned int block)
{
- ubifs_assert(!(block & ~UBIFS_S_KEY_BLOCK_MASK));
+ ubifs_assert(c, !(block & ~UBIFS_S_KEY_BLOCK_MASK));
key->u32[0] = inum;
key->u32[1] = block | (UBIFS_DATA_KEY << UBIFS_S_KEY_BLOCK_BITS);
}
diff --git a/fs/ubifs/log.c b/fs/ubifs/log.c
index db83f564f7..7a12cfd393 100644
--- a/fs/ubifs/log.c
+++ b/fs/ubifs/log.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -16,9 +27,6 @@
* journal.
*/
-#ifdef __UBOOT__
-#include <linux/err.h>
-#endif
#include "ubifs.h"
/**
@@ -51,6 +59,16 @@ struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum)
return NULL;
}
+/*
+ * removed in barebox
+struct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum)
+ */
+
+/*
+ * removed in barebox
+static inline long long empty_log_bytes(const struct ubifs_info *c)
+ */
+
/**
* ubifs_add_bud - add bud LEB to the tree of buds and its journal head list.
* @c: UBIFS file-system description object
@@ -67,7 +85,7 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
while (*p) {
parent = *p;
b = rb_entry(parent, struct ubifs_bud, rb);
- ubifs_assert(bud->lnum != b->lnum);
+ ubifs_assert(c, bud->lnum != b->lnum);
if (bud->lnum < b->lnum)
p = &(*p)->rb_left;
else
@@ -80,7 +98,7 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
jhead = &c->jheads[bud->jhead];
list_add_tail(&bud->list, &jhead->buds_list);
} else
- ubifs_assert(c->replaying && c->ro_mount);
+ ubifs_assert(c, c->replaying && c->ro_mount);
/*
* Note, although this is a new bud, we anyway account this space now,
@@ -94,3 +112,54 @@ void ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud)
bud->start, dbg_jhead(bud->jhead), c->bud_bytes);
spin_unlock(&c->buds_lock);
}
+
+/*
+ * removed in barebox
+int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static void remove_buds(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum)
+ */
+
+/*
+ * removed in barebox
+int ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum)
+ */
+
+/*
+ * removed in barebox
+int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum)
+ */
+
+/*
+ * removed in barebox
+static int done_already(struct rb_root *done_tree, int lnum)
+ */
+
+/*
+ * removed in barebox
+static void destroy_done_tree(struct rb_root *done_tree)
+ */
+
+/*
+ * removed in barebox
+static int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs,
+ void *node)
+ */
+
+/*
+ * removed in barebox
+int ubifs_consolidate_log(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static int dbg_check_bud_bytes(struct ubifs_info *c)
+ */
diff --git a/fs/ubifs/lpt_commit.c b/fs/ubifs/lpt_commit.c
index 7e7d645a51..d4fb901c7c 100644
--- a/fs/ubifs/lpt_commit.c
+++ b/fs/ubifs/lpt_commit.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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 (Битюцкий Артём)
@@ -17,3 +28,259 @@
#include <linux/err.h>
#include "crc16.h"
#include "ubifs.h"
+
+/*
+ * removed in barebox
+static struct ubifs_cnode *first_dirty_cnode(const struct ubifs_info *c, struct ubifs_nnode *nnode)
+ */
+
+/*
+ * removed in barebox
+static struct ubifs_cnode *next_dirty_cnode(const struct ubifs_info *c, struct ubifs_cnode *cnode)
+ */
+
+/*
+ * removed in barebox
+static int get_cnodes_to_commit(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static void upd_ltab(struct ubifs_info *c, int lnum, int free, int dirty)
+ */
+
+/*
+ * removed in barebox
+static int alloc_lpt_leb(struct ubifs_info *c, int *lnum)
+ */
+
+/*
+ * removed in barebox
+static int layout_cnodes(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static int realloc_lpt_leb(struct ubifs_info *c, int *lnum)
+ */
+
+/*
+ * removed in barebox
+static int write_cnodes(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c,
+ struct ubifs_pnode *pnode)
+ */
+
+/*
+ * removed in barebox
+static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i)
+ */
+
+/*
+ * removed in barebox
+static void add_pnode_dirt(struct ubifs_info *c, struct ubifs_pnode *pnode)
+ */
+
+/*
+ * removed in barebox
+static void do_make_pnode_dirty(struct ubifs_info *c, struct ubifs_pnode *pnode)
+ */
+
+/*
+ * removed in barebox
+static int make_tree_dirty(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static int need_write_all(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static void lpt_tgc_start(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static int lpt_tgc_end(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static void populate_lsave(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static struct ubifs_nnode *nnode_lookup(struct ubifs_info *c, int i)
+ */
+
+/*
+ * removed in barebox
+static int make_nnode_dirty(struct ubifs_info *c, int node_num, int lnum,
+ int offs)
+ */
+
+/*
+ * removed in barebox
+static int make_pnode_dirty(struct ubifs_info *c, int node_num, int lnum,
+ int offs)
+ */
+
+/*
+ * removed in barebox
+static int make_ltab_dirty(struct ubifs_info *c, int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static int make_lsave_dirty(struct ubifs_info *c, int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static int make_node_dirty(struct ubifs_info *c, int node_type, int node_num,
+ int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static int get_lpt_node_len(const struct ubifs_info *c, int node_type)
+ */
+
+/*
+ * removed in barebox
+static int get_pad_len(const struct ubifs_info *c, uint8_t *buf, int len)
+ */
+
+/*
+ * removed in barebox
+static int get_lpt_node_type(const struct ubifs_info *c, uint8_t *buf,
+ int *node_num)
+ */
+
+/*
+ * removed in barebox
+static int is_a_node(const struct ubifs_info *c, uint8_t *buf, int len)
+ */
+
+/*
+ * removed in barebox
+static int lpt_gc_lnum(struct ubifs_info *c, int lnum)
+ */
+
+/*
+ * removed in barebox
+static int lpt_gc(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int ubifs_lpt_start_commit(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static void free_obsolete_cnodes(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int ubifs_lpt_end_commit(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int ubifs_lpt_post_commit(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static struct ubifs_nnode *first_nnode(struct ubifs_info *c, int *hght)
+ */
+
+/*
+ * removed in barebox
+static struct ubifs_nnode *next_nnode(struct ubifs_info *c,
+ struct ubifs_nnode *nnode, int *hght)
+ */
+
+/*
+ * removed in barebox
+void ubifs_lpt_free(struct ubifs_info *c, int wr_only)
+ */
+
+/*
+ * Everything below is related to debugging.
+ */
+
+/*
+ * removed in barebox
+static int dbg_is_all_ff(uint8_t *buf, int len)
+ */
+
+/*
+ * removed in barebox
+static int dbg_is_nnode_dirty(struct ubifs_info *c, int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static int dbg_is_ltab_dirty(struct ubifs_info *c, int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static int dbg_is_lsave_dirty(struct ubifs_info *c, int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static int dbg_is_node_dirty(struct ubifs_info *c, int node_type, int lnum,
+ int offs)
+*/
+
+/*
+ * removed in barebox
+static int dbg_check_ltab_lnum(struct ubifs_info *c, int lnum)
+ */
+
+/*
+ * removed in barebox
+int dbg_check_ltab(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int dbg_chk_lpt_free_spc(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int dbg_chk_lpt_sz(struct ubifs_info *c, int action, int len)
+ */
+
+/*
+ * removed in barebox
+static void dump_lpt_leb(const struct ubifs_info *c, int lnum)
+ */
+
+/*
+ * removed in barebox
+void ubifs_dump_lpt_lebs(const struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static int dbg_populate_lsave(struct ubifs_info *c)
+ */
diff --git a/fs/ubifs/master.c b/fs/ubifs/master.c
index 3bf37c2b12..40b49b6346 100644
--- a/fs/ubifs/master.c
+++ b/fs/ubifs/master.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -12,7 +23,6 @@
/* This file implements reading and writing the master node */
#include "ubifs.h"
-#include <linux/err.h>
/**
* scan_for_master - search the valid master node.
@@ -333,7 +343,10 @@ int ubifs_read_master(struct ubifs_info *c)
if (err)
return err;
-
return err;
}
+/*
+ * removed in barebox
+int ubifs_write_master(struct ubifs_info *c)
+ */
diff --git a/fs/ubifs/misc.c b/fs/ubifs/misc.c
new file mode 100644
index 0000000000..51afb3d3ab
--- /dev/null
+++ b/fs/ubifs/misc.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/kernel.h>
+#include "ubifs.h"
+
+/* Normal UBIFS messages */
+void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ pr_notice("UBIFS (ubi%d:%d): %pV\n",
+ c->vi.ubi_num, c->vi.vol_id, &vaf);
+
+ va_end(args);
+} \
+
+/* UBIFS error messages */
+void ubifs_err(const struct ubifs_info *c, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ pr_err("UBIFS error (ubi%d:%d): %ps: %pV\n",
+ c->vi.ubi_num, c->vi.vol_id,
+ __builtin_return_address(0),
+ &vaf);
+
+ va_end(args);
+} \
+
+/* UBIFS warning messages */
+void ubifs_warn(const struct ubifs_info *c, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ pr_warn("UBIFS warning (ubi%d:%d): %ps: %pV\n",
+ c->vi.ubi_num, c->vi.vol_id,
+ __builtin_return_address(0),
+ &vaf);
+
+ va_end(args);
+}
+
+static char *assert_names[] = {
+ [ASSACT_REPORT] = "report",
+ [ASSACT_RO] = "read-only",
+ [ASSACT_PANIC] = "panic",
+};
+
+const char *ubifs_assert_action_name(struct ubifs_info *c)
+{
+ return assert_names[c->assert_action];
+}
diff --git a/fs/ubifs/misc.h b/fs/ubifs/misc.h
index 4822dd3b92..77429be554 100644
--- a/fs/ubifs/misc.h
+++ b/fs/ubifs/misc.h
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -94,25 +105,27 @@ static inline struct ubifs_inode *ubifs_inode(const struct inode *inode)
/**
* ubifs_compr_present - check if compressor was compiled in.
* @compr_type: compressor type to check
+ * @c: the UBIFS file-system description object
*
* This function returns %1 of compressor of type @compr_type is present, and
* %0 if not.
*/
-static inline int ubifs_compr_present(int compr_type)
+static inline int ubifs_compr_present(struct ubifs_info *c, int compr_type)
{
- ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
+ ubifs_assert(c, compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
return !!ubifs_compressors[compr_type]->capi_name;
}
/**
* ubifs_compr_name - get compressor name string by its type.
* @compr_type: compressor type
+ * @c: the UBIFS file-system description object
*
* This function returns compressor type string.
*/
-static inline const char *ubifs_compr_name(int compr_type)
+static inline const char *ubifs_compr_name(struct ubifs_info *c, int compr_type)
{
- ubifs_assert(compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
+ ubifs_assert(c, compr_type >= 0 && compr_type < UBIFS_COMPR_TYPES_CNT);
return ubifs_compressors[compr_type]->name;
}
@@ -133,6 +146,10 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
return err;
}
+/*
+ * removed in barebox
+static inline int ubifs_encode_dev(union ubifs_dev_desc *dev, dev_t rdev)
+ */
/**
* ubifs_add_dirt - add dirty space to LEB properties.
@@ -145,6 +162,7 @@ static inline int ubifs_wbuf_sync(struct ubifs_wbuf *wbuf)
*/
static inline int ubifs_add_dirt(struct ubifs_info *c, int lnum, int dirty)
{
+ /* removed in barebox */
return 0;
}
@@ -159,6 +177,7 @@ static inline int ubifs_add_dirt(struct ubifs_info *c, int lnum, int dirty)
*/
static inline int ubifs_return_leb(struct ubifs_info *c, int lnum)
{
+ /* removed in barebox */
return 0;
}
@@ -195,13 +214,9 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c,
static inline void *ubifs_idx_key(const struct ubifs_info *c,
const struct ubifs_idx_node *idx)
{
- struct ubifs_branch *tmp;
-
- tmp = (struct ubifs_branch *)idx->branches;
- return (void *)tmp->key;
+ return (void *)((struct ubifs_branch *)idx->branches)->key;
}
-
/**
* ubifs_tnc_lookup - look up a file-system node.
* @c: UBIFS file-system description object
@@ -240,8 +255,8 @@ static inline void ubifs_get_lprops(struct ubifs_info *c)
*/
static inline void ubifs_release_lprops(struct ubifs_info *c)
{
- ubifs_assert(mutex_is_locked(&c->lp_mutex));
- ubifs_assert(c->lst.empty_lebs >= 0 &&
+ ubifs_assert(c, mutex_is_locked(&c->lp_mutex));
+ ubifs_assert(c, c->lst.empty_lebs >= 0 &&
c->lst.empty_lebs <= c->main_lebs);
mutex_unlock(&c->lp_mutex);
}
@@ -263,4 +278,6 @@ static inline int ubifs_next_log_lnum(const struct ubifs_info *c, int lnum)
return lnum;
}
+const char *ubifs_assert_action_name(struct ubifs_info *c);
+
#endif /* __UBIFS_MISC_H__ */
diff --git a/fs/ubifs/recovery.c b/fs/ubifs/recovery.c
index 5b3902b632..fac83f87e0 100644
--- a/fs/ubifs/recovery.c
+++ b/fs/ubifs/recovery.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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 (Битюцкий Артём)
@@ -182,6 +193,12 @@ out_free:
return err;
}
+/*
+ * removed in barebox
+static int write_rcvrd_mst_node(struct ubifs_info *c,
+ struct ubifs_mst_node *mst)
+ */
+
/**
* ubifs_recover_master_node - recover the master node.
* @c: UBIFS file-system description object
@@ -302,6 +319,9 @@ int ubifs_recover_master_node(struct ubifs_info *c)
* dirty.
*/
c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
+ } else {
+ /* Write the recovered master node */
+ /* not done in barebox */
}
vfree(buf2);
@@ -326,6 +346,11 @@ out_free:
return err;
}
+/*
+ * removed in barebox
+int ubifs_write_rcvrd_mst_node(struct ubifs_info *c)
+ */
+
/**
* is_last_write - determine if an offset was in the last write to a LEB.
* @c: UBIFS file-system description object
@@ -369,10 +394,9 @@ static void clean_buf(const struct ubifs_info *c, void **buf, int lnum,
{
int empty_offs, pad_len;
- lnum = lnum;
dbg_rcvry("cleaning corruption at %d:%d", lnum, *offs);
- ubifs_assert(!(*offs & 7));
+ ubifs_assert(c, !(*offs & 7));
empty_offs = ALIGN(*offs, c->min_io_size);
pad_len = empty_offs - *offs;
ubifs_pad(c, *buf, pad_len);
@@ -453,6 +477,9 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
ucleb->lnum = lnum;
ucleb->endpt = endpt;
list_add_tail(&ucleb->list, &c->unclean_leb_list);
+ } else {
+ /* Write the fixed LEB back to flash */
+ /* not done in barebox */
}
return 0;
}
@@ -539,7 +566,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
if (IS_ERR(sleb))
return sleb;
- ubifs_assert(len >= 8);
+ ubifs_assert(c, len >= 8);
while (len >= 8) {
dbg_scan("look at LEB %d:%d (%d bytes left)",
lnum, offs, len);
@@ -683,7 +710,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
corrupted_rescan:
/* Re-scan the corrupted data with verbose messages */
ubifs_err(c, "corruption %d", ret);
- ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
+ ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
corrupted:
ubifs_scanned_corruption(c, lnum, offs, buf);
err = -EUCLEAN;
@@ -804,10 +831,36 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
return ubifs_recover_leb(c, lnum, offs, sbuf, -1);
}
+/*
+ * removed in barebox
+static int recover_head(struct ubifs_info *c, int lnum, int offs, void *sbuf)
+ */
+
+/*
+ * removed in barebox
+int ubifs_recover_inl_heads(struct ubifs_info *c, void *sbuf)
+ */
+
+/*
+ * removed in barebox
+static int clean_an_unclean_leb(struct ubifs_info *c,
+ struct ubifs_unclean_leb *ucleb, void *sbuf)
+ */
+
+/*
+ * removed in barebox
+int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf)
+ */
+
+/*
+ * removed in barebox
+static int grab_empty_leb(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
int ubifs_rcvry_gc_commit(struct ubifs_info *c)
-{
- return 0;
-}
+ */
/**
* struct size_entry - inode size information for recovery.
@@ -911,8 +964,7 @@ void ubifs_destroy_size_tree(struct ubifs_info *c)
struct size_entry *e, *n;
rbtree_postorder_for_each_entry_safe(e, n, &c->size_tree, rb) {
- if (e->inode)
- iput(e->inode);
+ iput(e->inode);
kfree(e);
}
@@ -987,6 +1039,10 @@ int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key,
return 0;
}
+/*
+ * removed in barebox
+static int fix_size_in_place(struct ubifs_info *c, struct size_entry *e)
+ */
/**
* ubifs_recover_size - recover inode size.
@@ -1034,7 +1090,7 @@ int ubifs_recover_size(struct ubifs_info *c)
struct inode *inode;
struct ubifs_inode *ui;
- ubifs_assert(!e->inode);
+ ubifs_assert(c, !e->inode);
inode = ubifs_iget(c->vfs_sb, e->inum);
if (IS_ERR(inode))
@@ -1053,6 +1109,9 @@ int ubifs_recover_size(struct ubifs_info *c)
continue;
}
iput(inode);
+ } else {
+ /* Fix the size in place */
+ /* Not done in barebox */
}
}
diff --git a/fs/ubifs/replay.c b/fs/ubifs/replay.c
index 19d0bf1f73..9eb24b035d 100644
--- a/fs/ubifs/replay.c
+++ b/fs/ubifs/replay.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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 (Битюцкий Артём)
@@ -21,9 +32,7 @@
* larger is the journal, the more memory its index may consume.
*/
-#include <linux/err.h>
#include "ubifs.h"
-#include <linux/bug.h>
#include <linux/list_sort.h>
/**
@@ -52,7 +61,7 @@ struct replay_entry {
struct list_head list;
union ubifs_key key;
union {
- struct qstr nm;
+ struct fscrypt_name nm;
struct {
loff_t old_size;
loff_t new_size;
@@ -76,6 +85,16 @@ struct bud_entry {
int dirty;
};
+/*
+ * removed in barebox
+static int set_bud_lprops(struct ubifs_info *c, struct bud_entry *b)
+ */
+
+/*
+ * removed in barebox
+static int set_buds_lprops(struct ubifs_info *c)
+ */
+
/**
* trun_remove_range - apply a replay entry for a truncation to the TNC.
* @c: UBIFS file-system description object
@@ -117,9 +136,6 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
dbg_mntk(&r->key, "LEB %d:%d len %d deletion %d sqnum %llu key ",
r->lnum, r->offs, r->len, r->deletion, r->sqnum);
- /* Set c->replay_sqnum to help deal with dangling branches. */
- c->replay_sqnum = r->sqnum;
-
if (is_hash_key(c, &r->key)) {
if (r->deletion)
err = ubifs_tnc_remove_nm(c, &r->key, &r->nm);
@@ -161,7 +177,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
* replay_entries_cmp - compare 2 replay entries.
* @priv: UBIFS file-system description object
* @a: first replay entry
- * @a: second replay entry
+ * @b: second replay entry
*
* This is a comparios function for 'list_sort()' which compares 2 replay
* entries @a and @b by comparing their sequence numer. Returns %1 if @a has
@@ -170,6 +186,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r)
static int replay_entries_cmp(void *priv, struct list_head *a,
struct list_head *b)
{
+ struct ubifs_info *c = priv;
struct replay_entry *ra, *rb;
cond_resched();
@@ -178,7 +195,7 @@ static int replay_entries_cmp(void *priv, struct list_head *a,
ra = list_entry(a, struct replay_entry, list);
rb = list_entry(b, struct replay_entry, list);
- ubifs_assert(ra->sqnum != rb->sqnum);
+ ubifs_assert(c, ra->sqnum != rb->sqnum);
if (ra->sqnum > rb->sqnum)
return 1;
return -1;
@@ -221,7 +238,7 @@ static void destroy_replay_list(struct ubifs_info *c)
list_for_each_entry_safe(r, tmp, &c->replay_list, list) {
if (is_hash_key(c, &r->key))
- kfree(r->nm.name);
+ kfree(fname_name(&r->nm));
list_del(&r->list);
kfree(r);
}
@@ -324,10 +341,10 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len,
r->deletion = !!deletion;
r->sqnum = sqnum;
key_copy(c, key, &r->key);
- r->nm.len = nlen;
+ fname_len(&r->nm) = nlen;
memcpy(nbuf, name, nlen);
nbuf[nlen] = '\0';
- r->nm.name = nbuf;
+ fname_name(&r->nm) = nbuf;
list_add_tail(&r->list, &c->replay_list);
return 0;
@@ -350,7 +367,7 @@ int ubifs_validate_entry(struct ubifs_info *c,
if (le32_to_cpu(dent->ch.len) != nlen + UBIFS_DENT_NODE_SZ + 1 ||
dent->type >= UBIFS_ITYPES_CNT ||
nlen > UBIFS_MAX_NLEN || dent->name[nlen] != 0 ||
- strnlen(dent->name, nlen) != nlen ||
+ (key_type == UBIFS_XENT_KEY && strnlen(dent->name, nlen) != nlen) ||
le64_to_cpu(dent->inum) > MAX_INUM) {
ubifs_err(c, "bad %s node", key_type == UBIFS_DENT_KEY ?
"directory entry" : "extended attribute entry");
@@ -565,9 +582,9 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
goto out;
}
- ubifs_assert(ubifs_search_bud(c, lnum));
- ubifs_assert(sleb->endpt - offs >= used);
- ubifs_assert(sleb->endpt % c->min_io_size == 0);
+ ubifs_assert(c, ubifs_search_bud(c, lnum));
+ ubifs_assert(c, sleb->endpt - offs >= used);
+ ubifs_assert(c, sleb->endpt % c->min_io_size == 0);
b->dirty = sleb->endpt - offs - used;
b->free = c->leb_size - sleb->endpt;
@@ -603,7 +620,7 @@ static int replay_buds(struct ubifs_info *c)
if (err)
return err;
- ubifs_assert(b->sqnum > prev_sqnum);
+ ubifs_assert(c, b->sqnum > prev_sqnum);
prev_sqnum = b->sqnum;
}
@@ -856,6 +873,11 @@ out_dump:
return -EINVAL;
}
+/*
+ * removed in barebox
+static int take_ihead(struct ubifs_info *c)
+ */
+
/**
* ubifs_replay_journal - replay journal.
* @c: UBIFS file-system description object
@@ -870,6 +892,9 @@ int ubifs_replay_journal(struct ubifs_info *c)
BUILD_BUG_ON(UBIFS_TRUN_KEY > 5);
+ /* Update the status of the index head in lprops to 'taken' */
+ /* Not done in barebox */
+
dbg_mnt("start replaying the journal");
c->replaying = 1;
lnum = c->ltail_lnum = c->lhead_lnum;
@@ -885,7 +910,7 @@ int ubifs_replay_journal(struct ubifs_info *c)
* The head of the log must always start with the
* "commit start" node on a properly formatted UBIFS.
* But we found no nodes at all, which means that
- * someting went wrong and we cannot proceed mounting
+ * something went wrong and we cannot proceed mounting
* the file-system.
*/
ubifs_err(c, "no UBIFS nodes found at the log head LEB %d:%d, possibly corrupted",
@@ -905,6 +930,8 @@ int ubifs_replay_journal(struct ubifs_info *c)
if (err)
goto out;
+ /* set_buds_lprops Not done in barebox */
+
/*
* UBIFS budgeting calculations use @c->bi.uncommitted_idx variable
* to roughly estimate index growth. Things like @c->bi.min_idx_lebs
@@ -914,7 +941,7 @@ int ubifs_replay_journal(struct ubifs_info *c)
c->bi.uncommitted_idx = atomic_long_read(&c->dirty_zn_cnt);
c->bi.uncommitted_idx *= c->max_idx_node_sz;
- ubifs_assert(c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
+ ubifs_assert(c, c->bud_bytes <= c->max_bud_bytes || c->need_recovery);
dbg_mnt("finished, log head LEB %d:%d, max_sqnum %llu, highest_inum %lu",
c->lhead_lnum, c->lhead_offs, c->max_sqnum,
(unsigned long)c->highest_inum);
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
index f7051c96d2..48bfb24955 100644
--- a/fs/ubifs/sb.c
+++ b/fs/ubifs/sb.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -52,6 +63,10 @@
/* Default time granularity in nanoseconds */
#define DEFAULT_TIME_GRAN 1000000000
+/*
+ * removed in barebox
+static int create_default_filesystem(struct ubifs_info *c)
+ */
/**
* validate_sb - validate superblock node.
@@ -179,6 +194,16 @@ static int validate_sb(struct ubifs_info *c, struct ubifs_sb_node *sup)
goto failed;
}
+ if (!c->double_hash && c->fmt_version >= 5) {
+ err = 16;
+ goto failed;
+ }
+
+ if (c->encrypted && c->fmt_version < 5) {
+ err = 17;
+ goto failed;
+ }
+
return 0;
failed:
@@ -214,6 +239,11 @@ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
return sup;
}
+/*
+ * removed in barebox
+int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup)
+ */
+
/**
* ubifs_read_superblock - read superblock.
* @c: UBIFS file-system description object
@@ -228,8 +258,8 @@ int ubifs_read_superblock(struct ubifs_info *c)
struct ubifs_sb_node *sup;
if (c->empty) {
- printf("No UBIFS filesystem found!\n");
- return -1;
+ ubifs_err(c, "No UBIFS filesystem found\n");
+ return -EINVAL;
}
sup = ubifs_read_sb_node(c);
@@ -244,7 +274,7 @@ int ubifs_read_superblock(struct ubifs_info *c)
* due to the unavailability of time-travelling equipment.
*/
if (c->fmt_version > UBIFS_FORMAT_VERSION) {
- ubifs_assert(!c->ro_media || c->ro_mount);
+ ubifs_assert(c, !c->ro_media || c->ro_mount);
if (!c->ro_mount ||
c->ro_compat_version > UBIFS_RO_COMPAT_VERSION) {
ubifs_err(c, "on-flash format version is w%d/r%d, but software only supports up to version w%d/r%d",
@@ -308,8 +338,6 @@ int ubifs_read_superblock(struct ubifs_info *c)
c->fanout = le32_to_cpu(sup->fanout);
c->lsave_cnt = le32_to_cpu(sup->lsave_cnt);
c->rp_size = le64_to_cpu(sup->rp_size);
- c->rp_uid = le32_to_cpu(sup->rp_uid);
- c->rp_gid = le32_to_cpu(sup->rp_gid);
sup_flags = le32_to_cpu(sup->flags);
if (!c->mount_opts.override_compr)
c->default_compr = le16_to_cpu(sup->default_compr);
@@ -318,6 +346,24 @@ int ubifs_read_superblock(struct ubifs_info *c)
memcpy(&c->uuid, &sup->uuid, 16);
c->big_lpt = !!(sup_flags & UBIFS_FLG_BIGLPT);
c->space_fixup = !!(sup_flags & UBIFS_FLG_SPACE_FIXUP);
+ c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH);
+ c->encrypted = !!(sup_flags & UBIFS_FLG_ENCRYPTION);
+
+ if ((sup_flags & ~UBIFS_FLG_MASK) != 0) {
+ ubifs_err(c, "Unknown feature flags found: %#x",
+ sup_flags & ~UBIFS_FLG_MASK);
+ err = -EINVAL;
+ goto out;
+ }
+
+#ifndef CONFIG_UBIFS_FS_ENCRYPTION
+ if (c->encrypted) {
+ ubifs_err(c, "file system contains encrypted files but UBIFS"
+ " was built without crypto support.");
+ err = -EINVAL;
+ goto out;
+ }
+#endif
/* Automatically increase file system size to the maximum size */
c->old_leb_cnt = c->leb_cnt;
@@ -326,6 +372,9 @@ int ubifs_read_superblock(struct ubifs_info *c)
if (c->ro_mount)
dbg_mnt("Auto resizing (ro) from %d LEBs to %d LEBs",
c->old_leb_cnt, c->leb_cnt);
+ else {
+ /* Auto resizing not done in barebox */
+ }
}
c->log_bytes = (long long)c->log_lebs * c->leb_size;
@@ -343,3 +392,23 @@ out:
kfree(sup);
return err;
}
+
+/*
+ * removed in barebox
+static int fixup_leb(struct ubifs_info *c, int lnum, int len)
+ */
+
+/*
+ * removed in barebox
+static int fixup_free_space(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int ubifs_fixup_free_space(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+int ubifs_enable_encryption(struct ubifs_info *c)
+ */
diff --git a/fs/ubifs/scan.c b/fs/ubifs/scan.c
index 1d4bdf603b..ea88926163 100644
--- a/fs/ubifs/scan.c
+++ b/fs/ubifs/scan.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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 (Битюцкий Артём)
@@ -16,7 +27,6 @@
* debugging functions.
*/
-#include <linux/err.h>
#include "ubifs.h"
/**
@@ -165,9 +175,8 @@ struct ubifs_scan_leb *ubifs_start_scan(const struct ubifs_info *c, int lnum,
void ubifs_end_scan(const struct ubifs_info *c, struct ubifs_scan_leb *sleb,
int lnum, int offs)
{
- lnum = lnum;
dbg_scan("stop scanning LEB %d at offset %d", lnum, offs);
- ubifs_assert(offs % c->min_io_size == 0);
+ ubifs_assert(c, offs % c->min_io_size == 0);
sleb->endpt = ALIGN(offs, c->min_io_size);
}
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c
index f5ddfc667b..2fe2f3f640 100644
--- a/fs/ubifs/super.c
+++ b/fs/ubifs/super.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -15,7 +26,6 @@
* corresponding subsystems, but most of it is here.
*/
-
#include <common.h>
#include <init.h>
#include <fs.h>
@@ -58,8 +68,10 @@ void unlock_new_inode(struct inode *inode)
#define UBIFS_KMALLOC_OK (128*1024)
/* Slab cache for UBIFS inodes */
-struct kmem_cache *ubifs_inode_slab;
+static struct kmem_cache *ubifs_inode_slab;
+/* UBIFS TNC shrinker description */
+/* No shrinker in barebox */
/**
* validate_inode - validate inode.
@@ -96,12 +108,12 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode)
if (ui->xattr && !S_ISREG(inode->i_mode))
return 5;
- if (!ubifs_compr_present(ui->compr_type)) {
+ if (!ubifs_compr_present(c, ui->compr_type)) {
ubifs_warn(c, "inode %lu uses '%s' compression, but it was not compiled in",
- inode->i_ino, ubifs_compr_name(ui->compr_type));
+ inode->i_ino, ubifs_compr_name(c, ui->compr_type));
}
- err = dbg_check_dir(c, inode);
+ err = 0;
return err;
}
@@ -138,7 +150,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
if (err)
goto out_ino;
- inode->i_flags |= (S_NOCMTIME | S_NOATIME);
+ inode->i_flags |= S_NOCMTIME;
+#ifndef CONFIG_UBIFS_ATIME_SUPPORT
+ inode->i_flags |= S_NOATIME;
+#endif
set_nlink(inode, le32_to_cpu(ino->nlink));
i_uid_write(inode, le32_to_cpu(ino->uid));
i_gid_write(inode, le32_to_cpu(ino->gid));
@@ -168,6 +183,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
switch (inode->i_mode & S_IFMT) {
case S_IFREG:
+ /* no address operations in barebox */
inode->i_op = &ubifs_file_inode_operations;
inode->i_fop = &ubifs_file_operations;
if (ui->xattr) {
@@ -206,6 +222,12 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
((char *)ui->data)[ui->data_len] = '\0';
inode->i_link = ui->data;
break;
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFSOCK:
+ case S_IFIFO:
+ /* No special files in barebox */
+ break;
default:
err = 15;
goto out_invalid;
@@ -243,6 +265,11 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb)
return &ui->vfs_inode;
};
+/*
+ * removed in barebox
+static void ubifs_i_callback(struct rcu_head *head)
+ */
+
static void ubifs_destroy_inode(struct inode *inode)
{
struct ubifs_inode *ui = ubifs_inode(inode);
@@ -251,6 +278,35 @@ static void ubifs_destroy_inode(struct inode *inode)
kfree(ui);
}
+/*
+ * removed in barebox
+static int ubifs_write_inode(struct inode *inode, struct writeback_control *wbc)
+ */
+
+/*
+ * removed in barebox
+static void ubifs_evict_inode(struct inode *inode)
+ */
+
+/*
+ * removed in barebox
+static void ubifs_dirty_inode(struct inode *inode, int flags)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_statfs(struct dentry *dentry, struct kstatfs *buf)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_show_options(struct seq_file *s, struct dentry *root)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_sync_fs(struct super_block *sb, int wait)
+ */
/**
* init_constants_early - initialize UBIFS constants.
@@ -288,19 +344,19 @@ static int init_constants_early(struct ubifs_info *c)
c->max_write_shift = fls(c->max_write_size) - 1;
if (c->leb_size < UBIFS_MIN_LEB_SZ) {
- ubifs_err(c, "too small LEBs (%d bytes), min. is %d bytes",
- c->leb_size, UBIFS_MIN_LEB_SZ);
+ ubifs_errc(c, "too small LEBs (%d bytes), min. is %d bytes",
+ c->leb_size, UBIFS_MIN_LEB_SZ);
return -EINVAL;
}
if (c->leb_cnt < UBIFS_MIN_LEB_CNT) {
- ubifs_err(c, "too few LEBs (%d), min. is %d",
- c->leb_cnt, UBIFS_MIN_LEB_CNT);
+ ubifs_errc(c, "too few LEBs (%d), min. is %d",
+ c->leb_cnt, UBIFS_MIN_LEB_CNT);
return -EINVAL;
}
if (!is_power_of_2(c->min_io_size)) {
- ubifs_err(c, "bad min. I/O size %d", c->min_io_size);
+ ubifs_errc(c, "bad min. I/O size %d", c->min_io_size);
return -EINVAL;
}
@@ -311,8 +367,8 @@ static int init_constants_early(struct ubifs_info *c)
if (c->max_write_size < c->min_io_size ||
c->max_write_size % c->min_io_size ||
!is_power_of_2(c->max_write_size)) {
- ubifs_err(c, "bad write buffer size %d for %d min. I/O unit",
- c->max_write_size, c->min_io_size);
+ ubifs_errc(c, "bad write buffer size %d for %d min. I/O unit",
+ c->max_write_size, c->min_io_size);
return -EINVAL;
}
@@ -387,6 +443,11 @@ static int init_constants_early(struct ubifs_info *c)
return 0;
}
+/*
+ * removed in barebox
+static int bud_wbuf_callback(struct ubifs_info *c, int lnum, int free, int pad)
+ */
+
/*
* init_constants_sb - initialize UBIFS constants.
* @c: UBIFS file-system description object
@@ -469,11 +530,23 @@ static int init_constants_sb(struct ubifs_info *c)
if (c->max_bud_bytes < tmp64 + c->leb_size)
c->max_bud_bytes = tmp64 + c->leb_size;
+ /* No lpt in barebox */
+
/* Initialize effective LEB size used in budgeting calculations */
c->idx_leb_size = c->leb_size - c->max_idx_node_sz;
return 0;
}
+/*
+ * removed in barebox
+static void init_constants_master(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static int take_gc_lnum(struct ubifs_info *c)
+ */
+
/**
* alloc_wbufs - allocate write-buffers.
* @c: UBIFS file-system description object
@@ -529,6 +602,11 @@ static void free_wbufs(struct ubifs_info *c)
}
}
+/*
+ * removed in barebox
+static void free_orphans(struct ubifs_info *c)
+ */
+
/**
* free_buds - free per-bud objects.
* @c: UBIFS file-system description object
@@ -570,6 +648,17 @@ static int check_volume_empty(struct ubifs_info *c)
return 0;
}
+/*
+ * removed in barebox
+static int parse_standard_option(const char *option)
+*/
+
+/*
+ * removed in barebox
+static int ubifs_parse_options(struct ubifs_info *c, char *options,
+ int is_remount)
+ */
+
/**
* destroy_journal - destroy journal data structures.
* @c: UBIFS file-system description object
@@ -599,6 +688,16 @@ static void destroy_journal(struct ubifs_info *c)
free_buds(c);
}
+/*
+ * removed in barebox
+static void bu_init(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static int check_free_space(struct ubifs_info *c)
+ */
+
/**
* mount_ubifs - mount UBIFS file-system.
* @c: UBIFS file-system description object
@@ -612,17 +711,16 @@ static int mount_ubifs(struct ubifs_info *c)
long long x, y;
size_t sz;
+ /* Always readonly in barebox */
c->ro_mount = true;
- /* Suppress error messages while probing if MS_SILENT is set */
- c->probing = !!(c->vfs_sb->s_flags & MS_SILENT);
+ /* Suppress error messages while probing if SB_SILENT is set */
+ c->probing = !!(c->vfs_sb->s_flags & SB_SILENT);
err = init_constants_early(c);
if (err)
return err;
- err = ubifs_debugging_init(c);
- if (err)
- return err;
+ /* No debugging in barebox, use Kernel to debug */
err = check_volume_empty(c);
if (err)
@@ -651,7 +749,8 @@ static int mount_ubifs(struct ubifs_info *c)
* never exceed 64.
*/
err = -ENOMEM;
- c->bottom_up_buf = kmalloc(BOTTOM_UP_HEIGHT * sizeof(int), GFP_KERNEL);
+ c->bottom_up_buf = kmalloc_array(BOTTOM_UP_HEIGHT, sizeof(int),
+ GFP_KERNEL);
if (!c->bottom_up_buf)
goto out_free;
@@ -672,9 +771,9 @@ static int mount_ubifs(struct ubifs_info *c)
* Make sure the compressor which is set as default in the superblock
* or overridden by mount options is actually compiled in.
*/
- if (!ubifs_compr_present(c->default_compr)) {
+ if (!ubifs_compr_present(c, c->default_compr)) {
ubifs_err(c, "'compressor \"%s\" is not compiled in",
- ubifs_compr_name(c->default_compr));
+ ubifs_compr_name(c, c->default_compr));
err = -ENOTSUPP;
goto out_free;
}
@@ -728,18 +827,12 @@ static int mount_ubifs(struct ubifs_info *c)
* the journal head LEBs may also be accounted as
* "empty taken" if they are empty.
*/
- ubifs_assert(c->lst.taken_empty_lebs > 0);
+ ubifs_assert(c, c->lst.taken_empty_lebs > 0);
}
+ } else {
+ /* c->lst.taken_empty_lebs is always 0 in ro implementation */
}
- err = dbg_check_filesystem(c);
- if (err)
- goto out_infos;
-
- err = dbg_debugfs_init_fs(c);
- if (err)
- goto out_infos;
-
c->mounting = 0;
ubifs_msg(c, "UBIFS: mounted UBI device %d, volume %d, name \"%s\"%s",
@@ -760,7 +853,7 @@ static int mount_ubifs(struct ubifs_info *c)
UBIFS_FORMAT_VERSION, UBIFS_RO_COMPAT_VERSION, c->uuid,
c->big_lpt ? ", big LPT model" : ", small LPT model");
- dbg_gen("default compressor: %s", ubifs_compr_name(c->default_compr));
+ dbg_gen("default compressor: %s", ubifs_compr_name(c, c->default_compr));
dbg_gen("data journal heads: %d",
c->jhead_cnt - NONDATA_JHEADS_CNT);
dbg_gen("log LEBs: %d (%d - %d)",
@@ -808,10 +901,6 @@ static int mount_ubifs(struct ubifs_info *c)
return 0;
-out_infos:
- spin_lock(&ubifs_infos_lock);
- list_del(&c->infos_list);
- spin_unlock(&ubifs_infos_lock);
out_orphans:
out_journal:
destroy_journal(c);
@@ -829,7 +918,6 @@ out_free:
vfree(c->ileb_buf);
vfree(c->sbuf);
kfree(c->bottom_up_buf);
- ubifs_debugging_exit(c);
return err;
}
@@ -847,7 +935,6 @@ void ubifs_umount(struct ubifs_info *c)
dbg_gen("un-mounting UBI device %d, volume %d", c->vi.ubi_num,
c->vi.vol_id);
- dbg_debugfs_exit_fs(c);
spin_lock(&ubifs_infos_lock);
list_del(&c->infos_list);
spin_unlock(&ubifs_infos_lock);
@@ -862,32 +949,36 @@ void ubifs_umount(struct ubifs_info *c)
vfree(c->ileb_buf);
vfree(c->sbuf);
kfree(c->bottom_up_buf);
- ubifs_debugging_exit(c);
}
+/*
+ * removed in barebox
+static int ubifs_remount_rw(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static void ubifs_remount_ro(struct ubifs_info *c)
+ */
+
+/*
+ * removed in barebox
+static void ubifs_put_super(struct super_block *sb)
+ */
+
+/*
+ * removed in barebox
+static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data)
+ */
+
const struct super_operations ubifs_super_operations = {
.alloc_inode = ubifs_alloc_inode,
.destroy_inode = ubifs_destroy_inode,
};
-/**
- * open_ubi - parse UBI device name string and open the UBI device.
- * @name: UBI volume name
- * @mode: UBI volume open mode
- *
- * The primary method of mounting UBIFS is by specifying the UBI volume
- * character device node path. However, UBIFS may also be mounted withoug any
- * character device node using one of the following methods:
- *
- * o ubiX_Y - mount UBI device number X, volume Y;
- * o ubiY - mount UBI device number 0, volume Y;
- * o ubiX:NAME - mount UBI device X, volume with name NAME;
- * o ubi:NAME - mount UBI device 0, volume with name NAME.
- *
- * Alternative '!' separator may be used instead of ':' (because some shells
- * like busybox may interpret ':' as an NFS host name separator). This function
- * returns UBI volume description object in case of success and a negative
- * error code in case of failure.
+/*
+ * removed in barebox
+static struct ubi_volume_desc *open_ubi(const char *name, int mode)
*/
static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
@@ -926,6 +1017,7 @@ static struct ubifs_info *alloc_ubifs_info(struct ubi_volume_desc *ubi)
INIT_LIST_HEAD(&c->orph_list);
INIT_LIST_HEAD(&c->orph_new);
c->no_chk_data_crc = 1;
+ c->assert_action = ASSACT_RO;
c->highest_inum = UBIFS_FIRST_INO;
c->lhead_lnum = c->ltail_lnum = UBIFS_LOG_LNUM;
@@ -943,6 +1035,7 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
int err;
c->vfs_sb = sb;
+
sb->s_fs_info = c;
sb->s_magic = UBIFS_SUPER_MAGIC;
sb->s_blocksize = UBIFS_BLOCK_SIZE;
@@ -951,11 +1044,17 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent)
if (c->max_inode_sz > MAX_LFS_FILESIZE)
sb->s_maxbytes = c->max_inode_sz = MAX_LFS_FILESIZE;
sb->s_op = &ubifs_super_operations;
+#ifdef CONFIG_UBIFS_FS_XATTR
+ sb->s_xattr = ubifs_xattr_handlers;
+#endif
+#ifdef CONFIG_UBIFS_FS_ENCRYPTION
+ sb->s_cop = &ubifs_crypt_operations;
+#endif
mutex_lock(&c->umount_mutex);
err = mount_ubifs(c);
if (err) {
- ubifs_assert(err < 0);
+ ubifs_assert(c, err < 0);
goto out_unlock;
}
@@ -979,9 +1078,31 @@ out_umount:
ubifs_umount(c);
out_unlock:
mutex_unlock(&c->umount_mutex);
+
return err;
}
+/*
+ * removed in barebox
+static int sb_test(struct super_block *sb, void *data)
+ */
+
+/*
+ * removed in barebox
+static int sb_set(struct super_block *sb, void *data)
+ */
+
+/*
+ * removed in barebox
+static struct dentry *ubifs_mount(struct file_system_type *fs_type, int flags,
+ const char *name, void *data)
+ */
+
+/*
+ * removed in barebox
+static void kill_ubifs_super(struct super_block *s)
+ */
+
/*
* Inode slab cache constructor.
*/
@@ -1041,12 +1162,12 @@ static int __init ubifs_init(void)
BUILD_BUG_ON(UBIFS_COMPR_TYPES_CNT > 4);
/*
- * We require that PAGE_CACHE_SIZE is greater-than-or-equal-to
+ * We require that PAGE_SIZE is greater-than-or-equal-to
* UBIFS_BLOCK_SIZE. It is assumed that both are powers of 2.
*/
- if (PAGE_CACHE_SIZE < UBIFS_BLOCK_SIZE) {
- pr_err("UBIFS error (pid %d): VFS page cache size is %u bytes, but UBIFS requires at least 4096 bytes",
- 0, (unsigned int)PAGE_CACHE_SIZE);
+ if (PAGE_SIZE < UBIFS_BLOCK_SIZE) {
+ pr_err("UBIFS error: VFS page cache size is %u bytes, but UBIFS requires at least 4096 bytes",
+ (unsigned int)PAGE_SIZE);
return -EINVAL;
}
@@ -1070,7 +1191,6 @@ out_shrinker:
/* late_initcall to let compressors initialize first */
late_initcall(ubifs_init);
-
int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent)
{
struct fs_device_d *fsdev = dev_to_fs_device(dev);
@@ -1085,12 +1205,11 @@ int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silen
sb->s_fs_info = c;
strncpy(sb->s_id, dev->name, sizeof(sb->s_id));
- /* Re-open the UBI device in read-write mode */
c->ubi = ubi;
err = ubifs_fill_super(sb, NULL, silent);
if (err) {
- ubifs_assert(err < 0);
+ ubifs_assert(c, err < 0);
goto out;
}
sb->s_dev = c->vi.cdev;
@@ -1100,3 +1219,8 @@ out:
kfree(c);
return err;
}
+
+/*
+ * removed in barebox
+static void __exit ubifs_exit(void)
+ */
diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c
index 0f93051bac..191785cbc1 100644
--- a/fs/ubifs/tnc.c
+++ b/fs/ubifs/tnc.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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 (Битюцкий Артём)
@@ -23,6 +34,11 @@
#include <linux/stat.h>
#include "ubifs.h"
+static int try_read_node(const struct ubifs_info *c, void *buf, int type,
+ int len, int lnum, int offs);
+static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_zbranch *zbr, void *node);
+
/*
* Returned codes of 'matches_name()' and 'fallible_matches_name()' functions.
* @NAME_LESS: name corresponding to the first argument is less than second
@@ -175,6 +191,17 @@ void destroy_old_idx(struct ubifs_info *c)
c->old_idx = RB_ROOT;
}
+/*
+ * removed in barebox
+static struct ubifs_znode *copy_znode(struct ubifs_info *c,
+ struct ubifs_znode *znode)
+ */
+
+/*
+ * removed in barebox
+static int add_idx_dirt(struct ubifs_info *c, int lnum, int dirt)
+ */
+
/**
* dirty_cow_znode - ensure a znode is not being committed.
* @c: UBIFS file-system description object
@@ -185,6 +212,7 @@ void destroy_old_idx(struct ubifs_info *c)
static struct ubifs_znode *dirty_cow_znode(struct ubifs_info *c,
struct ubifs_zbranch *zbr)
{
+ /* No cow in barebox, just return original node */
return zbr->znode;
}
@@ -215,9 +243,9 @@ static int lnc_add(struct ubifs_info *c, struct ubifs_zbranch *zbr,
void *lnc_node;
const struct ubifs_dent_node *dent = node;
- ubifs_assert(!zbr->leaf);
- ubifs_assert(zbr->len != 0);
- ubifs_assert(is_hash_key(c, &zbr->key));
+ ubifs_assert(c, !zbr->leaf);
+ ubifs_assert(c, zbr->len != 0);
+ ubifs_assert(c, is_hash_key(c, &zbr->key));
err = ubifs_validate_entry(c, dent);
if (err) {
@@ -249,8 +277,8 @@ static int lnc_add_directly(struct ubifs_info *c, struct ubifs_zbranch *zbr,
{
int err;
- ubifs_assert(!zbr->leaf);
- ubifs_assert(zbr->len != 0);
+ ubifs_assert(c, !zbr->leaf);
+ ubifs_assert(c, zbr->len != 0);
err = ubifs_validate_entry(c, node);
if (err) {
@@ -277,7 +305,7 @@ static void lnc_free(struct ubifs_zbranch *zbr)
}
/**
- * tnc_read_node_nm - read a "hashed" leaf node.
+ * tnc_read_hashed_node - read a "hashed" leaf node.
* @c: UBIFS file-system description object
* @zbr: key and position of the node
* @node: node is returned here
@@ -287,21 +315,33 @@ static void lnc_free(struct ubifs_zbranch *zbr)
* added to LNC. Returns zero in case of success or a negative negative error
* code in case of failure.
*/
-static int tnc_read_node_nm(struct ubifs_info *c, struct ubifs_zbranch *zbr,
- void *node)
+static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
+ void *node)
{
int err;
- ubifs_assert(is_hash_key(c, &zbr->key));
+ ubifs_assert(c, is_hash_key(c, &zbr->key));
if (zbr->leaf) {
/* Read from the leaf node cache */
- ubifs_assert(zbr->len != 0);
+ ubifs_assert(c, zbr->len != 0);
memcpy(node, zbr->leaf, zbr->len);
return 0;
}
- err = ubifs_tnc_read_node(c, zbr, node);
+ if (c->replaying) {
+ err = fallible_read_node(c, &zbr->key, zbr, node);
+ /*
+ * When the node was not found, return -ENOENT, 0 otherwise.
+ * Negative return codes stay as-is.
+ */
+ if (err == 0)
+ err = -ENOENT;
+ else if (err == 1)
+ err = 0;
+ } else {
+ err = ubifs_tnc_read_node(c, zbr, node);
+ }
if (err)
return err;
@@ -418,7 +458,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key,
* of failure, a negative error code is returned.
*/
static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
- const struct qstr *nm)
+ const struct fscrypt_name *nm)
{
struct ubifs_dent_node *dent;
int nlen, err;
@@ -441,11 +481,11 @@ static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr,
dent = zbr->leaf;
nlen = le16_to_cpu(dent->nlen);
- err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+ err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
if (err == 0) {
- if (nlen == nm->len)
+ if (nlen == fname_len(nm))
return NAME_MATCHES;
- else if (nlen < nm->len)
+ else if (nlen < fname_len(nm))
return NAME_LESS;
else
return NAME_GREATER;
@@ -588,7 +628,7 @@ static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n)
*/
static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_znode **zn, int *n,
- const struct qstr *nm)
+ const struct fscrypt_name *nm)
{
int err;
@@ -603,7 +643,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
while (1) {
err = tnc_prev(c, zn, n);
if (err == -ENOENT) {
- ubifs_assert(*n == 0);
+ ubifs_assert(c, *n == 0);
*n = -1;
return 0;
}
@@ -643,12 +683,12 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
err = tnc_next(c, zn, n);
if (err) {
/* Should be impossible */
- ubifs_assert(0);
+ ubifs_assert(c, 0);
if (err == -ENOENT)
err = -EINVAL;
return err;
}
- ubifs_assert(*n == 0);
+ ubifs_assert(c, *n == 0);
*n = -1;
}
return 0;
@@ -660,7 +700,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
return 0;
if (err == NAME_MATCHES)
return 1;
- ubifs_assert(err == NAME_GREATER);
+ ubifs_assert(c, err == NAME_GREATER);
}
} else {
int nn = *n;
@@ -684,7 +724,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
*n = nn;
if (err == NAME_MATCHES)
return 1;
- ubifs_assert(err == NAME_LESS);
+ ubifs_assert(c, err == NAME_LESS);
}
}
}
@@ -706,7 +746,7 @@ static int resolve_collision(struct ubifs_info *c, const union ubifs_key *key,
*/
static int fallible_matches_name(struct ubifs_info *c,
struct ubifs_zbranch *zbr,
- const struct qstr *nm)
+ const struct fscrypt_name *nm)
{
struct ubifs_dent_node *dent;
int nlen, err;
@@ -725,7 +765,7 @@ static int fallible_matches_name(struct ubifs_info *c,
err = NOT_ON_MEDIA;
goto out_free;
}
- ubifs_assert(err == 1);
+ ubifs_assert(c, err == 1);
err = lnc_add_directly(c, zbr, dent);
if (err)
@@ -734,11 +774,11 @@ static int fallible_matches_name(struct ubifs_info *c,
dent = zbr->leaf;
nlen = le16_to_cpu(dent->nlen);
- err = memcmp(dent->name, nm->name, min_t(int, nlen, nm->len));
+ err = memcmp(dent->name, fname_name(nm), min_t(int, nlen, fname_len(nm)));
if (err == 0) {
- if (nlen == nm->len)
+ if (nlen == fname_len(nm))
return NAME_MATCHES;
- else if (nlen < nm->len)
+ else if (nlen < fname_len(nm))
return NAME_LESS;
else
return NAME_GREATER;
@@ -777,7 +817,8 @@ out_free:
static int fallible_resolve_collision(struct ubifs_info *c,
const union ubifs_key *key,
struct ubifs_znode **zn, int *n,
- const struct qstr *nm, int adding)
+ const struct fscrypt_name *nm,
+ int adding)
{
struct ubifs_znode *o_znode = NULL, *znode = *zn;
int uninitialized_var(o_n), err, cmp, unsure = 0, nn = *n;
@@ -804,7 +845,7 @@ static int fallible_resolve_collision(struct ubifs_info *c,
while (1) {
err = tnc_prev(c, zn, n);
if (err == -ENOENT) {
- ubifs_assert(*n == 0);
+ ubifs_assert(c, *n == 0);
*n = -1;
break;
}
@@ -816,12 +857,12 @@ static int fallible_resolve_collision(struct ubifs_info *c,
err = tnc_next(c, zn, n);
if (err) {
/* Should be impossible */
- ubifs_assert(0);
+ ubifs_assert(c, 0);
if (err == -ENOENT)
err = -EINVAL;
return err;
}
- ubifs_assert(*n == 0);
+ ubifs_assert(c, *n == 0);
*n = -1;
}
break;
@@ -885,6 +926,25 @@ static int fallible_resolve_collision(struct ubifs_info *c,
return 1;
}
+/*
+ * removed in barebox
+static int matches_position(struct ubifs_zbranch *zbr, int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static int resolve_collision_directly(struct ubifs_info *c,
+ const union ubifs_key *key,
+ struct ubifs_znode **zn, int *n,
+ int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static struct ubifs_znode *dirty_cow_bottom_up(struct ubifs_info *c,
+ struct ubifs_znode *znode)
+ */
+
/**
* ubifs_lookup_level0 - search for zero-level znode.
* @c: UBIFS file-system description object
@@ -912,10 +972,9 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
{
int err, exact;
struct ubifs_znode *znode;
- unsigned long time = get_seconds();
dbg_tnck(key, "search key ");
- ubifs_assert(key_type(c, key) < UBIFS_INVALID_KEY);
+ ubifs_assert(c, key_type(c, key) < UBIFS_INVALID_KEY);
znode = c->zroot.znode;
if (unlikely(!znode)) {
@@ -924,8 +983,6 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
return PTR_ERR(znode);
}
- znode->time = time;
-
while (1) {
struct ubifs_zbranch *zbr;
@@ -939,7 +996,6 @@ int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
zbr = &znode->zbranch[*n];
if (zbr->znode) {
- znode->time = time;
znode = zbr->znode;
continue;
}
@@ -1048,7 +1104,6 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
{
int err, exact;
struct ubifs_znode *znode;
- unsigned long time = get_seconds();
dbg_tnck(key, "search and dirty key ");
@@ -1063,8 +1118,6 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
if (IS_ERR(znode))
return PTR_ERR(znode);
- znode->time = time;
-
while (1) {
struct ubifs_zbranch *zbr;
@@ -1078,7 +1131,6 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
zbr = &znode->zbranch[*n];
if (zbr->znode) {
- znode->time = time;
znode = dirty_cow_znode(c, zbr);
if (IS_ERR(znode))
return PTR_ERR(znode);
@@ -1135,7 +1187,7 @@ static int lookup_level0_dirty(struct ubifs_info *c, const union ubifs_key *key,
*/
static int maybe_leb_gced(struct ubifs_info *c, int lnum, int gc_seq1)
{
- /* No garbage collection in the read-only U-Boot implementation */
+ /* No GC in barebox */
return 0;
}
@@ -1179,7 +1231,7 @@ again:
* In this case the leaf node cache gets used, so we pass the
* address of the zbranch and keep the mutex locked
*/
- err = tnc_read_node_nm(c, zt, node);
+ err = tnc_read_hashed_node(c, zt, node);
goto out;
}
if (safely) {
@@ -1207,6 +1259,28 @@ out:
return err;
}
+/*
+ * removed in barebox
+int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu)
+ */
+
+/*
+ * removed in barebox
+static int read_wbuf(struct ubifs_wbuf *wbuf, void *buf, int len, int lnum,
+ int offs)
+ */
+
+/*
+ * removed in barebox
+static int validate_data_node(struct ubifs_info *c, void *buf,
+ struct ubifs_zbranch *zbr)
+ */
+
+/*
+ * removed in barebox
+int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu)
+ */
+
/**
* do_lookup_nm- look up a "hashed" node.
* @c: UBIFS file-system description object
@@ -1214,19 +1288,19 @@ out:
* @node: the node is returned here
* @nm: node name
*
- * This function look up and reads a node which contains name hash in the key.
+ * This function looks up and reads a node which contains name hash in the key.
* Since the hash may have collisions, there may be many nodes with the same
* key, so we have to sequentially look to all of them until the needed one is
* found. This function returns zero in case of success, %-ENOENT if the node
* was not found, and a negative error code in case of failure.
*/
static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
- void *node, const struct qstr *nm)
+ void *node, const struct fscrypt_name *nm)
{
int found, n, err;
struct ubifs_znode *znode;
- dbg_tnck(key, "name '%.*s' key ", nm->len, nm->name);
+ dbg_tnck(key, "key ");
mutex_lock(&c->tnc_mutex);
found = ubifs_lookup_level0(c, key, &znode, &n);
if (!found) {
@@ -1237,7 +1311,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
goto out_unlock;
}
- ubifs_assert(n >= 0);
+ ubifs_assert(c, n >= 0);
err = resolve_collision(c, key, &znode, &n, nm);
dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
@@ -1248,7 +1322,7 @@ static int do_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
goto out_unlock;
}
- err = tnc_read_node_nm(c, &znode->zbranch[n], node);
+ err = tnc_read_hashed_node(c, &znode->zbranch[n], node);
out_unlock:
mutex_unlock(&c->tnc_mutex);
@@ -1262,14 +1336,14 @@ out_unlock:
* @node: the node is returned here
* @nm: node name
*
- * This function look up and reads a node which contains name hash in the key.
+ * This function looks up and reads a node which contains name hash in the key.
* Since the hash may have collisions, there may be many nodes with the same
* key, so we have to sequentially look to all of them until the needed one is
* found. This function returns zero in case of success, %-ENOENT if the node
* was not found, and a negative error code in case of failure.
*/
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
- void *node, const struct qstr *nm)
+ void *node, const struct fscrypt_name *nm)
{
int err, len;
const struct ubifs_dent_node *dent = node;
@@ -1283,16 +1357,115 @@ int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
return err;
len = le16_to_cpu(dent->nlen);
- if (nm->len == len && !memcmp(dent->name, nm->name, len))
+ if (fname_len(nm) == len && !memcmp(dent->name, fname_name(nm), len))
return 0;
/*
* Unluckily, there are hash collisions and we have to iterate over
* them look at each direntry with colliding name hash sequentially.
*/
+
return do_lookup_nm(c, key, node, nm);
}
+static int search_dh_cookie(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_dent_node *dent, uint32_t cookie,
+ struct ubifs_znode **zn, int *n)
+{
+ int err;
+ struct ubifs_znode *znode = *zn;
+ struct ubifs_zbranch *zbr;
+ union ubifs_key *dkey;
+
+ for (;;) {
+ zbr = &znode->zbranch[*n];
+ dkey = &zbr->key;
+
+ if (key_inum(c, dkey) != key_inum(c, key) ||
+ key_type(c, dkey) != key_type(c, key)) {
+ return -ENOENT;
+ }
+
+ err = tnc_read_hashed_node(c, zbr, dent);
+ if (err)
+ return err;
+
+ if (key_hash(c, key) == key_hash(c, dkey) &&
+ le32_to_cpu(dent->cookie) == cookie) {
+ *zn = znode;
+ return 0;
+ }
+
+ err = tnc_next(c, &znode, n);
+ if (err)
+ return err;
+ }
+}
+
+static int do_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+ struct ubifs_dent_node *dent, uint32_t cookie)
+{
+ int n, err;
+ struct ubifs_znode *znode;
+ union ubifs_key start_key;
+
+ ubifs_assert(c, is_hash_key(c, key));
+
+ lowest_dent_key(c, &start_key, key_inum(c, key));
+
+ mutex_lock(&c->tnc_mutex);
+ err = ubifs_lookup_level0(c, &start_key, &znode, &n);
+ if (unlikely(err < 0))
+ goto out_unlock;
+
+ err = search_dh_cookie(c, key, dent, cookie, &znode, &n);
+
+out_unlock:
+ mutex_unlock(&c->tnc_mutex);
+ return err;
+}
+
+/**
+ * ubifs_tnc_lookup_dh - look up a "double hashed" node.
+ * @c: UBIFS file-system description object
+ * @key: node key to lookup
+ * @node: the node is returned here
+ * @cookie: node cookie for collision resolution
+ *
+ * This function looks up and reads a node which contains name hash in the key.
+ * Since the hash may have collisions, there may be many nodes with the same
+ * key, so we have to sequentially look to all of them until the needed one
+ * with the same cookie value is found.
+ * This function returns zero in case of success, %-ENOENT if the node
+ * was not found, and a negative error code in case of failure.
+ */
+int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, uint32_t cookie)
+{
+ int err;
+ const struct ubifs_dent_node *dent = node;
+
+ if (!c->double_hash)
+ return -EOPNOTSUPP;
+
+ /*
+ * We assume that in most of the cases there are no name collisions and
+ * 'ubifs_tnc_lookup()' returns us the right direntry.
+ */
+ err = ubifs_tnc_lookup(c, key, node);
+ if (err)
+ return err;
+
+ if (le32_to_cpu(dent->cookie) == cookie)
+ return 0;
+
+ /*
+ * Unluckily, there are hash collisions and we have to iterate over
+ * them look at each direntry with colliding name hash sequentially.
+ */
+ return do_lookup_dh(c, key, node, cookie);
+}
+
/**
* correct_parent_keys - correct parent znodes' keys.
* @c: UBIFS file-system description object
@@ -1307,8 +1480,8 @@ static void correct_parent_keys(const struct ubifs_info *c,
{
union ubifs_key *key, *key1;
- ubifs_assert(znode->parent);
- ubifs_assert(znode->iip == 0);
+ ubifs_assert(c, znode->parent);
+ ubifs_assert(c, znode->iip == 0);
key = &znode->zbranch[0].key;
key1 = &znode->parent->zbranch[0].key;
@@ -1325,6 +1498,7 @@ static void correct_parent_keys(const struct ubifs_info *c,
/**
* insert_zbranch - insert a zbranch into a znode.
+ * @c: UBIFS file-system description object
* @znode: znode into which to insert
* @zbr: zbranch to insert
* @n: slot number to insert to
@@ -1334,11 +1508,13 @@ static void correct_parent_keys(const struct ubifs_info *c,
* zbranch has to be inserted to the @znode->zbranches[]' array at the @n-th
* slot, zbranches starting from @n have to be moved right.
*/
-static void insert_zbranch(struct ubifs_znode *znode,
+static void insert_zbranch(struct ubifs_info *c, struct ubifs_znode *znode,
const struct ubifs_zbranch *zbr, int n)
{
int i;
+ /* znode is never dirty in barebox ro implementation */
+
if (znode->level) {
for (i = znode->child_cnt; i > n; i--) {
znode->zbranch[i] = znode->zbranch[i - 1];
@@ -1391,16 +1567,16 @@ static int tnc_insert(struct ubifs_info *c, struct ubifs_znode *znode,
int i, keep, move, appending = 0;
union ubifs_key *key = &zbr->key, *key1;
- ubifs_assert(n >= 0 && n <= c->fanout);
+ ubifs_assert(c, n >= 0 && n <= c->fanout);
/* Implement naive insert for now */
again:
zp = znode->parent;
if (znode->child_cnt < c->fanout) {
- ubifs_assert(n != c->fanout);
+ ubifs_assert(c, n != c->fanout);
dbg_tnck(key, "inserted at %d level %d, key ", n, znode->level);
- insert_zbranch(znode, zbr, n);
+ insert_zbranch(c, znode, zbr, n);
/* Ensure parent's key is correct */
if (n == 0 && zp && znode->iip == 0)
@@ -1509,7 +1685,7 @@ do_split:
/* Insert new key and branch */
dbg_tnck(key, "inserting at %d level %d, key ", n, zn->level);
- insert_zbranch(zi, zbr, n);
+ insert_zbranch(c, zi, zbr, n);
/* Insert new znode (produced by spitting) into the parent */
if (zp) {
@@ -1611,6 +1787,12 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
return err;
}
+/*
+ * removed in barebox
+int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
+ int old_lnum, int old_offs, int lnum, int offs, int len)
+ */
+
/**
* ubifs_tnc_add_nm - add a "hashed" node to TNC.
* @c: UBIFS file-system description object
@@ -1624,14 +1806,14 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
* may have collisions, like directory entry keys.
*/
int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
- int lnum, int offs, int len, const struct qstr *nm)
+ int lnum, int offs, int len,
+ const struct fscrypt_name *nm)
{
int found, n, err = 0;
struct ubifs_znode *znode;
mutex_lock(&c->tnc_mutex);
- dbg_tnck(key, "LEB %d:%d, name '%.*s', key ",
- lnum, offs, nm->len, nm->name);
+ dbg_tnck(key, "LEB %d:%d, key ", lnum, offs);
found = lookup_level0_dirty(c, key, &znode, &n);
if (found < 0) {
err = found;
@@ -1680,7 +1862,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
* by passing 'ubifs_tnc_remove_nm()' the same key but
* an unmatchable name.
*/
- struct qstr noname = { .name = "" };
+ struct fscrypt_name noname = { .disk_name = { .name = "", .len = 1 } };
err = dbg_check_tnc(c, 0);
mutex_unlock(&c->tnc_mutex);
@@ -1713,8 +1895,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
int i, err;
/* Delete without merge for now */
- ubifs_assert(znode->level == 0);
- ubifs_assert(n >= 0 && n < c->fanout);
+ ubifs_assert(c, znode->level == 0);
+ ubifs_assert(c, n >= 0 && n < c->fanout);
dbg_tnck(&znode->zbranch[n].key, "deleting key ");
zbr = &znode->zbranch[n];
@@ -1740,8 +1922,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
*/
do {
- ubifs_assert(!ubifs_zn_obsolete(znode));
- ubifs_assert(ubifs_zn_dirty(znode));
+ ubifs_assert(c, !ubifs_zn_obsolete(znode));
+ ubifs_assert(c, ubifs_zn_dirty(znode));
zp = znode->parent;
n = znode->iip;
@@ -1763,7 +1945,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
/* Remove from znode, entry n - 1 */
znode->child_cnt -= 1;
- ubifs_assert(znode->level != 0);
+ ubifs_assert(c, znode->level != 0);
for (i = n; i < znode->child_cnt; i++) {
znode->zbranch[i] = znode->zbranch[i + 1];
if (znode->zbranch[i].znode)
@@ -1796,8 +1978,8 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n)
c->zroot.offs = zbr->offs;
c->zroot.len = zbr->len;
c->zroot.znode = znode;
- ubifs_assert(!ubifs_zn_obsolete(zp));
- ubifs_assert(ubifs_zn_dirty(zp));
+ ubifs_assert(c, !ubifs_zn_obsolete(zp));
+ ubifs_assert(c, ubifs_zn_dirty(zp));
atomic_long_dec(&c->dirty_zn_cnt);
if (zp->cnext) {
@@ -1850,13 +2032,13 @@ out_unlock:
* Returns %0 on success or negative error code on failure.
*/
int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
- const struct qstr *nm)
+ const struct fscrypt_name *nm)
{
int n, err;
struct ubifs_znode *znode;
mutex_lock(&c->tnc_mutex);
- dbg_tnck(key, "%.*s, key ", nm->len, nm->name);
+ dbg_tnck(key, "key ");
err = lookup_level0_dirty(c, key, &znode, &n);
if (err < 0)
goto out_unlock;
@@ -1870,8 +2052,9 @@ int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
dbg_tnc("rc returned %d, znode %p, n %d", err, znode, n);
if (err < 0)
goto out_unlock;
- if (err)
+ if (err) {
err = tnc_delete(c, znode, n);
+ }
}
out_unlock:
@@ -1881,6 +2064,12 @@ out_unlock:
return err;
}
+/*
+ * removed in barebox
+int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key,
+ uint32_t cookie)
+ */
+
/**
* key_in_range - determine if a key falls within a range of keys.
* @c: UBIFS file-system description object
@@ -1987,7 +2176,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
{
union ubifs_key key1, key2;
struct ubifs_dent_node *xent, *pxent = NULL;
- struct qstr nm = { .name = NULL };
+ struct fscrypt_name nm = {0};
dbg_tnc("ino %lu", (unsigned long)inum);
@@ -2012,8 +2201,10 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
dbg_tnc("xent '%s', ino %lu", xent->name,
(unsigned long)xattr_inum);
- nm.name = xent->name;
- nm.len = le16_to_cpu(xent->nlen);
+ ubifs_evict_xattr_inode(c, xattr_inum);
+
+ fname_name(&nm) = xent->name;
+ fname_len(&nm) = le16_to_cpu(xent->nlen);
err = ubifs_tnc_remove_nm(c, &key1, &nm);
if (err) {
kfree(xent);
@@ -2065,7 +2256,7 @@ int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum)
*/
struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
union ubifs_key *key,
- const struct qstr *nm)
+ const struct fscrypt_name *nm)
{
int n, err, type = key_type(c, key);
struct ubifs_znode *znode;
@@ -2073,18 +2264,22 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
struct ubifs_zbranch *zbr;
union ubifs_key *dkey;
- dbg_tnck(key, "%s ", nm->name ? (char *)nm->name : "(lowest)");
- ubifs_assert(is_hash_key(c, key));
+ dbg_tnck(key, "key ");
+ ubifs_assert(c, is_hash_key(c, key));
mutex_lock(&c->tnc_mutex);
err = ubifs_lookup_level0(c, key, &znode, &n);
if (unlikely(err < 0))
goto out_unlock;
- if (nm->name) {
+ if (fname_len(nm) > 0) {
if (err) {
/* Handle collisions */
- err = resolve_collision(c, key, &znode, &n, nm);
+ if (c->replaying)
+ err = fallible_resolve_collision(c, key, &znode, &n,
+ nm, 0);
+ else
+ err = resolve_collision(c, key, &znode, &n, nm);
dbg_tnc("rc returned %d, znode %p, n %d",
err, znode, n);
if (unlikely(err < 0))
@@ -2131,7 +2326,7 @@ struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
goto out_free;
}
- err = tnc_read_node_nm(c, zbr, dent);
+ err = tnc_read_hashed_node(c, zbr, dent);
if (unlikely(err))
goto out_free;
@@ -2157,7 +2352,7 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
if (!c->cnext)
return;
- ubifs_assert(c->cmt_state == COMMIT_BROKEN);
+ ubifs_assert(c, c->cmt_state == COMMIT_BROKEN);
cnext = c->cnext;
do {
struct ubifs_znode *znode = cnext;
@@ -2179,11 +2374,60 @@ void ubifs_tnc_close(struct ubifs_info *c)
long n, freed;
n = atomic_long_read(&c->clean_zn_cnt);
- freed = ubifs_destroy_tnc_subtree(c->zroot.znode);
- ubifs_assert(freed == n);
+ freed = ubifs_destroy_tnc_subtree(c, c->zroot.znode);
+ ubifs_assert(c, freed == n);
atomic_long_sub(n, &ubifs_clean_zn_cnt);
}
kfree(c->gap_lebs);
kfree(c->ilebs);
destroy_old_idx(c);
}
+
+/*
+ * removed in barebox
+static struct ubifs_znode *left_znode(struct ubifs_info *c,
+ struct ubifs_znode *znode)
+ */
+
+/*
+ * removed in barebox
+static struct ubifs_znode *right_znode(struct ubifs_info *c,
+ struct ubifs_znode *znode)
+ */
+
+/*
+ * removed in barebox
+static struct ubifs_znode *lookup_znode(struct ubifs_info *c,
+ union ubifs_key *key, int level,
+ int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+int is_idx_node_in_tnc(struct ubifs_info *c, union ubifs_key *key, int level,
+ int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+static int is_leaf_node_in_tnc(struct ubifs_info *c, union ubifs_key *key,
+ int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
+ int lnum, int offs, int is_idx)
+ */
+
+/*
+ * removed in barebox
+int ubifs_dirty_idx_node(struct ubifs_info *c, union ubifs_key *key, int level,
+ int lnum, int offs)
+ */
+
+/*
+ * removed in barebox
+int dbg_check_inode_size(struct ubifs_info *c, const struct inode *inode,
+ loff_t size)
+ */
diff --git a/fs/ubifs/tnc_misc.c b/fs/ubifs/tnc_misc.c
index 1619d08be8..3106c9d511 100644
--- a/fs/ubifs/tnc_misc.c
+++ b/fs/ubifs/tnc_misc.c
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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 (Битюцкий Артём)
@@ -16,24 +27,25 @@
* putting it all in one file would make that file too big and unreadable.
*/
-#include <linux/err.h>
#include "ubifs.h"
/**
* ubifs_tnc_levelorder_next - next TNC tree element in levelorder traversal.
+ * @c: UBIFS file-system description object
* @zr: root of the subtree to traverse
* @znode: previous znode
*
* This function implements levelorder TNC traversal. The LNC is ignored.
* Returns the next element or %NULL if @znode is already the last one.
*/
-struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
+struct ubifs_znode *ubifs_tnc_levelorder_next(const struct ubifs_info *c,
+ struct ubifs_znode *zr,
struct ubifs_znode *znode)
{
int level, iip, level_search = 0;
struct ubifs_znode *zn;
- ubifs_assert(zr);
+ ubifs_assert(c, zr);
if (unlikely(!znode))
return zr;
@@ -48,7 +60,7 @@ struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
iip = znode->iip;
while (1) {
- ubifs_assert(znode->level <= zr->level);
+ ubifs_assert(c, znode->level <= zr->level);
/*
* First walk up until there is a znode with next branch to
@@ -75,7 +87,7 @@ struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
level_search = 1;
iip = -1;
znode = ubifs_tnc_find_child(zr, 0);
- ubifs_assert(znode);
+ ubifs_assert(c, znode);
}
/* Switch to the next index */
@@ -101,7 +113,7 @@ struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
}
if (zn) {
- ubifs_assert(zn->level >= 0);
+ ubifs_assert(c, zn->level >= 0);
return zn;
}
}
@@ -130,7 +142,7 @@ int ubifs_search_zbranch(const struct ubifs_info *c,
int uninitialized_var(cmp);
const struct ubifs_zbranch *zbr = &znode->zbranch[0];
- ubifs_assert(end > beg);
+ ubifs_assert(c, end > beg);
while (end > beg) {
mid = (beg + end) >> 1;
@@ -148,13 +160,13 @@ int ubifs_search_zbranch(const struct ubifs_info *c,
*n = end - 1;
/* The insert point is after *n */
- ubifs_assert(*n >= -1 && *n < znode->child_cnt);
+ ubifs_assert(c, *n >= -1 && *n < znode->child_cnt);
if (*n == -1)
- ubifs_assert(keys_cmp(c, key, &zbr[0].key) < 0);
+ ubifs_assert(c, keys_cmp(c, key, &zbr[0].key) < 0);
else
- ubifs_assert(keys_cmp(c, key, &zbr[*n].key) > 0);
+ ubifs_assert(c, keys_cmp(c, key, &zbr[*n].key) > 0);
if (*n + 1 < znode->child_cnt)
- ubifs_assert(keys_cmp(c, key, &zbr[*n + 1].key) < 0);
+ ubifs_assert(c, keys_cmp(c, key, &zbr[*n + 1].key) < 0);
return 0;
}
@@ -185,16 +197,18 @@ struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode)
/**
* ubifs_tnc_postorder_next - next TNC tree element in postorder traversal.
+ * @c: UBIFS file-system description object
* @znode: previous znode
*
* This function implements postorder TNC traversal. The LNC is ignored.
* Returns the next element or %NULL if @znode is already the last one.
*/
-struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode)
+struct ubifs_znode *ubifs_tnc_postorder_next(const struct ubifs_info *c,
+ struct ubifs_znode *znode)
{
struct ubifs_znode *zn;
- ubifs_assert(znode);
+ ubifs_assert(c, znode);
if (unlikely(!znode->parent))
return NULL;
@@ -210,18 +224,20 @@ struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode)
/**
* ubifs_destroy_tnc_subtree - destroy all znodes connected to a subtree.
+ * @c: UBIFS file-system description object
* @znode: znode defining subtree to destroy
*
* This function destroys subtree of the TNC tree. Returns number of clean
* znodes in the subtree.
*/
-long ubifs_destroy_tnc_subtree(struct ubifs_znode *znode)
+long ubifs_destroy_tnc_subtree(const struct ubifs_info *c,
+ struct ubifs_znode *znode)
{
struct ubifs_znode *zn = ubifs_tnc_postorder_first(znode);
long clean_freed = 0;
int n;
- ubifs_assert(zn);
+ ubifs_assert(c, zn);
while (1) {
for (n = 0; n < zn->child_cnt; n++) {
if (!zn->zbranch[n].znode)
@@ -242,7 +258,7 @@ long ubifs_destroy_tnc_subtree(struct ubifs_znode *znode)
return clean_freed;
}
- zn = ubifs_tnc_postorder_next(zn);
+ zn = ubifs_tnc_postorder_next(c, zn);
}
}
@@ -400,7 +416,7 @@ struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
int err;
struct ubifs_znode *znode;
- ubifs_assert(!zbr->znode);
+ ubifs_assert(c, !zbr->znode);
/*
* A slab cache is not presently used for znodes because the znode size
* depends on the fanout which is stored in the superblock.
@@ -425,7 +441,6 @@ struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
zbr->znode = znode;
znode->parent = parent;
- znode->time = get_seconds();
znode->iip = iip;
return znode;
@@ -453,7 +468,6 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
err = ubifs_read_node(c, node, type, zbr->len, zbr->lnum,
zbr->offs);
-
if (err) {
dbg_tnck(key, "key ");
return err;
diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h
index 3462249848..e8c23c9d4f 100644
--- a/fs/ubifs/ubifs-media.h
+++ b/fs/ubifs/ubifs-media.h
@@ -3,7 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -35,7 +46,7 @@
* UBIFS went into mainline kernel with format version 4. The older formats
* were development formats.
*/
-#define UBIFS_FORMAT_VERSION 4
+#define UBIFS_FORMAT_VERSION 5
/*
* Read-only compatibility version. If the UBIFS format is changed, older UBIFS
@@ -289,6 +300,13 @@ enum {
/* The largest UBIFS node */
#define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ
+/*
+ * xattr name of UBIFS encryption context, we don't use a prefix
+ * nor a long name to not waste space on the flash.
+ */
+#define UBIFS_XATTR_NAME_ENCRYPTION_CONTEXT "c"
+
+
/*
* On-flash inode flags.
*
@@ -298,6 +316,7 @@ enum {
* UBIFS_APPEND_FL: writes to the inode may only append data
* UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous
* UBIFS_XATTR_FL: this inode is the inode for an extended attribute value
+ * UBIFS_CRYPT_FL: use encryption for this inode
*
* Note, these are on-flash flags which correspond to ioctl flags
* (@FS_COMPR_FL, etc). They have the same values now, but generally, do not
@@ -310,6 +329,7 @@ enum {
UBIFS_APPEND_FL = 0x08,
UBIFS_DIRSYNC_FL = 0x10,
UBIFS_XATTR_FL = 0x20,
+ UBIFS_CRYPT_FL = 0x40,
};
/* Inode flag bits used by UBIFS */
@@ -398,12 +418,19 @@ enum {
*
* UBIFS_FLG_BIGLPT: if "big" LPT model is used if set
* UBIFS_FLG_SPACE_FIXUP: first-mount "fixup" of free space within LEBs needed
+ * UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to
+ * support 64bit cookies for lookups by hash
+ * UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files
*/
enum {
UBIFS_FLG_BIGLPT = 0x02,
UBIFS_FLG_SPACE_FIXUP = 0x04,
+ UBIFS_FLG_DOUBLE_HASH = 0x08,
+ UBIFS_FLG_ENCRYPTION = 0x10,
};
+#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT|UBIFS_FLG_SPACE_FIXUP|UBIFS_FLG_DOUBLE_HASH|UBIFS_FLG_ENCRYPTION)
+
/**
* struct ubifs_ch - common header node.
* @magic: UBIFS node magic number (%UBIFS_NODE_MAGIC)
@@ -510,7 +537,8 @@ struct ubifs_ino_node {
* @padding1: reserved for future, zeroes
* @type: type of the target inode (%UBIFS_ITYPE_REG, %UBIFS_ITYPE_DIR, etc)
* @nlen: name length
- * @padding2: reserved for future, zeroes
+ * @cookie: A 32bits random number, used to construct a 64bits
+ * identifier.
* @name: zero-terminated name
*
* Note, do not forget to amend 'zero_dent_node_unused()' function when
@@ -523,8 +551,8 @@ struct ubifs_dent_node {
__u8 padding1;
__u8 type;
__le16 nlen;
- __u8 padding2[4]; /* Watch 'zero_dent_node_unused()' if changing! */
- char name[];
+ __le32 cookie;
+ __u8 name[];
} __packed;
/**
@@ -533,18 +561,16 @@ struct ubifs_dent_node {
* @key: node key
* @size: uncompressed data size in bytes
* @compr_type: compression type (%UBIFS_COMPR_NONE, %UBIFS_COMPR_LZO, etc)
- * @padding: reserved for future, zeroes
+ * @compr_size: compressed data size in bytes, only valid when data is encrypted
* @data: data
*
- * Note, do not forget to amend 'zero_data_node_unused()' function when
- * changing the padding fields.
*/
struct ubifs_data_node {
struct ubifs_ch ch;
__u8 key[UBIFS_MAX_KEY_LEN];
__le32 size;
__le16 compr_type;
- __u8 padding[2]; /* Watch 'zero_data_node_unused()' if changing! */
+ __le16 compr_size;
__u8 data[];
} __packed;
@@ -731,7 +757,7 @@ struct ubifs_branch {
__le32 lnum;
__le32 offs;
__le32 len;
- char key[];
+ __u8 key[];
} __packed;
/**
@@ -745,7 +771,7 @@ struct ubifs_idx_node {
struct ubifs_ch ch;
__le16 child_cnt;
__le16 level;
- char branches[];
+ __u8 branches[];
} __packed;
/**
diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c
index 99612732dd..11fb3187ad 100644
--- a/fs/ubifs/ubifs.c
+++ b/fs/ubifs/ubifs.c
@@ -23,6 +23,8 @@
#include <linux/err.h>
+struct task_struct *current;
+
struct ubifs_priv {
struct cdev *cdev;
struct ubi_volume_desc *ubi;
@@ -262,7 +264,7 @@ static int read_block(struct inode *inode, void *addr, unsigned int block,
return err;
}
- ubifs_assert(le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);
+ ubifs_assert(c, le64_to_cpu(dn->ch.sqnum) > ubifs_inode(inode)->creat_sqnum);
len = le32_to_cpu(dn->size);
if (len <= 0 || len > UBIFS_BLOCK_SIZE)
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h
index b3ad054ba7..900cc31177 100644
--- a/fs/ubifs/ubifs.h
+++ b/fs/ubifs/ubifs.h
@@ -3,10 +3,18 @@
*
* Copyright (C) 2006-2008 Nokia Corporation
*
- * (C) Copyright 2008-2009
- * Stefan Roese, DENX Software Engineering, sr@denx.de.
+ * 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.
*
- * SPDX-License-Identifier: GPL-2.0+
+ * 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: Artem Bityutskiy (Битюцкий Артём)
* Adrian Hunter
@@ -20,6 +28,7 @@
#include <crc.h>
#include <linux/fs.h>
#include <linux/stat.h>
+#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/ctype.h>
#include <linux/time.h>
@@ -29,59 +38,29 @@
#include <linux/pagemap.h>
#include <asm/atomic.h>
#include <asm-generic/atomic-long.h>
+
+#define __FS_HAS_ENCRYPTION 0
+#include <linux/fscrypt.h>
+
#include "ubifs-media.h"
#define crc32(seed, data, length) crc32_no_comp(seed, (unsigned char const *)data, length)
-struct file;
struct iattr;
struct kstat;
-struct page;
/* uapi/linux/limits.h */
#define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */
-/*
- * get_seconds() not really needed in the read-only implmentation
- */
-#define get_seconds() 0
-
-/* debug.c */
-
/* Version of this UBIFS implementation */
#define UBIFS_VERSION 1
-/* Normal UBIFS messages */
-#define ubifs_msg(c, fmt, ...) \
- pr_notice("UBIFS (ubi%d:%d): " fmt "\n", \
- (c)->vi.ubi_num, (c)->vi.vol_id, ##__VA_ARGS__)
-/* UBIFS error messages */
-#define ubifs_err(c, fmt, ...) \
- pr_err("UBIFS error (ubi%d:%d pid %d): %s: " fmt "\n", \
- (c)->vi.ubi_num, (c)->vi.vol_id, 0, \
- __func__, ##__VA_ARGS__)
-/* UBIFS warning messages */
-#define ubifs_warn(c, fmt, ...) \
- pr_warn("UBIFS warning (ubi%d:%d pid %d): %s: " fmt "\n", \
- (c)->vi.ubi_num, (c)->vi.vol_id, 0, \
- __func__, ##__VA_ARGS__)
-
-/*
- * A variant of 'ubifs_err()' which takes the UBIFS file-sytem description
- * object as an argument.
- */
-#define ubifs_errc(c, fmt, ...) \
- do { \
- if (!(c)->probing) \
- ubifs_err(c, fmt, ##__VA_ARGS__); \
- } while (0)
-
/* UBIFS file system VFS magic number */
#define UBIFS_SUPER_MAGIC 0x24051905
/* Number of UBIFS blocks per VFS page */
-#define UBIFS_BLOCKS_PER_PAGE (PAGE_CACHE_SIZE / UBIFS_BLOCK_SIZE)
-#define UBIFS_BLOCKS_PER_PAGE_SHIFT (PAGE_CACHE_SHIFT - UBIFS_BLOCK_SHIFT)
+#define UBIFS_BLOCKS_PER_PAGE (PAGE_SIZE / UBIFS_BLOCK_SIZE)
+#define UBIFS_BLOCKS_PER_PAGE_SHIFT (PAGE_SHIFT - UBIFS_BLOCK_SHIFT)
/* "File system end of life" sequence number watermark */
#define SQNUM_WARN_WATERMARK 0xFFFFFFFF00000000ULL
@@ -116,10 +95,6 @@ struct page;
*/
#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
-/* Write-buffer synchronization timeout interval in seconds */
-#define WBUF_TIMEOUT_SOFTLIMIT 3
-#define WBUF_TIMEOUT_HARDLIMIT 5
-
/* Maximum possible inode number (only 32-bit inodes are supported now) */
#define MAX_INUM 0xFFFFFFFF
@@ -171,6 +146,12 @@ struct page;
*/
#define WORST_COMPR_FACTOR 2
+#ifdef CONFIG_UBIFS_FS_ENCRYPTION
+#define UBIFS_CIPHER_BLOCK_SIZE FS_CRYPTO_BLOCK_SIZE
+#else
+#define UBIFS_CIPHER_BLOCK_SIZE 0
+#endif
+
/*
* How much memory is needed for a buffer where we compress a data node.
*/
@@ -190,6 +171,7 @@ enum {
WB_MUTEX_1 = 0,
WB_MUTEX_2 = 1,
WB_MUTEX_3 = 2,
+ WB_MUTEX_4 = 3,
};
/*
@@ -283,6 +265,18 @@ enum {
LEB_RETAINED,
};
+/*
+ * Action taken upon a failed ubifs_assert().
+ * @ASSACT_REPORT: just report the failed assertion
+ * @ASSACT_RO: switch to read-only mode
+ * @ASSACT_PANIC: call BUG() and possible panic the kernel
+ */
+enum {
+ ASSACT_REPORT = 0,
+ ASSACT_RO,
+ ASSACT_PANIC,
+};
+
/**
* struct ubifs_old_idx - index node obsoleted since last commit start.
* @rb: rb-tree node
@@ -677,9 +671,6 @@ typedef int (*ubifs_lpt_scan_callback)(struct ubifs_info *c,
* @io_mutex: serializes write-buffer I/O
* @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
* fields
- * @softlimit: soft write-buffer timeout interval
- * @delta: hard and soft timeouts delta (the timer expire interval is @softlimit
- * and @softlimit + @delta)
* @timer: write-buffer timer
* @no_timer: non-zero if this write-buffer does not have a timer
* @need_sync: non-zero if the timer expired and the wbuf needs sync'ing
@@ -708,9 +699,6 @@ struct ubifs_wbuf {
int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
struct mutex io_mutex;
spinlock_t lock;
-// ktime_t softlimit;
-// unsigned long long delta;
-// struct hrtimer timer;
unsigned int no_timer:1;
unsigned int need_sync:1;
int next_ino;
@@ -788,7 +776,6 @@ struct ubifs_znode {
struct ubifs_znode *parent;
struct ubifs_znode *cnext;
unsigned long flags;
- unsigned long time;
int level;
int child_cnt;
int iip;
@@ -870,9 +857,9 @@ struct ubifs_compressor {
* @mod_dent: non-zero if the operation removes or modifies an existing
* directory entry
* @new_ino: non-zero if the operation adds a new inode
- * @new_ino_d: now much data newly created inode contains
+ * @new_ino_d: how much data newly created inode contains
* @dirtied_ino: how many inodes the operation makes dirty
- * @dirtied_ino_d: now much data dirtied inode contains
+ * @dirtied_ino_d: how much data dirtied inode contains
* @idx_growth: how much the index will supposedly grow
* @data_growth: how much new data the operation will supposedly add
* @dd_growth: how much data that makes other data dirty the operation will
@@ -1003,7 +990,6 @@ struct ubifs_debug_info;
* struct ubifs_info - UBIFS file-system description data structure
* (per-superblock).
* @vfs_sb: VFS @struct super_block object
- * @bdi: backing device info object to make VFS happy and disable read-ahead
*
* @highest_inum: highest used inode number
* @max_sqnum: current global sequence number
@@ -1041,11 +1027,14 @@ struct ubifs_debug_info;
*
* @big_lpt: flag that LPT is too big to write whole during commit
* @space_fixup: flag indicating that free space in LEBs needs to be cleaned up
+ * @double_hash: flag indicating that we can do lookups by hash
+ * @encrypted: flag indicating that this file system contains encrypted files
* @no_chk_data_crc: do not check CRCs when reading data nodes (except during
* recovery)
* @bulk_read: enable bulk-reads
* @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc)
* @rw_incompat: the media is not R/W compatible
+ * @assert_action: action to take when a ubifs_assert() fails
*
* @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and
* @calc_idx_sz
@@ -1232,12 +1221,11 @@ struct ubifs_debug_info;
* @need_recovery: %1 if the file-system needs recovery
* @replaying: %1 during journal replay
* @mounting: %1 while mounting
- * @probing: %1 while attempting to mount if MS_SILENT mount flag is set
+ * @probing: %1 while attempting to mount if SB_SILENT mount flag is set
* @remounting_rw: %1 while re-mounting from R/O mode to R/W mode
* @replay_list: temporary list used during journal replay
* @replay_buds: list of buds to replay
* @cs_sqnum: sequence number of first node in the log (commit start node)
- * @replay_sqnum: sequence number of node currently being replayed
* @unclean_leb_list: LEBs to recover when re-mounting R/O mounted FS to R/W
* mode
* @rcvrd_mst_node: recovered master node to write when re-mounting R/O mounted
@@ -1249,6 +1237,7 @@ struct ubifs_debug_info;
*/
struct ubifs_info {
struct super_block *vfs_sb;
+
ino_t highest_inum;
unsigned long long max_sqnum;
unsigned long long cmt_no;
@@ -1281,10 +1270,13 @@ struct ubifs_info {
unsigned int big_lpt:1;
unsigned int space_fixup:1;
+ unsigned int double_hash:1;
+ unsigned int encrypted:1;
unsigned int no_chk_data_crc:1;
unsigned int bulk_read:1;
unsigned int default_compr:2;
unsigned int rw_incompat:1;
+ unsigned int assert_action:2;
struct mutex tnc_mutex;
struct ubifs_zbranch zroot;
@@ -1466,28 +1458,25 @@ struct ubifs_info {
struct list_head replay_list;
struct list_head replay_buds;
unsigned long long cs_sqnum;
- unsigned long long replay_sqnum;
struct list_head unclean_leb_list;
struct ubifs_mst_node *rcvrd_mst_node;
struct rb_root size_tree;
struct ubifs_mount_opts mount_opts;
struct device_d *dev;
+ struct ubifs_debug_info *dbg;
};
extern struct list_head ubifs_infos;
extern spinlock_t ubifs_infos_lock;
extern atomic_long_t ubifs_clean_zn_cnt;
-extern struct kmem_cache *ubifs_inode_slab;
extern const struct super_operations ubifs_super_operations;
-extern const struct xattr_handler *ubifs_xattr_handlers[];
extern const struct address_space_operations ubifs_file_address_operations;
extern const struct file_operations ubifs_file_operations;
extern const struct inode_operations ubifs_file_inode_operations;
extern const struct file_operations ubifs_dir_operations;
extern const struct inode_operations ubifs_dir_inode_operations;
extern const struct inode_operations ubifs_symlink_inode_operations;
-extern struct backing_dev_info ubifs_backing_dev_info;
extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
/* io.c */
@@ -1548,20 +1537,29 @@ int ubifs_consolidate_log(struct ubifs_info *c);
/* journal.c */
int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir,
- const struct qstr *nm, const struct inode *inode,
+ const struct fscrypt_name *nm, const struct inode *inode,
int deletion, int xent);
int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode,
const union ubifs_key *key, const void *buf, int len);
int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode);
int ubifs_jnl_delete_inode(struct ubifs_info *c, const struct inode *inode);
+int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir,
+ const struct inode *fst_inode,
+ const struct fscrypt_name *fst_nm,
+ const struct inode *snd_dir,
+ const struct inode *snd_inode,
+ const struct fscrypt_name *snd_nm, int sync);
int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir,
- const struct dentry *old_dentry,
+ const struct inode *old_inode,
+ const struct fscrypt_name *old_nm,
const struct inode *new_dir,
- const struct dentry *new_dentry, int sync);
+ const struct inode *new_inode,
+ const struct fscrypt_name *new_nm,
+ const struct inode *whiteout, int sync);
int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode,
loff_t old_size, loff_t new_size);
int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host,
- const struct inode *inode, const struct qstr *nm);
+ const struct inode *inode, const struct fscrypt_name *nm);
int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode1,
const struct inode *inode2);
@@ -1596,7 +1594,9 @@ int ubifs_save_dirty_idx_lnums(struct ubifs_info *c);
int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key,
struct ubifs_znode **zn, int *n);
int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key,
- void *node, const struct qstr *nm);
+ void *node, const struct fscrypt_name *nm);
+int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key,
+ void *node, uint32_t secondary_hash);
int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key,
void *node, int *lnum, int *offs);
int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
@@ -1604,16 +1604,18 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key,
int old_lnum, int old_offs, int lnum, int offs, int len);
int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key,
- int lnum, int offs, int len, const struct qstr *nm);
+ int lnum, int offs, int len, const struct fscrypt_name *nm);
int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key);
int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key,
- const struct qstr *nm);
+ const struct fscrypt_name *nm);
+int ubifs_tnc_remove_dh(struct ubifs_info *c, const union ubifs_key *key,
+ uint32_t cookie);
int ubifs_tnc_remove_range(struct ubifs_info *c, union ubifs_key *from_key,
union ubifs_key *to_key);
int ubifs_tnc_remove_ino(struct ubifs_info *c, ino_t inum);
struct ubifs_dent_node *ubifs_tnc_next_ent(struct ubifs_info *c,
union ubifs_key *key,
- const struct qstr *nm);
+ const struct fscrypt_name *nm);
void ubifs_tnc_close(struct ubifs_info *c);
int ubifs_tnc_has_node(struct ubifs_info *c, union ubifs_key *key, int level,
int lnum, int offs, int is_idx);
@@ -1628,14 +1630,17 @@ int ubifs_tnc_get_bu_keys(struct ubifs_info *c, struct bu_info *bu);
int ubifs_tnc_bulk_read(struct ubifs_info *c, struct bu_info *bu);
/* tnc_misc.c */
-struct ubifs_znode *ubifs_tnc_levelorder_next(struct ubifs_znode *zr,
+struct ubifs_znode *ubifs_tnc_levelorder_next(const struct ubifs_info *c,
+ struct ubifs_znode *zr,
struct ubifs_znode *znode);
int ubifs_search_zbranch(const struct ubifs_info *c,
const struct ubifs_znode *znode,
const union ubifs_key *key, int *n);
struct ubifs_znode *ubifs_tnc_postorder_first(struct ubifs_znode *znode);
-struct ubifs_znode *ubifs_tnc_postorder_next(struct ubifs_znode *znode);
-long ubifs_destroy_tnc_subtree(struct ubifs_znode *zr);
+struct ubifs_znode *ubifs_tnc_postorder_next(const struct ubifs_info *c,
+ struct ubifs_znode *znode);
+long ubifs_destroy_tnc_subtree(const struct ubifs_info *c,
+ struct ubifs_znode *zr);
struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c,
struct ubifs_zbranch *zbr,
struct ubifs_znode *parent, int iip);
@@ -1646,7 +1651,6 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr,
int ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot);
int ubifs_tnc_end_commit(struct ubifs_info *c);
-
/* commit.c */
int ubifs_bg_thread(void *info);
void ubifs_commit_required(struct ubifs_info *c);
@@ -1665,6 +1669,7 @@ int ubifs_read_superblock(struct ubifs_info *c);
struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c);
int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup);
int ubifs_fixup_free_space(struct ubifs_info *c);
+int ubifs_enable_encryption(struct ubifs_info *c);
/* replay.c */
int ubifs_validate_entry(struct ubifs_info *c,
@@ -1712,7 +1717,7 @@ struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c,
int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip);
void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty);
void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode);
-uint32_t ubifs_unpack_bits(uint8_t **addr, int *pos, int nrbits);
+uint32_t ubifs_unpack_bits(const struct ubifs_info *c, uint8_t **addr, int *pos, int nrbits);
struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght);
/* Needed only in debugging code in lpt_commit.c */
int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf,
@@ -1751,26 +1756,46 @@ int ubifs_calc_dark(const struct ubifs_info *c, int spc);
/* file.c */
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync);
int ubifs_setattr(struct dentry *dentry, struct iattr *attr);
+#ifdef CONFIG_UBIFS_ATIME_SUPPORT
+int ubifs_update_time(struct inode *inode, struct timespec64 *time, int flags);
+#endif
/* dir.c */
-struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir,
+struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir,
umode_t mode);
-int ubifs_getattr(struct vfsmount *mnt, struct dentry *dentry,
- struct kstat *stat);
+int ubifs_getattr(const struct path *path, struct kstat *stat,
+ u32 request_mask, unsigned int flags);
+int ubifs_check_dir_empty(struct inode *dir);
/* xattr.c */
-int ubifs_setxattr(struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags);
-ssize_t ubifs_getxattr(struct dentry *dentry, const char *name, void *buf,
- size_t size);
+extern const struct xattr_handler *ubifs_xattr_handlers[];
ssize_t ubifs_listxattr(struct dentry *dentry, char *buffer, size_t size);
-int ubifs_removexattr(struct dentry *dentry, const char *name);
-int ubifs_init_security(struct inode *dentry, struct inode *inode,
+int ubifs_xattr_set(struct inode *host, const char *name, const void *value,
+ size_t size, int flags, bool check_lock);
+ssize_t ubifs_xattr_get(struct inode *host, const char *name, void *buf,
+ size_t size);
+
+#ifdef CONFIG_UBIFS_FS_XATTR
+void ubifs_evict_xattr_inode(struct ubifs_info *c, ino_t xattr_inum);
+#else
+static inline void ubifs_evict_xattr_inode(struct ubifs_info *c,
+ ino_t xattr_inum) { }
+#endif
+
+#ifdef CONFIG_UBIFS_FS_SECURITY
+extern int ubifs_init_security(struct inode *dentry, struct inode *inode,
const struct qstr *qstr);
+#else
+static inline int ubifs_init_security(struct inode *dentry,
+ struct inode *inode, const struct qstr *qstr)
+{
+ return 0;
+}
+#endif
+
/* super.c */
struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
-int ubifs_iput(struct inode *inode);
/* recovery.c */
int ubifs_recover_master_node(struct ubifs_info *c);
@@ -1806,7 +1831,61 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len,
#include "misc.h"
#include "key.h"
+/* barebox specific */
void ubifs_umount(struct ubifs_info *c);
+/* barebox specific */
int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent);
+#ifndef CONFIG_UBIFS_FS_ENCRYPTION
+static inline int ubifs_encrypt(const struct inode *inode,
+ struct ubifs_data_node *dn,
+ unsigned int in_len, unsigned int *out_len,
+ int block)
+{
+ struct ubifs_info *c = inode->i_sb->s_fs_info;
+ ubifs_assert(c, 0);
+ return -EOPNOTSUPP;
+}
+static inline int ubifs_decrypt(const struct inode *inode,
+ struct ubifs_data_node *dn,
+ unsigned int *out_len, int block)
+{
+ struct ubifs_info *c = inode->i_sb->s_fs_info;
+ ubifs_assert(c, 0);
+ return -EOPNOTSUPP;
+}
+#else
+/* crypto.c */
+int ubifs_encrypt(const struct inode *inode, struct ubifs_data_node *dn,
+ unsigned int in_len, unsigned int *out_len, int block);
+int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn,
+ unsigned int *out_len, int block);
+#endif
+
+extern const struct fscrypt_operations ubifs_crypt_operations;
+
+static inline bool ubifs_crypt_is_encrypted(const struct inode *inode)
+{
+ const struct ubifs_inode *ui = ubifs_inode(inode);
+
+ return ui->flags & UBIFS_CRYPT_FL;
+}
+
+/* Normal UBIFS messages */
+__printf(2, 3)
+void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...);
+__printf(2, 3)
+void ubifs_err(const struct ubifs_info *c, const char *fmt, ...);
+__printf(2, 3)
+void ubifs_warn(const struct ubifs_info *c, const char *fmt, ...);
+/*
+ * A conditional variant of 'ubifs_err()' which doesn't output anything
+ * if probing (ie. SB_SILENT set).
+ */
+#define ubifs_errc(c, fmt, ...) \
+do { \
+ if (!(c)->probing) \
+ ubifs_err(c, fmt, ##__VA_ARGS__); \
+} while (0)
+
#endif /* !__UBIFS_H__ */
--
2.19.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 18+ messages in thread