summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ubifs/Makefile8
-rw-r--r--fs/ubifs/budget.c729
-rw-r--r--fs/ubifs/debug.c2533
-rw-r--r--fs/ubifs/debug.h66
-rw-r--r--fs/ubifs/gc.c976
-rw-r--r--fs/ubifs/io.c806
-rw-r--r--fs/ubifs/log.c649
-rw-r--r--fs/ubifs/lprops.c1313
-rw-r--r--fs/ubifs/lpt.c2282
-rw-r--r--fs/ubifs/lpt_commit.c2022
-rw-r--r--fs/ubifs/master.c52
-rw-r--r--fs/ubifs/misc.h41
-rw-r--r--fs/ubifs/orphan.c946
-rw-r--r--fs/ubifs/recovery.c490
-rw-r--r--fs/ubifs/replay.c151
-rw-r--r--fs/ubifs/sb.c473
-rw-r--r--fs/ubifs/scan.c2
-rw-r--r--fs/ubifs/super.c1428
-rw-r--r--fs/ubifs/tnc.c1140
-rw-r--r--fs/ubifs/tnc_misc.c16
-rw-r--r--fs/ubifs/ubifs-media.h12
-rw-r--r--fs/ubifs/ubifs.c14
-rw-r--r--fs/ubifs/ubifs.h71
23 files changed, 14 insertions, 16206 deletions
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;
@@ -343,629 +251,6 @@ void ubifs_pad(const struct ubifs_info *c, void *buf, int 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
* @buf: buffer to read to
@@ -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
@@ -54,61 +52,6 @@ struct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum)
}
/**
- * 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
* @bud: the bud to add
@@ -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"
/**
@@ -188,36 +183,6 @@ out_free:
}
/**
- * 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);
@@ -370,31 +327,6 @@ out_free:
}
/**
- * 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
* @buf: buffer to check
@@ -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>
@@ -79,103 +77,6 @@ struct bud_entry {
};
/**
- * 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
* @r: replay entry of truncation
@@ -956,41 +857,6 @@ out_dump:
}
/**
- * 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.
@@ -498,21 +215,6 @@ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c)
}
/**
- * 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;
}
@@ -848,32 +530,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,62 +594,12 @@ 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"
/*
@@ -181,61 +176,6 @@ void destroy_old_idx(struct ubifs_info *c)
}
/**
- * 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
* @zbr: branch of znode to check
@@ -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;
}
/**
@@ -982,153 +886,6 @@ static int fallible_resolve_collision(struct ubifs_info *c,
}
/**
- * 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
* @key: key to lookup
@@ -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)) {
/*
@@ -1487,294 +1208,6 @@ out:
}
/**
- * 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
* @key: node key to lookup
@@ -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];
@@ -2181,91 +1612,6 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum,
}
/**
- * 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
* @key: key to add
@@ -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__ */