xref: /kernel/linux/linux-6.6/fs/ubifs/commit.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This file is part of UBIFS.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Authors: Adrian Hunter
862306a36Sopenharmony_ci *          Artem Bityutskiy (Битюцкий Артём)
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/*
1262306a36Sopenharmony_ci * This file implements functions that manage the running of the commit process.
1362306a36Sopenharmony_ci * Each affected module has its own functions to accomplish their part in the
1462306a36Sopenharmony_ci * commit and those functions are called here.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * The commit is the process whereby all updates to the index and LEB properties
1762306a36Sopenharmony_ci * are written out together and the journal becomes empty. This keeps the
1862306a36Sopenharmony_ci * file system consistent - at all times the state can be recreated by reading
1962306a36Sopenharmony_ci * the index and LEB properties and then replaying the journal.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * The commit is split into two parts named "commit start" and "commit end".
2262306a36Sopenharmony_ci * During commit start, the commit process has exclusive access to the journal
2362306a36Sopenharmony_ci * by holding the commit semaphore down for writing. As few I/O operations as
2462306a36Sopenharmony_ci * possible are performed during commit start, instead the nodes that are to be
2562306a36Sopenharmony_ci * written are merely identified. During commit end, the commit semaphore is no
2662306a36Sopenharmony_ci * longer held and the journal is again in operation, allowing users to continue
2762306a36Sopenharmony_ci * to use the file system while the bulk of the commit I/O is performed. The
2862306a36Sopenharmony_ci * purpose of this two-step approach is to prevent the commit from causing any
2962306a36Sopenharmony_ci * latency blips. Note that in any case, the commit does not prevent lookups
3062306a36Sopenharmony_ci * (as permitted by the TNC mutex), or access to VFS data structures e.g. page
3162306a36Sopenharmony_ci * cache.
3262306a36Sopenharmony_ci */
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci#include <linux/freezer.h>
3562306a36Sopenharmony_ci#include <linux/kthread.h>
3662306a36Sopenharmony_ci#include <linux/slab.h>
3762306a36Sopenharmony_ci#include "ubifs.h"
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci * nothing_to_commit - check if there is nothing to commit.
4162306a36Sopenharmony_ci * @c: UBIFS file-system description object
4262306a36Sopenharmony_ci *
4362306a36Sopenharmony_ci * This is a helper function which checks if there is anything to commit. It is
4462306a36Sopenharmony_ci * used as an optimization to avoid starting the commit if it is not really
4562306a36Sopenharmony_ci * necessary. Indeed, the commit operation always assumes flash I/O (e.g.,
4662306a36Sopenharmony_ci * writing the commit start node to the log), and it is better to avoid doing
4762306a36Sopenharmony_ci * this unnecessarily. E.g., 'ubifs_sync_fs()' runs the commit, but if there is
4862306a36Sopenharmony_ci * nothing to commit, it is more optimal to avoid any flash I/O.
4962306a36Sopenharmony_ci *
5062306a36Sopenharmony_ci * This function has to be called with @c->commit_sem locked for writing -
5162306a36Sopenharmony_ci * this function does not take LPT/TNC locks because the @c->commit_sem
5262306a36Sopenharmony_ci * guarantees that we have exclusive access to the TNC and LPT data structures.
5362306a36Sopenharmony_ci *
5462306a36Sopenharmony_ci * This function returns %1 if there is nothing to commit and %0 otherwise.
5562306a36Sopenharmony_ci */
5662306a36Sopenharmony_cistatic int nothing_to_commit(struct ubifs_info *c)
5762306a36Sopenharmony_ci{
5862306a36Sopenharmony_ci	/*
5962306a36Sopenharmony_ci	 * During mounting or remounting from R/O mode to R/W mode we may
6062306a36Sopenharmony_ci	 * commit for various recovery-related reasons.
6162306a36Sopenharmony_ci	 */
6262306a36Sopenharmony_ci	if (c->mounting || c->remounting_rw)
6362306a36Sopenharmony_ci		return 0;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/*
6662306a36Sopenharmony_ci	 * If the root TNC node is dirty, we definitely have something to
6762306a36Sopenharmony_ci	 * commit.
6862306a36Sopenharmony_ci	 */
6962306a36Sopenharmony_ci	if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode))
7062306a36Sopenharmony_ci		return 0;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	/*
7362306a36Sopenharmony_ci	 * Even though the TNC is clean, the LPT tree may have dirty nodes. For
7462306a36Sopenharmony_ci	 * example, this may happen if the budgeting subsystem invoked GC to
7562306a36Sopenharmony_ci	 * make some free space, and the GC found an LEB with only dirty and
7662306a36Sopenharmony_ci	 * free space. In this case GC would just change the lprops of this
7762306a36Sopenharmony_ci	 * LEB (by turning all space into free space) and unmap it.
7862306a36Sopenharmony_ci	 */
7962306a36Sopenharmony_ci	if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags))
8062306a36Sopenharmony_ci		return 0;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	ubifs_assert(c, atomic_long_read(&c->dirty_zn_cnt) == 0);
8362306a36Sopenharmony_ci	ubifs_assert(c, c->dirty_pn_cnt == 0);
8462306a36Sopenharmony_ci	ubifs_assert(c, c->dirty_nn_cnt == 0);
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return 1;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/**
9062306a36Sopenharmony_ci * do_commit - commit the journal.
9162306a36Sopenharmony_ci * @c: UBIFS file-system description object
9262306a36Sopenharmony_ci *
9362306a36Sopenharmony_ci * This function implements UBIFS commit. It has to be called with commit lock
9462306a36Sopenharmony_ci * locked. Returns zero in case of success and a negative error code in case of
9562306a36Sopenharmony_ci * failure.
9662306a36Sopenharmony_ci */
9762306a36Sopenharmony_cistatic int do_commit(struct ubifs_info *c)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	int err, new_ltail_lnum, old_ltail_lnum, i;
10062306a36Sopenharmony_ci	struct ubifs_zbranch zroot;
10162306a36Sopenharmony_ci	struct ubifs_lp_stats lst;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	dbg_cmt("start");
10462306a36Sopenharmony_ci	ubifs_assert(c, !c->ro_media && !c->ro_mount);
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (c->ro_error) {
10762306a36Sopenharmony_ci		err = -EROFS;
10862306a36Sopenharmony_ci		goto out_up;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	if (nothing_to_commit(c)) {
11262306a36Sopenharmony_ci		up_write(&c->commit_sem);
11362306a36Sopenharmony_ci		err = 0;
11462306a36Sopenharmony_ci		goto out_cancel;
11562306a36Sopenharmony_ci	}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	/* Sync all write buffers (necessary for recovery) */
11862306a36Sopenharmony_ci	for (i = 0; i < c->jhead_cnt; i++) {
11962306a36Sopenharmony_ci		err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
12062306a36Sopenharmony_ci		if (err)
12162306a36Sopenharmony_ci			goto out_up;
12262306a36Sopenharmony_ci	}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	c->cmt_no += 1;
12562306a36Sopenharmony_ci	err = ubifs_gc_start_commit(c);
12662306a36Sopenharmony_ci	if (err)
12762306a36Sopenharmony_ci		goto out_up;
12862306a36Sopenharmony_ci	err = dbg_check_lprops(c);
12962306a36Sopenharmony_ci	if (err)
13062306a36Sopenharmony_ci		goto out_up;
13162306a36Sopenharmony_ci	err = ubifs_log_start_commit(c, &new_ltail_lnum);
13262306a36Sopenharmony_ci	if (err)
13362306a36Sopenharmony_ci		goto out_up;
13462306a36Sopenharmony_ci	err = ubifs_tnc_start_commit(c, &zroot);
13562306a36Sopenharmony_ci	if (err)
13662306a36Sopenharmony_ci		goto out_up;
13762306a36Sopenharmony_ci	err = ubifs_lpt_start_commit(c);
13862306a36Sopenharmony_ci	if (err)
13962306a36Sopenharmony_ci		goto out_up;
14062306a36Sopenharmony_ci	err = ubifs_orphan_start_commit(c);
14162306a36Sopenharmony_ci	if (err)
14262306a36Sopenharmony_ci		goto out_up;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	ubifs_get_lp_stats(c, &lst);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	up_write(&c->commit_sem);
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	err = ubifs_tnc_end_commit(c);
14962306a36Sopenharmony_ci	if (err)
15062306a36Sopenharmony_ci		goto out;
15162306a36Sopenharmony_ci	err = ubifs_lpt_end_commit(c);
15262306a36Sopenharmony_ci	if (err)
15362306a36Sopenharmony_ci		goto out;
15462306a36Sopenharmony_ci	err = ubifs_orphan_end_commit(c);
15562306a36Sopenharmony_ci	if (err)
15662306a36Sopenharmony_ci		goto out;
15762306a36Sopenharmony_ci	err = dbg_check_old_index(c, &zroot);
15862306a36Sopenharmony_ci	if (err)
15962306a36Sopenharmony_ci		goto out;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	c->mst_node->cmt_no      = cpu_to_le64(c->cmt_no);
16262306a36Sopenharmony_ci	c->mst_node->log_lnum    = cpu_to_le32(new_ltail_lnum);
16362306a36Sopenharmony_ci	c->mst_node->root_lnum   = cpu_to_le32(zroot.lnum);
16462306a36Sopenharmony_ci	c->mst_node->root_offs   = cpu_to_le32(zroot.offs);
16562306a36Sopenharmony_ci	c->mst_node->root_len    = cpu_to_le32(zroot.len);
16662306a36Sopenharmony_ci	c->mst_node->ihead_lnum  = cpu_to_le32(c->ihead_lnum);
16762306a36Sopenharmony_ci	c->mst_node->ihead_offs  = cpu_to_le32(c->ihead_offs);
16862306a36Sopenharmony_ci	c->mst_node->index_size  = cpu_to_le64(c->bi.old_idx_sz);
16962306a36Sopenharmony_ci	c->mst_node->lpt_lnum    = cpu_to_le32(c->lpt_lnum);
17062306a36Sopenharmony_ci	c->mst_node->lpt_offs    = cpu_to_le32(c->lpt_offs);
17162306a36Sopenharmony_ci	c->mst_node->nhead_lnum  = cpu_to_le32(c->nhead_lnum);
17262306a36Sopenharmony_ci	c->mst_node->nhead_offs  = cpu_to_le32(c->nhead_offs);
17362306a36Sopenharmony_ci	c->mst_node->ltab_lnum   = cpu_to_le32(c->ltab_lnum);
17462306a36Sopenharmony_ci	c->mst_node->ltab_offs   = cpu_to_le32(c->ltab_offs);
17562306a36Sopenharmony_ci	c->mst_node->lsave_lnum  = cpu_to_le32(c->lsave_lnum);
17662306a36Sopenharmony_ci	c->mst_node->lsave_offs  = cpu_to_le32(c->lsave_offs);
17762306a36Sopenharmony_ci	c->mst_node->lscan_lnum  = cpu_to_le32(c->lscan_lnum);
17862306a36Sopenharmony_ci	c->mst_node->empty_lebs  = cpu_to_le32(lst.empty_lebs);
17962306a36Sopenharmony_ci	c->mst_node->idx_lebs    = cpu_to_le32(lst.idx_lebs);
18062306a36Sopenharmony_ci	c->mst_node->total_free  = cpu_to_le64(lst.total_free);
18162306a36Sopenharmony_ci	c->mst_node->total_dirty = cpu_to_le64(lst.total_dirty);
18262306a36Sopenharmony_ci	c->mst_node->total_used  = cpu_to_le64(lst.total_used);
18362306a36Sopenharmony_ci	c->mst_node->total_dead  = cpu_to_le64(lst.total_dead);
18462306a36Sopenharmony_ci	c->mst_node->total_dark  = cpu_to_le64(lst.total_dark);
18562306a36Sopenharmony_ci	if (c->no_orphs)
18662306a36Sopenharmony_ci		c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
18762306a36Sopenharmony_ci	else
18862306a36Sopenharmony_ci		c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_NO_ORPHS);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	old_ltail_lnum = c->ltail_lnum;
19162306a36Sopenharmony_ci	err = ubifs_log_end_commit(c, new_ltail_lnum);
19262306a36Sopenharmony_ci	if (err)
19362306a36Sopenharmony_ci		goto out;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	err = ubifs_log_post_commit(c, old_ltail_lnum);
19662306a36Sopenharmony_ci	if (err)
19762306a36Sopenharmony_ci		goto out;
19862306a36Sopenharmony_ci	err = ubifs_gc_end_commit(c);
19962306a36Sopenharmony_ci	if (err)
20062306a36Sopenharmony_ci		goto out;
20162306a36Sopenharmony_ci	err = ubifs_lpt_post_commit(c);
20262306a36Sopenharmony_ci	if (err)
20362306a36Sopenharmony_ci		goto out;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ciout_cancel:
20662306a36Sopenharmony_ci	spin_lock(&c->cs_lock);
20762306a36Sopenharmony_ci	c->cmt_state = COMMIT_RESTING;
20862306a36Sopenharmony_ci	wake_up(&c->cmt_wq);
20962306a36Sopenharmony_ci	dbg_cmt("commit end");
21062306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
21162306a36Sopenharmony_ci	return 0;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ciout_up:
21462306a36Sopenharmony_ci	up_write(&c->commit_sem);
21562306a36Sopenharmony_ciout:
21662306a36Sopenharmony_ci	ubifs_err(c, "commit failed, error %d", err);
21762306a36Sopenharmony_ci	spin_lock(&c->cs_lock);
21862306a36Sopenharmony_ci	c->cmt_state = COMMIT_BROKEN;
21962306a36Sopenharmony_ci	wake_up(&c->cmt_wq);
22062306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
22162306a36Sopenharmony_ci	ubifs_ro_mode(c, err);
22262306a36Sopenharmony_ci	return err;
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/**
22662306a36Sopenharmony_ci * run_bg_commit - run background commit if it is needed.
22762306a36Sopenharmony_ci * @c: UBIFS file-system description object
22862306a36Sopenharmony_ci *
22962306a36Sopenharmony_ci * This function runs background commit if it is needed. Returns zero in case
23062306a36Sopenharmony_ci * of success and a negative error code in case of failure.
23162306a36Sopenharmony_ci */
23262306a36Sopenharmony_cistatic int run_bg_commit(struct ubifs_info *c)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	spin_lock(&c->cs_lock);
23562306a36Sopenharmony_ci	/*
23662306a36Sopenharmony_ci	 * Run background commit only if background commit was requested or if
23762306a36Sopenharmony_ci	 * commit is required.
23862306a36Sopenharmony_ci	 */
23962306a36Sopenharmony_ci	if (c->cmt_state != COMMIT_BACKGROUND &&
24062306a36Sopenharmony_ci	    c->cmt_state != COMMIT_REQUIRED)
24162306a36Sopenharmony_ci		goto out;
24262306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	down_write(&c->commit_sem);
24562306a36Sopenharmony_ci	spin_lock(&c->cs_lock);
24662306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_REQUIRED)
24762306a36Sopenharmony_ci		c->cmt_state = COMMIT_RUNNING_REQUIRED;
24862306a36Sopenharmony_ci	else if (c->cmt_state == COMMIT_BACKGROUND)
24962306a36Sopenharmony_ci		c->cmt_state = COMMIT_RUNNING_BACKGROUND;
25062306a36Sopenharmony_ci	else
25162306a36Sopenharmony_ci		goto out_cmt_unlock;
25262306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return do_commit(c);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ciout_cmt_unlock:
25762306a36Sopenharmony_ci	up_write(&c->commit_sem);
25862306a36Sopenharmony_ciout:
25962306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
26062306a36Sopenharmony_ci	return 0;
26162306a36Sopenharmony_ci}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci/**
26462306a36Sopenharmony_ci * ubifs_bg_thread - UBIFS background thread function.
26562306a36Sopenharmony_ci * @info: points to the file-system description object
26662306a36Sopenharmony_ci *
26762306a36Sopenharmony_ci * This function implements various file-system background activities:
26862306a36Sopenharmony_ci * o when a write-buffer timer expires it synchronizes the appropriate
26962306a36Sopenharmony_ci *   write-buffer;
27062306a36Sopenharmony_ci * o when the journal is about to be full, it starts in-advance commit.
27162306a36Sopenharmony_ci *
27262306a36Sopenharmony_ci * Note, other stuff like background garbage collection may be added here in
27362306a36Sopenharmony_ci * future.
27462306a36Sopenharmony_ci */
27562306a36Sopenharmony_ciint ubifs_bg_thread(void *info)
27662306a36Sopenharmony_ci{
27762306a36Sopenharmony_ci	int err;
27862306a36Sopenharmony_ci	struct ubifs_info *c = info;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	ubifs_msg(c, "background thread \"%s\" started, PID %d",
28162306a36Sopenharmony_ci		  c->bgt_name, current->pid);
28262306a36Sopenharmony_ci	set_freezable();
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	while (1) {
28562306a36Sopenharmony_ci		if (kthread_should_stop())
28662306a36Sopenharmony_ci			break;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci		if (try_to_freeze())
28962306a36Sopenharmony_ci			continue;
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci		set_current_state(TASK_INTERRUPTIBLE);
29262306a36Sopenharmony_ci		/* Check if there is something to do */
29362306a36Sopenharmony_ci		if (!c->need_bgt) {
29462306a36Sopenharmony_ci			/*
29562306a36Sopenharmony_ci			 * Nothing prevents us from going sleep now and
29662306a36Sopenharmony_ci			 * be never woken up and block the task which
29762306a36Sopenharmony_ci			 * could wait in 'kthread_stop()' forever.
29862306a36Sopenharmony_ci			 */
29962306a36Sopenharmony_ci			if (kthread_should_stop())
30062306a36Sopenharmony_ci				break;
30162306a36Sopenharmony_ci			schedule();
30262306a36Sopenharmony_ci			continue;
30362306a36Sopenharmony_ci		} else
30462306a36Sopenharmony_ci			__set_current_state(TASK_RUNNING);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci		c->need_bgt = 0;
30762306a36Sopenharmony_ci		err = ubifs_bg_wbufs_sync(c);
30862306a36Sopenharmony_ci		if (err)
30962306a36Sopenharmony_ci			ubifs_ro_mode(c, err);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci		run_bg_commit(c);
31262306a36Sopenharmony_ci		cond_resched();
31362306a36Sopenharmony_ci	}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	ubifs_msg(c, "background thread \"%s\" stops", c->bgt_name);
31662306a36Sopenharmony_ci	return 0;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci/**
32062306a36Sopenharmony_ci * ubifs_commit_required - set commit state to "required".
32162306a36Sopenharmony_ci * @c: UBIFS file-system description object
32262306a36Sopenharmony_ci *
32362306a36Sopenharmony_ci * This function is called if a commit is required but cannot be done from the
32462306a36Sopenharmony_ci * calling function, so it is just flagged instead.
32562306a36Sopenharmony_ci */
32662306a36Sopenharmony_civoid ubifs_commit_required(struct ubifs_info *c)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	spin_lock(&c->cs_lock);
32962306a36Sopenharmony_ci	switch (c->cmt_state) {
33062306a36Sopenharmony_ci	case COMMIT_RESTING:
33162306a36Sopenharmony_ci	case COMMIT_BACKGROUND:
33262306a36Sopenharmony_ci		dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state),
33362306a36Sopenharmony_ci			dbg_cstate(COMMIT_REQUIRED));
33462306a36Sopenharmony_ci		c->cmt_state = COMMIT_REQUIRED;
33562306a36Sopenharmony_ci		break;
33662306a36Sopenharmony_ci	case COMMIT_RUNNING_BACKGROUND:
33762306a36Sopenharmony_ci		dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state),
33862306a36Sopenharmony_ci			dbg_cstate(COMMIT_RUNNING_REQUIRED));
33962306a36Sopenharmony_ci		c->cmt_state = COMMIT_RUNNING_REQUIRED;
34062306a36Sopenharmony_ci		break;
34162306a36Sopenharmony_ci	case COMMIT_REQUIRED:
34262306a36Sopenharmony_ci	case COMMIT_RUNNING_REQUIRED:
34362306a36Sopenharmony_ci	case COMMIT_BROKEN:
34462306a36Sopenharmony_ci		break;
34562306a36Sopenharmony_ci	}
34662306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/**
35062306a36Sopenharmony_ci * ubifs_request_bg_commit - notify the background thread to do a commit.
35162306a36Sopenharmony_ci * @c: UBIFS file-system description object
35262306a36Sopenharmony_ci *
35362306a36Sopenharmony_ci * This function is called if the journal is full enough to make a commit
35462306a36Sopenharmony_ci * worthwhile, so background thread is kicked to start it.
35562306a36Sopenharmony_ci */
35662306a36Sopenharmony_civoid ubifs_request_bg_commit(struct ubifs_info *c)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	spin_lock(&c->cs_lock);
35962306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_RESTING) {
36062306a36Sopenharmony_ci		dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state),
36162306a36Sopenharmony_ci			dbg_cstate(COMMIT_BACKGROUND));
36262306a36Sopenharmony_ci		c->cmt_state = COMMIT_BACKGROUND;
36362306a36Sopenharmony_ci		spin_unlock(&c->cs_lock);
36462306a36Sopenharmony_ci		ubifs_wake_up_bgt(c);
36562306a36Sopenharmony_ci	} else
36662306a36Sopenharmony_ci		spin_unlock(&c->cs_lock);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci/**
37062306a36Sopenharmony_ci * wait_for_commit - wait for commit.
37162306a36Sopenharmony_ci * @c: UBIFS file-system description object
37262306a36Sopenharmony_ci *
37362306a36Sopenharmony_ci * This function sleeps until the commit operation is no longer running.
37462306a36Sopenharmony_ci */
37562306a36Sopenharmony_cistatic int wait_for_commit(struct ubifs_info *c)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	dbg_cmt("pid %d goes sleep", current->pid);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	/*
38062306a36Sopenharmony_ci	 * The following sleeps if the condition is false, and will be woken
38162306a36Sopenharmony_ci	 * when the commit ends. It is possible, although very unlikely, that we
38262306a36Sopenharmony_ci	 * will wake up and see the subsequent commit running, rather than the
38362306a36Sopenharmony_ci	 * one we were waiting for, and go back to sleep.  However, we will be
38462306a36Sopenharmony_ci	 * woken again, so there is no danger of sleeping forever.
38562306a36Sopenharmony_ci	 */
38662306a36Sopenharmony_ci	wait_event(c->cmt_wq, c->cmt_state != COMMIT_RUNNING_BACKGROUND &&
38762306a36Sopenharmony_ci			      c->cmt_state != COMMIT_RUNNING_REQUIRED);
38862306a36Sopenharmony_ci	dbg_cmt("commit finished, pid %d woke up", current->pid);
38962306a36Sopenharmony_ci	return 0;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci/**
39362306a36Sopenharmony_ci * ubifs_run_commit - run or wait for commit.
39462306a36Sopenharmony_ci * @c: UBIFS file-system description object
39562306a36Sopenharmony_ci *
39662306a36Sopenharmony_ci * This function runs commit and returns zero in case of success and a negative
39762306a36Sopenharmony_ci * error code in case of failure.
39862306a36Sopenharmony_ci */
39962306a36Sopenharmony_ciint ubifs_run_commit(struct ubifs_info *c)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	int err = 0;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	spin_lock(&c->cs_lock);
40462306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_BROKEN) {
40562306a36Sopenharmony_ci		err = -EROFS;
40662306a36Sopenharmony_ci		goto out;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_RUNNING_BACKGROUND)
41062306a36Sopenharmony_ci		/*
41162306a36Sopenharmony_ci		 * We set the commit state to 'running required' to indicate
41262306a36Sopenharmony_ci		 * that we want it to complete as quickly as possible.
41362306a36Sopenharmony_ci		 */
41462306a36Sopenharmony_ci		c->cmt_state = COMMIT_RUNNING_REQUIRED;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_RUNNING_REQUIRED) {
41762306a36Sopenharmony_ci		spin_unlock(&c->cs_lock);
41862306a36Sopenharmony_ci		return wait_for_commit(c);
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	/* Ok, the commit is indeed needed */
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	down_write(&c->commit_sem);
42562306a36Sopenharmony_ci	spin_lock(&c->cs_lock);
42662306a36Sopenharmony_ci	/*
42762306a36Sopenharmony_ci	 * Since we unlocked 'c->cs_lock', the state may have changed, so
42862306a36Sopenharmony_ci	 * re-check it.
42962306a36Sopenharmony_ci	 */
43062306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_BROKEN) {
43162306a36Sopenharmony_ci		err = -EROFS;
43262306a36Sopenharmony_ci		goto out_cmt_unlock;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_RUNNING_BACKGROUND)
43662306a36Sopenharmony_ci		c->cmt_state = COMMIT_RUNNING_REQUIRED;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_RUNNING_REQUIRED) {
43962306a36Sopenharmony_ci		up_write(&c->commit_sem);
44062306a36Sopenharmony_ci		spin_unlock(&c->cs_lock);
44162306a36Sopenharmony_ci		return wait_for_commit(c);
44262306a36Sopenharmony_ci	}
44362306a36Sopenharmony_ci	c->cmt_state = COMMIT_RUNNING_REQUIRED;
44462306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	err = do_commit(c);
44762306a36Sopenharmony_ci	return err;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ciout_cmt_unlock:
45062306a36Sopenharmony_ci	up_write(&c->commit_sem);
45162306a36Sopenharmony_ciout:
45262306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
45362306a36Sopenharmony_ci	return err;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci/**
45762306a36Sopenharmony_ci * ubifs_gc_should_commit - determine if it is time for GC to run commit.
45862306a36Sopenharmony_ci * @c: UBIFS file-system description object
45962306a36Sopenharmony_ci *
46062306a36Sopenharmony_ci * This function is called by garbage collection to determine if commit should
46162306a36Sopenharmony_ci * be run. If commit state is @COMMIT_BACKGROUND, which means that the journal
46262306a36Sopenharmony_ci * is full enough to start commit, this function returns true. It is not
46362306a36Sopenharmony_ci * absolutely necessary to commit yet, but it feels like this should be better
46462306a36Sopenharmony_ci * then to keep doing GC. This function returns %1 if GC has to initiate commit
46562306a36Sopenharmony_ci * and %0 if not.
46662306a36Sopenharmony_ci */
46762306a36Sopenharmony_ciint ubifs_gc_should_commit(struct ubifs_info *c)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	int ret = 0;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	spin_lock(&c->cs_lock);
47262306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_BACKGROUND) {
47362306a36Sopenharmony_ci		dbg_cmt("commit required now");
47462306a36Sopenharmony_ci		c->cmt_state = COMMIT_REQUIRED;
47562306a36Sopenharmony_ci	} else
47662306a36Sopenharmony_ci		dbg_cmt("commit not requested");
47762306a36Sopenharmony_ci	if (c->cmt_state == COMMIT_REQUIRED)
47862306a36Sopenharmony_ci		ret = 1;
47962306a36Sopenharmony_ci	spin_unlock(&c->cs_lock);
48062306a36Sopenharmony_ci	return ret;
48162306a36Sopenharmony_ci}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci/*
48462306a36Sopenharmony_ci * Everything below is related to debugging.
48562306a36Sopenharmony_ci */
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci/**
48862306a36Sopenharmony_ci * struct idx_node - hold index nodes during index tree traversal.
48962306a36Sopenharmony_ci * @list: list
49062306a36Sopenharmony_ci * @iip: index in parent (slot number of this indexing node in the parent
49162306a36Sopenharmony_ci *       indexing node)
49262306a36Sopenharmony_ci * @upper_key: all keys in this indexing node have to be less or equivalent to
49362306a36Sopenharmony_ci *             this key
49462306a36Sopenharmony_ci * @idx: index node (8-byte aligned because all node structures must be 8-byte
49562306a36Sopenharmony_ci *       aligned)
49662306a36Sopenharmony_ci */
49762306a36Sopenharmony_cistruct idx_node {
49862306a36Sopenharmony_ci	struct list_head list;
49962306a36Sopenharmony_ci	int iip;
50062306a36Sopenharmony_ci	union ubifs_key upper_key;
50162306a36Sopenharmony_ci	struct ubifs_idx_node idx __aligned(8);
50262306a36Sopenharmony_ci};
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci/**
50562306a36Sopenharmony_ci * dbg_old_index_check_init - get information for the next old index check.
50662306a36Sopenharmony_ci * @c: UBIFS file-system description object
50762306a36Sopenharmony_ci * @zroot: root of the index
50862306a36Sopenharmony_ci *
50962306a36Sopenharmony_ci * This function records information about the index that will be needed for the
51062306a36Sopenharmony_ci * next old index check i.e. 'dbg_check_old_index()'.
51162306a36Sopenharmony_ci *
51262306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
51362306a36Sopenharmony_ci */
51462306a36Sopenharmony_ciint dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot)
51562306a36Sopenharmony_ci{
51662306a36Sopenharmony_ci	struct ubifs_idx_node *idx;
51762306a36Sopenharmony_ci	int lnum, offs, len, err = 0;
51862306a36Sopenharmony_ci	struct ubifs_debug_info *d = c->dbg;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	d->old_zroot = *zroot;
52162306a36Sopenharmony_ci	lnum = d->old_zroot.lnum;
52262306a36Sopenharmony_ci	offs = d->old_zroot.offs;
52362306a36Sopenharmony_ci	len = d->old_zroot.len;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	idx = kmalloc(c->max_idx_node_sz, GFP_NOFS);
52662306a36Sopenharmony_ci	if (!idx)
52762306a36Sopenharmony_ci		return -ENOMEM;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
53062306a36Sopenharmony_ci	if (err)
53162306a36Sopenharmony_ci		goto out;
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	d->old_zroot_level = le16_to_cpu(idx->level);
53462306a36Sopenharmony_ci	d->old_zroot_sqnum = le64_to_cpu(idx->ch.sqnum);
53562306a36Sopenharmony_ciout:
53662306a36Sopenharmony_ci	kfree(idx);
53762306a36Sopenharmony_ci	return err;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci/**
54162306a36Sopenharmony_ci * dbg_check_old_index - check the old copy of the index.
54262306a36Sopenharmony_ci * @c: UBIFS file-system description object
54362306a36Sopenharmony_ci * @zroot: root of the new index
54462306a36Sopenharmony_ci *
54562306a36Sopenharmony_ci * In order to be able to recover from an unclean unmount, a complete copy of
54662306a36Sopenharmony_ci * the index must exist on flash. This is the "old" index. The commit process
54762306a36Sopenharmony_ci * must write the "new" index to flash without overwriting or destroying any
54862306a36Sopenharmony_ci * part of the old index. This function is run at commit end in order to check
54962306a36Sopenharmony_ci * that the old index does indeed exist completely intact.
55062306a36Sopenharmony_ci *
55162306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
55262306a36Sopenharmony_ci */
55362306a36Sopenharmony_ciint dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	int lnum, offs, len, err = 0, last_level, child_cnt;
55662306a36Sopenharmony_ci	int first = 1, iip;
55762306a36Sopenharmony_ci	struct ubifs_debug_info *d = c->dbg;
55862306a36Sopenharmony_ci	union ubifs_key lower_key, upper_key, l_key, u_key;
55962306a36Sopenharmony_ci	unsigned long long last_sqnum;
56062306a36Sopenharmony_ci	struct ubifs_idx_node *idx;
56162306a36Sopenharmony_ci	struct list_head list;
56262306a36Sopenharmony_ci	struct idx_node *i;
56362306a36Sopenharmony_ci	size_t sz;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	if (!dbg_is_chk_index(c))
56662306a36Sopenharmony_ci		return 0;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	INIT_LIST_HEAD(&list);
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	sz = sizeof(struct idx_node) + ubifs_idx_node_sz(c, c->fanout) -
57162306a36Sopenharmony_ci	     UBIFS_IDX_NODE_SZ;
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	/* Start at the old zroot */
57462306a36Sopenharmony_ci	lnum = d->old_zroot.lnum;
57562306a36Sopenharmony_ci	offs = d->old_zroot.offs;
57662306a36Sopenharmony_ci	len = d->old_zroot.len;
57762306a36Sopenharmony_ci	iip = 0;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	/*
58062306a36Sopenharmony_ci	 * Traverse the index tree preorder depth-first i.e. do a node and then
58162306a36Sopenharmony_ci	 * its subtrees from left to right.
58262306a36Sopenharmony_ci	 */
58362306a36Sopenharmony_ci	while (1) {
58462306a36Sopenharmony_ci		struct ubifs_branch *br;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci		/* Get the next index node */
58762306a36Sopenharmony_ci		i = kmalloc(sz, GFP_NOFS);
58862306a36Sopenharmony_ci		if (!i) {
58962306a36Sopenharmony_ci			err = -ENOMEM;
59062306a36Sopenharmony_ci			goto out_free;
59162306a36Sopenharmony_ci		}
59262306a36Sopenharmony_ci		i->iip = iip;
59362306a36Sopenharmony_ci		/* Keep the index nodes on our path in a linked list */
59462306a36Sopenharmony_ci		list_add_tail(&i->list, &list);
59562306a36Sopenharmony_ci		/* Read the index node */
59662306a36Sopenharmony_ci		idx = &i->idx;
59762306a36Sopenharmony_ci		err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs);
59862306a36Sopenharmony_ci		if (err)
59962306a36Sopenharmony_ci			goto out_free;
60062306a36Sopenharmony_ci		/* Validate index node */
60162306a36Sopenharmony_ci		child_cnt = le16_to_cpu(idx->child_cnt);
60262306a36Sopenharmony_ci		if (child_cnt < 1 || child_cnt > c->fanout) {
60362306a36Sopenharmony_ci			err = 1;
60462306a36Sopenharmony_ci			goto out_dump;
60562306a36Sopenharmony_ci		}
60662306a36Sopenharmony_ci		if (first) {
60762306a36Sopenharmony_ci			first = 0;
60862306a36Sopenharmony_ci			/* Check root level and sqnum */
60962306a36Sopenharmony_ci			if (le16_to_cpu(idx->level) != d->old_zroot_level) {
61062306a36Sopenharmony_ci				err = 2;
61162306a36Sopenharmony_ci				goto out_dump;
61262306a36Sopenharmony_ci			}
61362306a36Sopenharmony_ci			if (le64_to_cpu(idx->ch.sqnum) != d->old_zroot_sqnum) {
61462306a36Sopenharmony_ci				err = 3;
61562306a36Sopenharmony_ci				goto out_dump;
61662306a36Sopenharmony_ci			}
61762306a36Sopenharmony_ci			/* Set last values as though root had a parent */
61862306a36Sopenharmony_ci			last_level = le16_to_cpu(idx->level) + 1;
61962306a36Sopenharmony_ci			last_sqnum = le64_to_cpu(idx->ch.sqnum) + 1;
62062306a36Sopenharmony_ci			key_read(c, ubifs_idx_key(c, idx), &lower_key);
62162306a36Sopenharmony_ci			highest_ino_key(c, &upper_key, INUM_WATERMARK);
62262306a36Sopenharmony_ci		}
62362306a36Sopenharmony_ci		key_copy(c, &upper_key, &i->upper_key);
62462306a36Sopenharmony_ci		if (le16_to_cpu(idx->level) != last_level - 1) {
62562306a36Sopenharmony_ci			err = 3;
62662306a36Sopenharmony_ci			goto out_dump;
62762306a36Sopenharmony_ci		}
62862306a36Sopenharmony_ci		/*
62962306a36Sopenharmony_ci		 * The index is always written bottom up hence a child's sqnum
63062306a36Sopenharmony_ci		 * is always less than the parents.
63162306a36Sopenharmony_ci		 */
63262306a36Sopenharmony_ci		if (le64_to_cpu(idx->ch.sqnum) >= last_sqnum) {
63362306a36Sopenharmony_ci			err = 4;
63462306a36Sopenharmony_ci			goto out_dump;
63562306a36Sopenharmony_ci		}
63662306a36Sopenharmony_ci		/* Check key range */
63762306a36Sopenharmony_ci		key_read(c, ubifs_idx_key(c, idx), &l_key);
63862306a36Sopenharmony_ci		br = ubifs_idx_branch(c, idx, child_cnt - 1);
63962306a36Sopenharmony_ci		key_read(c, &br->key, &u_key);
64062306a36Sopenharmony_ci		if (keys_cmp(c, &lower_key, &l_key) > 0) {
64162306a36Sopenharmony_ci			err = 5;
64262306a36Sopenharmony_ci			goto out_dump;
64362306a36Sopenharmony_ci		}
64462306a36Sopenharmony_ci		if (keys_cmp(c, &upper_key, &u_key) < 0) {
64562306a36Sopenharmony_ci			err = 6;
64662306a36Sopenharmony_ci			goto out_dump;
64762306a36Sopenharmony_ci		}
64862306a36Sopenharmony_ci		if (keys_cmp(c, &upper_key, &u_key) == 0)
64962306a36Sopenharmony_ci			if (!is_hash_key(c, &u_key)) {
65062306a36Sopenharmony_ci				err = 7;
65162306a36Sopenharmony_ci				goto out_dump;
65262306a36Sopenharmony_ci			}
65362306a36Sopenharmony_ci		/* Go to next index node */
65462306a36Sopenharmony_ci		if (le16_to_cpu(idx->level) == 0) {
65562306a36Sopenharmony_ci			/* At the bottom, so go up until can go right */
65662306a36Sopenharmony_ci			while (1) {
65762306a36Sopenharmony_ci				/* Drop the bottom of the list */
65862306a36Sopenharmony_ci				list_del(&i->list);
65962306a36Sopenharmony_ci				kfree(i);
66062306a36Sopenharmony_ci				/* No more list means we are done */
66162306a36Sopenharmony_ci				if (list_empty(&list))
66262306a36Sopenharmony_ci					goto out;
66362306a36Sopenharmony_ci				/* Look at the new bottom */
66462306a36Sopenharmony_ci				i = list_entry(list.prev, struct idx_node,
66562306a36Sopenharmony_ci					       list);
66662306a36Sopenharmony_ci				idx = &i->idx;
66762306a36Sopenharmony_ci				/* Can we go right */
66862306a36Sopenharmony_ci				if (iip + 1 < le16_to_cpu(idx->child_cnt)) {
66962306a36Sopenharmony_ci					iip = iip + 1;
67062306a36Sopenharmony_ci					break;
67162306a36Sopenharmony_ci				} else
67262306a36Sopenharmony_ci					/* Nope, so go up again */
67362306a36Sopenharmony_ci					iip = i->iip;
67462306a36Sopenharmony_ci			}
67562306a36Sopenharmony_ci		} else
67662306a36Sopenharmony_ci			/* Go down left */
67762306a36Sopenharmony_ci			iip = 0;
67862306a36Sopenharmony_ci		/*
67962306a36Sopenharmony_ci		 * We have the parent in 'idx' and now we set up for reading the
68062306a36Sopenharmony_ci		 * child pointed to by slot 'iip'.
68162306a36Sopenharmony_ci		 */
68262306a36Sopenharmony_ci		last_level = le16_to_cpu(idx->level);
68362306a36Sopenharmony_ci		last_sqnum = le64_to_cpu(idx->ch.sqnum);
68462306a36Sopenharmony_ci		br = ubifs_idx_branch(c, idx, iip);
68562306a36Sopenharmony_ci		lnum = le32_to_cpu(br->lnum);
68662306a36Sopenharmony_ci		offs = le32_to_cpu(br->offs);
68762306a36Sopenharmony_ci		len = le32_to_cpu(br->len);
68862306a36Sopenharmony_ci		key_read(c, &br->key, &lower_key);
68962306a36Sopenharmony_ci		if (iip + 1 < le16_to_cpu(idx->child_cnt)) {
69062306a36Sopenharmony_ci			br = ubifs_idx_branch(c, idx, iip + 1);
69162306a36Sopenharmony_ci			key_read(c, &br->key, &upper_key);
69262306a36Sopenharmony_ci		} else
69362306a36Sopenharmony_ci			key_copy(c, &i->upper_key, &upper_key);
69462306a36Sopenharmony_ci	}
69562306a36Sopenharmony_ciout:
69662306a36Sopenharmony_ci	err = dbg_old_index_check_init(c, zroot);
69762306a36Sopenharmony_ci	if (err)
69862306a36Sopenharmony_ci		goto out_free;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	return 0;
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ciout_dump:
70362306a36Sopenharmony_ci	ubifs_err(c, "dumping index node (iip=%d)", i->iip);
70462306a36Sopenharmony_ci	ubifs_dump_node(c, idx, ubifs_idx_node_sz(c, c->fanout));
70562306a36Sopenharmony_ci	list_del(&i->list);
70662306a36Sopenharmony_ci	kfree(i);
70762306a36Sopenharmony_ci	if (!list_empty(&list)) {
70862306a36Sopenharmony_ci		i = list_entry(list.prev, struct idx_node, list);
70962306a36Sopenharmony_ci		ubifs_err(c, "dumping parent index node");
71062306a36Sopenharmony_ci		ubifs_dump_node(c, &i->idx, ubifs_idx_node_sz(c, c->fanout));
71162306a36Sopenharmony_ci	}
71262306a36Sopenharmony_ciout_free:
71362306a36Sopenharmony_ci	while (!list_empty(&list)) {
71462306a36Sopenharmony_ci		i = list_entry(list.next, struct idx_node, list);
71562306a36Sopenharmony_ci		list_del(&i->list);
71662306a36Sopenharmony_ci		kfree(i);
71762306a36Sopenharmony_ci	}
71862306a36Sopenharmony_ci	ubifs_err(c, "failed, error %d", err);
71962306a36Sopenharmony_ci	if (err > 0)
72062306a36Sopenharmony_ci		err = -EINVAL;
72162306a36Sopenharmony_ci	return err;
72262306a36Sopenharmony_ci}
723