18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * This file is part of UBIFS.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Authors: Adrian Hunter
88c2ecf20Sopenharmony_ci *          Artem Bityutskiy (Битюцкий Артём)
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/* This file implements TNC functions for committing */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/random.h>
148c2ecf20Sopenharmony_ci#include "ubifs.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci/**
178c2ecf20Sopenharmony_ci * make_idx_node - make an index node for fill-the-gaps method of TNC commit.
188c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
198c2ecf20Sopenharmony_ci * @idx: buffer in which to place new index node
208c2ecf20Sopenharmony_ci * @znode: znode from which to make new index node
218c2ecf20Sopenharmony_ci * @lnum: LEB number where new index node will be written
228c2ecf20Sopenharmony_ci * @offs: offset where new index node will be written
238c2ecf20Sopenharmony_ci * @len: length of new index node
248c2ecf20Sopenharmony_ci */
258c2ecf20Sopenharmony_cistatic int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx,
268c2ecf20Sopenharmony_ci			 struct ubifs_znode *znode, int lnum, int offs, int len)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	struct ubifs_znode *zp;
298c2ecf20Sopenharmony_ci	u8 hash[UBIFS_HASH_ARR_SZ];
308c2ecf20Sopenharmony_ci	int i, err;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	/* Make index node */
338c2ecf20Sopenharmony_ci	idx->ch.node_type = UBIFS_IDX_NODE;
348c2ecf20Sopenharmony_ci	idx->child_cnt = cpu_to_le16(znode->child_cnt);
358c2ecf20Sopenharmony_ci	idx->level = cpu_to_le16(znode->level);
368c2ecf20Sopenharmony_ci	for (i = 0; i < znode->child_cnt; i++) {
378c2ecf20Sopenharmony_ci		struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
388c2ecf20Sopenharmony_ci		struct ubifs_zbranch *zbr = &znode->zbranch[i];
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci		key_write_idx(c, &zbr->key, &br->key);
418c2ecf20Sopenharmony_ci		br->lnum = cpu_to_le32(zbr->lnum);
428c2ecf20Sopenharmony_ci		br->offs = cpu_to_le32(zbr->offs);
438c2ecf20Sopenharmony_ci		br->len = cpu_to_le32(zbr->len);
448c2ecf20Sopenharmony_ci		ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
458c2ecf20Sopenharmony_ci		if (!zbr->lnum || !zbr->len) {
468c2ecf20Sopenharmony_ci			ubifs_err(c, "bad ref in znode");
478c2ecf20Sopenharmony_ci			ubifs_dump_znode(c, znode);
488c2ecf20Sopenharmony_ci			if (zbr->znode)
498c2ecf20Sopenharmony_ci				ubifs_dump_znode(c, zbr->znode);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci			return -EINVAL;
528c2ecf20Sopenharmony_ci		}
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci	ubifs_prepare_node(c, idx, len, 0);
558c2ecf20Sopenharmony_ci	ubifs_node_calc_hash(c, idx, hash);
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	znode->lnum = lnum;
588c2ecf20Sopenharmony_ci	znode->offs = offs;
598c2ecf20Sopenharmony_ci	znode->len = len;
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	err = insert_old_idx_znode(c, znode);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	/* Update the parent */
648c2ecf20Sopenharmony_ci	zp = znode->parent;
658c2ecf20Sopenharmony_ci	if (zp) {
668c2ecf20Sopenharmony_ci		struct ubifs_zbranch *zbr;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci		zbr = &zp->zbranch[znode->iip];
698c2ecf20Sopenharmony_ci		zbr->lnum = lnum;
708c2ecf20Sopenharmony_ci		zbr->offs = offs;
718c2ecf20Sopenharmony_ci		zbr->len = len;
728c2ecf20Sopenharmony_ci		ubifs_copy_hash(c, hash, zbr->hash);
738c2ecf20Sopenharmony_ci	} else {
748c2ecf20Sopenharmony_ci		c->zroot.lnum = lnum;
758c2ecf20Sopenharmony_ci		c->zroot.offs = offs;
768c2ecf20Sopenharmony_ci		c->zroot.len = len;
778c2ecf20Sopenharmony_ci		ubifs_copy_hash(c, hash, c->zroot.hash);
788c2ecf20Sopenharmony_ci	}
798c2ecf20Sopenharmony_ci	c->calc_idx_sz += ALIGN(len, 8);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	atomic_long_dec(&c->dirty_zn_cnt);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	ubifs_assert(c, ubifs_zn_dirty(znode));
848c2ecf20Sopenharmony_ci	ubifs_assert(c, ubifs_zn_cow(znode));
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	/*
878c2ecf20Sopenharmony_ci	 * Note, unlike 'write_index()' we do not add memory barriers here
888c2ecf20Sopenharmony_ci	 * because this function is called with @c->tnc_mutex locked.
898c2ecf20Sopenharmony_ci	 */
908c2ecf20Sopenharmony_ci	__clear_bit(DIRTY_ZNODE, &znode->flags);
918c2ecf20Sopenharmony_ci	__clear_bit(COW_ZNODE, &znode->flags);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	return err;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/**
978c2ecf20Sopenharmony_ci * fill_gap - make index nodes in gaps in dirty index LEBs.
988c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
998c2ecf20Sopenharmony_ci * @lnum: LEB number that gap appears in
1008c2ecf20Sopenharmony_ci * @gap_start: offset of start of gap
1018c2ecf20Sopenharmony_ci * @gap_end: offset of end of gap
1028c2ecf20Sopenharmony_ci * @dirt: adds dirty space to this
1038c2ecf20Sopenharmony_ci *
1048c2ecf20Sopenharmony_ci * This function returns the number of index nodes written into the gap.
1058c2ecf20Sopenharmony_ci */
1068c2ecf20Sopenharmony_cistatic int fill_gap(struct ubifs_info *c, int lnum, int gap_start, int gap_end,
1078c2ecf20Sopenharmony_ci		    int *dirt)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	int len, gap_remains, gap_pos, written, pad_len;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	ubifs_assert(c, (gap_start & 7) == 0);
1128c2ecf20Sopenharmony_ci	ubifs_assert(c, (gap_end & 7) == 0);
1138c2ecf20Sopenharmony_ci	ubifs_assert(c, gap_end >= gap_start);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	gap_remains = gap_end - gap_start;
1168c2ecf20Sopenharmony_ci	if (!gap_remains)
1178c2ecf20Sopenharmony_ci		return 0;
1188c2ecf20Sopenharmony_ci	gap_pos = gap_start;
1198c2ecf20Sopenharmony_ci	written = 0;
1208c2ecf20Sopenharmony_ci	while (c->enext) {
1218c2ecf20Sopenharmony_ci		len = ubifs_idx_node_sz(c, c->enext->child_cnt);
1228c2ecf20Sopenharmony_ci		if (len < gap_remains) {
1238c2ecf20Sopenharmony_ci			struct ubifs_znode *znode = c->enext;
1248c2ecf20Sopenharmony_ci			const int alen = ALIGN(len, 8);
1258c2ecf20Sopenharmony_ci			int err;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci			ubifs_assert(c, alen <= gap_remains);
1288c2ecf20Sopenharmony_ci			err = make_idx_node(c, c->ileb_buf + gap_pos, znode,
1298c2ecf20Sopenharmony_ci					    lnum, gap_pos, len);
1308c2ecf20Sopenharmony_ci			if (err)
1318c2ecf20Sopenharmony_ci				return err;
1328c2ecf20Sopenharmony_ci			gap_remains -= alen;
1338c2ecf20Sopenharmony_ci			gap_pos += alen;
1348c2ecf20Sopenharmony_ci			c->enext = znode->cnext;
1358c2ecf20Sopenharmony_ci			if (c->enext == c->cnext)
1368c2ecf20Sopenharmony_ci				c->enext = NULL;
1378c2ecf20Sopenharmony_ci			written += 1;
1388c2ecf20Sopenharmony_ci		} else
1398c2ecf20Sopenharmony_ci			break;
1408c2ecf20Sopenharmony_ci	}
1418c2ecf20Sopenharmony_ci	if (gap_end == c->leb_size) {
1428c2ecf20Sopenharmony_ci		c->ileb_len = ALIGN(gap_pos, c->min_io_size);
1438c2ecf20Sopenharmony_ci		/* Pad to end of min_io_size */
1448c2ecf20Sopenharmony_ci		pad_len = c->ileb_len - gap_pos;
1458c2ecf20Sopenharmony_ci	} else
1468c2ecf20Sopenharmony_ci		/* Pad to end of gap */
1478c2ecf20Sopenharmony_ci		pad_len = gap_remains;
1488c2ecf20Sopenharmony_ci	dbg_gc("LEB %d:%d to %d len %d nodes written %d wasted bytes %d",
1498c2ecf20Sopenharmony_ci	       lnum, gap_start, gap_end, gap_end - gap_start, written, pad_len);
1508c2ecf20Sopenharmony_ci	ubifs_pad(c, c->ileb_buf + gap_pos, pad_len);
1518c2ecf20Sopenharmony_ci	*dirt += pad_len;
1528c2ecf20Sopenharmony_ci	return written;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/**
1568c2ecf20Sopenharmony_ci * find_old_idx - find an index node obsoleted since the last commit start.
1578c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
1588c2ecf20Sopenharmony_ci * @lnum: LEB number of obsoleted index node
1598c2ecf20Sopenharmony_ci * @offs: offset of obsoleted index node
1608c2ecf20Sopenharmony_ci *
1618c2ecf20Sopenharmony_ci * Returns %1 if found and %0 otherwise.
1628c2ecf20Sopenharmony_ci */
1638c2ecf20Sopenharmony_cistatic int find_old_idx(struct ubifs_info *c, int lnum, int offs)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	struct ubifs_old_idx *o;
1668c2ecf20Sopenharmony_ci	struct rb_node *p;
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	p = c->old_idx.rb_node;
1698c2ecf20Sopenharmony_ci	while (p) {
1708c2ecf20Sopenharmony_ci		o = rb_entry(p, struct ubifs_old_idx, rb);
1718c2ecf20Sopenharmony_ci		if (lnum < o->lnum)
1728c2ecf20Sopenharmony_ci			p = p->rb_left;
1738c2ecf20Sopenharmony_ci		else if (lnum > o->lnum)
1748c2ecf20Sopenharmony_ci			p = p->rb_right;
1758c2ecf20Sopenharmony_ci		else if (offs < o->offs)
1768c2ecf20Sopenharmony_ci			p = p->rb_left;
1778c2ecf20Sopenharmony_ci		else if (offs > o->offs)
1788c2ecf20Sopenharmony_ci			p = p->rb_right;
1798c2ecf20Sopenharmony_ci		else
1808c2ecf20Sopenharmony_ci			return 1;
1818c2ecf20Sopenharmony_ci	}
1828c2ecf20Sopenharmony_ci	return 0;
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci/**
1868c2ecf20Sopenharmony_ci * is_idx_node_in_use - determine if an index node can be overwritten.
1878c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
1888c2ecf20Sopenharmony_ci * @key: key of index node
1898c2ecf20Sopenharmony_ci * @level: index node level
1908c2ecf20Sopenharmony_ci * @lnum: LEB number of index node
1918c2ecf20Sopenharmony_ci * @offs: offset of index node
1928c2ecf20Sopenharmony_ci *
1938c2ecf20Sopenharmony_ci * If @key / @lnum / @offs identify an index node that was not part of the old
1948c2ecf20Sopenharmony_ci * index, then this function returns %0 (obsolete).  Else if the index node was
1958c2ecf20Sopenharmony_ci * part of the old index but is now dirty %1 is returned, else if it is clean %2
1968c2ecf20Sopenharmony_ci * is returned. A negative error code is returned on failure.
1978c2ecf20Sopenharmony_ci */
1988c2ecf20Sopenharmony_cistatic int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key,
1998c2ecf20Sopenharmony_ci			      int level, int lnum, int offs)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	int ret;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	ret = is_idx_node_in_tnc(c, key, level, lnum, offs);
2048c2ecf20Sopenharmony_ci	if (ret < 0)
2058c2ecf20Sopenharmony_ci		return ret; /* Error code */
2068c2ecf20Sopenharmony_ci	if (ret == 0)
2078c2ecf20Sopenharmony_ci		if (find_old_idx(c, lnum, offs))
2088c2ecf20Sopenharmony_ci			return 1;
2098c2ecf20Sopenharmony_ci	return ret;
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci/**
2138c2ecf20Sopenharmony_ci * layout_leb_in_gaps - layout index nodes using in-the-gaps method.
2148c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
2158c2ecf20Sopenharmony_ci * @p: return LEB number in @c->gap_lebs[p]
2168c2ecf20Sopenharmony_ci *
2178c2ecf20Sopenharmony_ci * This function lays out new index nodes for dirty znodes using in-the-gaps
2188c2ecf20Sopenharmony_ci * method of TNC commit.
2198c2ecf20Sopenharmony_ci * This function merely puts the next znode into the next gap, making no attempt
2208c2ecf20Sopenharmony_ci * to try to maximise the number of znodes that fit.
2218c2ecf20Sopenharmony_ci * This function returns the number of index nodes written into the gaps, or a
2228c2ecf20Sopenharmony_ci * negative error code on failure.
2238c2ecf20Sopenharmony_ci */
2248c2ecf20Sopenharmony_cistatic int layout_leb_in_gaps(struct ubifs_info *c, int p)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	struct ubifs_scan_leb *sleb;
2278c2ecf20Sopenharmony_ci	struct ubifs_scan_node *snod;
2288c2ecf20Sopenharmony_ci	int lnum, dirt = 0, gap_start, gap_end, err, written, tot_written;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	tot_written = 0;
2318c2ecf20Sopenharmony_ci	/* Get an index LEB with lots of obsolete index nodes */
2328c2ecf20Sopenharmony_ci	lnum = ubifs_find_dirty_idx_leb(c);
2338c2ecf20Sopenharmony_ci	if (lnum < 0)
2348c2ecf20Sopenharmony_ci		/*
2358c2ecf20Sopenharmony_ci		 * There also may be dirt in the index head that could be
2368c2ecf20Sopenharmony_ci		 * filled, however we do not check there at present.
2378c2ecf20Sopenharmony_ci		 */
2388c2ecf20Sopenharmony_ci		return lnum; /* Error code */
2398c2ecf20Sopenharmony_ci	c->gap_lebs[p] = lnum;
2408c2ecf20Sopenharmony_ci	dbg_gc("LEB %d", lnum);
2418c2ecf20Sopenharmony_ci	/*
2428c2ecf20Sopenharmony_ci	 * Scan the index LEB.  We use the generic scan for this even though
2438c2ecf20Sopenharmony_ci	 * it is more comprehensive and less efficient than is needed for this
2448c2ecf20Sopenharmony_ci	 * purpose.
2458c2ecf20Sopenharmony_ci	 */
2468c2ecf20Sopenharmony_ci	sleb = ubifs_scan(c, lnum, 0, c->ileb_buf, 0);
2478c2ecf20Sopenharmony_ci	c->ileb_len = 0;
2488c2ecf20Sopenharmony_ci	if (IS_ERR(sleb))
2498c2ecf20Sopenharmony_ci		return PTR_ERR(sleb);
2508c2ecf20Sopenharmony_ci	gap_start = 0;
2518c2ecf20Sopenharmony_ci	list_for_each_entry(snod, &sleb->nodes, list) {
2528c2ecf20Sopenharmony_ci		struct ubifs_idx_node *idx;
2538c2ecf20Sopenharmony_ci		int in_use, level;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		ubifs_assert(c, snod->type == UBIFS_IDX_NODE);
2568c2ecf20Sopenharmony_ci		idx = snod->node;
2578c2ecf20Sopenharmony_ci		key_read(c, ubifs_idx_key(c, idx), &snod->key);
2588c2ecf20Sopenharmony_ci		level = le16_to_cpu(idx->level);
2598c2ecf20Sopenharmony_ci		/* Determine if the index node is in use (not obsolete) */
2608c2ecf20Sopenharmony_ci		in_use = is_idx_node_in_use(c, &snod->key, level, lnum,
2618c2ecf20Sopenharmony_ci					    snod->offs);
2628c2ecf20Sopenharmony_ci		if (in_use < 0) {
2638c2ecf20Sopenharmony_ci			ubifs_scan_destroy(sleb);
2648c2ecf20Sopenharmony_ci			return in_use; /* Error code */
2658c2ecf20Sopenharmony_ci		}
2668c2ecf20Sopenharmony_ci		if (in_use) {
2678c2ecf20Sopenharmony_ci			if (in_use == 1)
2688c2ecf20Sopenharmony_ci				dirt += ALIGN(snod->len, 8);
2698c2ecf20Sopenharmony_ci			/*
2708c2ecf20Sopenharmony_ci			 * The obsolete index nodes form gaps that can be
2718c2ecf20Sopenharmony_ci			 * overwritten.  This gap has ended because we have
2728c2ecf20Sopenharmony_ci			 * found an index node that is still in use
2738c2ecf20Sopenharmony_ci			 * i.e. not obsolete
2748c2ecf20Sopenharmony_ci			 */
2758c2ecf20Sopenharmony_ci			gap_end = snod->offs;
2768c2ecf20Sopenharmony_ci			/* Try to fill gap */
2778c2ecf20Sopenharmony_ci			written = fill_gap(c, lnum, gap_start, gap_end, &dirt);
2788c2ecf20Sopenharmony_ci			if (written < 0) {
2798c2ecf20Sopenharmony_ci				ubifs_scan_destroy(sleb);
2808c2ecf20Sopenharmony_ci				return written; /* Error code */
2818c2ecf20Sopenharmony_ci			}
2828c2ecf20Sopenharmony_ci			tot_written += written;
2838c2ecf20Sopenharmony_ci			gap_start = ALIGN(snod->offs + snod->len, 8);
2848c2ecf20Sopenharmony_ci		}
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci	ubifs_scan_destroy(sleb);
2878c2ecf20Sopenharmony_ci	c->ileb_len = c->leb_size;
2888c2ecf20Sopenharmony_ci	gap_end = c->leb_size;
2898c2ecf20Sopenharmony_ci	/* Try to fill gap */
2908c2ecf20Sopenharmony_ci	written = fill_gap(c, lnum, gap_start, gap_end, &dirt);
2918c2ecf20Sopenharmony_ci	if (written < 0)
2928c2ecf20Sopenharmony_ci		return written; /* Error code */
2938c2ecf20Sopenharmony_ci	tot_written += written;
2948c2ecf20Sopenharmony_ci	if (tot_written == 0) {
2958c2ecf20Sopenharmony_ci		struct ubifs_lprops lp;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
2988c2ecf20Sopenharmony_ci		err = ubifs_read_one_lp(c, lnum, &lp);
2998c2ecf20Sopenharmony_ci		if (err)
3008c2ecf20Sopenharmony_ci			return err;
3018c2ecf20Sopenharmony_ci		if (lp.free == c->leb_size) {
3028c2ecf20Sopenharmony_ci			/*
3038c2ecf20Sopenharmony_ci			 * We must have snatched this LEB from the idx_gc list
3048c2ecf20Sopenharmony_ci			 * so we need to correct the free and dirty space.
3058c2ecf20Sopenharmony_ci			 */
3068c2ecf20Sopenharmony_ci			err = ubifs_change_one_lp(c, lnum,
3078c2ecf20Sopenharmony_ci						  c->leb_size - c->ileb_len,
3088c2ecf20Sopenharmony_ci						  dirt, 0, 0, 0);
3098c2ecf20Sopenharmony_ci			if (err)
3108c2ecf20Sopenharmony_ci				return err;
3118c2ecf20Sopenharmony_ci		}
3128c2ecf20Sopenharmony_ci		return 0;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci	err = ubifs_change_one_lp(c, lnum, c->leb_size - c->ileb_len, dirt,
3158c2ecf20Sopenharmony_ci				  0, 0, 0);
3168c2ecf20Sopenharmony_ci	if (err)
3178c2ecf20Sopenharmony_ci		return err;
3188c2ecf20Sopenharmony_ci	err = ubifs_leb_change(c, lnum, c->ileb_buf, c->ileb_len);
3198c2ecf20Sopenharmony_ci	if (err)
3208c2ecf20Sopenharmony_ci		return err;
3218c2ecf20Sopenharmony_ci	dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written);
3228c2ecf20Sopenharmony_ci	return tot_written;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci/**
3268c2ecf20Sopenharmony_ci * get_leb_cnt - calculate the number of empty LEBs needed to commit.
3278c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
3288c2ecf20Sopenharmony_ci * @cnt: number of znodes to commit
3298c2ecf20Sopenharmony_ci *
3308c2ecf20Sopenharmony_ci * This function returns the number of empty LEBs needed to commit @cnt znodes
3318c2ecf20Sopenharmony_ci * to the current index head.  The number is not exact and may be more than
3328c2ecf20Sopenharmony_ci * needed.
3338c2ecf20Sopenharmony_ci */
3348c2ecf20Sopenharmony_cistatic int get_leb_cnt(struct ubifs_info *c, int cnt)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	int d;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	/* Assume maximum index node size (i.e. overestimate space needed) */
3398c2ecf20Sopenharmony_ci	cnt -= (c->leb_size - c->ihead_offs) / c->max_idx_node_sz;
3408c2ecf20Sopenharmony_ci	if (cnt < 0)
3418c2ecf20Sopenharmony_ci		cnt = 0;
3428c2ecf20Sopenharmony_ci	d = c->leb_size / c->max_idx_node_sz;
3438c2ecf20Sopenharmony_ci	return DIV_ROUND_UP(cnt, d);
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci/**
3478c2ecf20Sopenharmony_ci * layout_in_gaps - in-the-gaps method of committing TNC.
3488c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
3498c2ecf20Sopenharmony_ci * @cnt: number of dirty znodes to commit.
3508c2ecf20Sopenharmony_ci *
3518c2ecf20Sopenharmony_ci * This function lays out new index nodes for dirty znodes using in-the-gaps
3528c2ecf20Sopenharmony_ci * method of TNC commit.
3538c2ecf20Sopenharmony_ci *
3548c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
3558c2ecf20Sopenharmony_ci */
3568c2ecf20Sopenharmony_cistatic int layout_in_gaps(struct ubifs_info *c, int cnt)
3578c2ecf20Sopenharmony_ci{
3588c2ecf20Sopenharmony_ci	int err, leb_needed_cnt, written, p = 0, old_idx_lebs, *gap_lebs;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	dbg_gc("%d znodes to write", cnt);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	c->gap_lebs = kmalloc_array(c->lst.idx_lebs + 1, sizeof(int),
3638c2ecf20Sopenharmony_ci				    GFP_NOFS);
3648c2ecf20Sopenharmony_ci	if (!c->gap_lebs)
3658c2ecf20Sopenharmony_ci		return -ENOMEM;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	old_idx_lebs = c->lst.idx_lebs;
3688c2ecf20Sopenharmony_ci	do {
3698c2ecf20Sopenharmony_ci		ubifs_assert(c, p < c->lst.idx_lebs);
3708c2ecf20Sopenharmony_ci		written = layout_leb_in_gaps(c, p);
3718c2ecf20Sopenharmony_ci		if (written < 0) {
3728c2ecf20Sopenharmony_ci			err = written;
3738c2ecf20Sopenharmony_ci			if (err != -ENOSPC) {
3748c2ecf20Sopenharmony_ci				kfree(c->gap_lebs);
3758c2ecf20Sopenharmony_ci				c->gap_lebs = NULL;
3768c2ecf20Sopenharmony_ci				return err;
3778c2ecf20Sopenharmony_ci			}
3788c2ecf20Sopenharmony_ci			if (!dbg_is_chk_index(c)) {
3798c2ecf20Sopenharmony_ci				/*
3808c2ecf20Sopenharmony_ci				 * Do not print scary warnings if the debugging
3818c2ecf20Sopenharmony_ci				 * option which forces in-the-gaps is enabled.
3828c2ecf20Sopenharmony_ci				 */
3838c2ecf20Sopenharmony_ci				ubifs_warn(c, "out of space");
3848c2ecf20Sopenharmony_ci				ubifs_dump_budg(c, &c->bi);
3858c2ecf20Sopenharmony_ci				ubifs_dump_lprops(c);
3868c2ecf20Sopenharmony_ci			}
3878c2ecf20Sopenharmony_ci			/* Try to commit anyway */
3888c2ecf20Sopenharmony_ci			break;
3898c2ecf20Sopenharmony_ci		}
3908c2ecf20Sopenharmony_ci		p++;
3918c2ecf20Sopenharmony_ci		cnt -= written;
3928c2ecf20Sopenharmony_ci		leb_needed_cnt = get_leb_cnt(c, cnt);
3938c2ecf20Sopenharmony_ci		dbg_gc("%d znodes remaining, need %d LEBs, have %d", cnt,
3948c2ecf20Sopenharmony_ci		       leb_needed_cnt, c->ileb_cnt);
3958c2ecf20Sopenharmony_ci		/*
3968c2ecf20Sopenharmony_ci		 * Dynamically change the size of @c->gap_lebs to prevent
3978c2ecf20Sopenharmony_ci		 * oob, because @c->lst.idx_lebs could be increased by
3988c2ecf20Sopenharmony_ci		 * function @get_idx_gc_leb (called by layout_leb_in_gaps->
3998c2ecf20Sopenharmony_ci		 * ubifs_find_dirty_idx_leb) during loop. Only enlarge
4008c2ecf20Sopenharmony_ci		 * @c->gap_lebs when needed.
4018c2ecf20Sopenharmony_ci		 *
4028c2ecf20Sopenharmony_ci		 */
4038c2ecf20Sopenharmony_ci		if (leb_needed_cnt > c->ileb_cnt && p >= old_idx_lebs &&
4048c2ecf20Sopenharmony_ci		    old_idx_lebs < c->lst.idx_lebs) {
4058c2ecf20Sopenharmony_ci			old_idx_lebs = c->lst.idx_lebs;
4068c2ecf20Sopenharmony_ci			gap_lebs = krealloc(c->gap_lebs, sizeof(int) *
4078c2ecf20Sopenharmony_ci					       (old_idx_lebs + 1), GFP_NOFS);
4088c2ecf20Sopenharmony_ci			if (!gap_lebs) {
4098c2ecf20Sopenharmony_ci				kfree(c->gap_lebs);
4108c2ecf20Sopenharmony_ci				c->gap_lebs = NULL;
4118c2ecf20Sopenharmony_ci				return -ENOMEM;
4128c2ecf20Sopenharmony_ci			}
4138c2ecf20Sopenharmony_ci			c->gap_lebs = gap_lebs;
4148c2ecf20Sopenharmony_ci		}
4158c2ecf20Sopenharmony_ci	} while (leb_needed_cnt > c->ileb_cnt);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	c->gap_lebs[p] = -1;
4188c2ecf20Sopenharmony_ci	return 0;
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci/**
4228c2ecf20Sopenharmony_ci * layout_in_empty_space - layout index nodes in empty space.
4238c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
4248c2ecf20Sopenharmony_ci *
4258c2ecf20Sopenharmony_ci * This function lays out new index nodes for dirty znodes using empty LEBs.
4268c2ecf20Sopenharmony_ci *
4278c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
4288c2ecf20Sopenharmony_ci */
4298c2ecf20Sopenharmony_cistatic int layout_in_empty_space(struct ubifs_info *c)
4308c2ecf20Sopenharmony_ci{
4318c2ecf20Sopenharmony_ci	struct ubifs_znode *znode, *cnext, *zp;
4328c2ecf20Sopenharmony_ci	int lnum, offs, len, next_len, buf_len, buf_offs, used, avail;
4338c2ecf20Sopenharmony_ci	int wlen, blen, err;
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_ci	cnext = c->enext;
4368c2ecf20Sopenharmony_ci	if (!cnext)
4378c2ecf20Sopenharmony_ci		return 0;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	lnum = c->ihead_lnum;
4408c2ecf20Sopenharmony_ci	buf_offs = c->ihead_offs;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	buf_len = ubifs_idx_node_sz(c, c->fanout);
4438c2ecf20Sopenharmony_ci	buf_len = ALIGN(buf_len, c->min_io_size);
4448c2ecf20Sopenharmony_ci	used = 0;
4458c2ecf20Sopenharmony_ci	avail = buf_len;
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	/* Ensure there is enough room for first write */
4488c2ecf20Sopenharmony_ci	next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
4498c2ecf20Sopenharmony_ci	if (buf_offs + next_len > c->leb_size)
4508c2ecf20Sopenharmony_ci		lnum = -1;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	while (1) {
4538c2ecf20Sopenharmony_ci		znode = cnext;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		len = ubifs_idx_node_sz(c, znode->child_cnt);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		/* Determine the index node position */
4588c2ecf20Sopenharmony_ci		if (lnum == -1) {
4598c2ecf20Sopenharmony_ci			if (c->ileb_nxt >= c->ileb_cnt) {
4608c2ecf20Sopenharmony_ci				ubifs_err(c, "out of space");
4618c2ecf20Sopenharmony_ci				return -ENOSPC;
4628c2ecf20Sopenharmony_ci			}
4638c2ecf20Sopenharmony_ci			lnum = c->ilebs[c->ileb_nxt++];
4648c2ecf20Sopenharmony_ci			buf_offs = 0;
4658c2ecf20Sopenharmony_ci			used = 0;
4668c2ecf20Sopenharmony_ci			avail = buf_len;
4678c2ecf20Sopenharmony_ci		}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci		offs = buf_offs + used;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci		znode->lnum = lnum;
4728c2ecf20Sopenharmony_ci		znode->offs = offs;
4738c2ecf20Sopenharmony_ci		znode->len = len;
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci		/* Update the parent */
4768c2ecf20Sopenharmony_ci		zp = znode->parent;
4778c2ecf20Sopenharmony_ci		if (zp) {
4788c2ecf20Sopenharmony_ci			struct ubifs_zbranch *zbr;
4798c2ecf20Sopenharmony_ci			int i;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci			i = znode->iip;
4828c2ecf20Sopenharmony_ci			zbr = &zp->zbranch[i];
4838c2ecf20Sopenharmony_ci			zbr->lnum = lnum;
4848c2ecf20Sopenharmony_ci			zbr->offs = offs;
4858c2ecf20Sopenharmony_ci			zbr->len = len;
4868c2ecf20Sopenharmony_ci		} else {
4878c2ecf20Sopenharmony_ci			c->zroot.lnum = lnum;
4888c2ecf20Sopenharmony_ci			c->zroot.offs = offs;
4898c2ecf20Sopenharmony_ci			c->zroot.len = len;
4908c2ecf20Sopenharmony_ci		}
4918c2ecf20Sopenharmony_ci		c->calc_idx_sz += ALIGN(len, 8);
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci		/*
4948c2ecf20Sopenharmony_ci		 * Once lprops is updated, we can decrease the dirty znode count
4958c2ecf20Sopenharmony_ci		 * but it is easier to just do it here.
4968c2ecf20Sopenharmony_ci		 */
4978c2ecf20Sopenharmony_ci		atomic_long_dec(&c->dirty_zn_cnt);
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci		/*
5008c2ecf20Sopenharmony_ci		 * Calculate the next index node length to see if there is
5018c2ecf20Sopenharmony_ci		 * enough room for it
5028c2ecf20Sopenharmony_ci		 */
5038c2ecf20Sopenharmony_ci		cnext = znode->cnext;
5048c2ecf20Sopenharmony_ci		if (cnext == c->cnext)
5058c2ecf20Sopenharmony_ci			next_len = 0;
5068c2ecf20Sopenharmony_ci		else
5078c2ecf20Sopenharmony_ci			next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci		/* Update buffer positions */
5108c2ecf20Sopenharmony_ci		wlen = used + len;
5118c2ecf20Sopenharmony_ci		used += ALIGN(len, 8);
5128c2ecf20Sopenharmony_ci		avail -= ALIGN(len, 8);
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci		if (next_len != 0 &&
5158c2ecf20Sopenharmony_ci		    buf_offs + used + next_len <= c->leb_size &&
5168c2ecf20Sopenharmony_ci		    avail > 0)
5178c2ecf20Sopenharmony_ci			continue;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci		if (avail <= 0 && next_len &&
5208c2ecf20Sopenharmony_ci		    buf_offs + used + next_len <= c->leb_size)
5218c2ecf20Sopenharmony_ci			blen = buf_len;
5228c2ecf20Sopenharmony_ci		else
5238c2ecf20Sopenharmony_ci			blen = ALIGN(wlen, c->min_io_size);
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci		/* The buffer is full or there are no more znodes to do */
5268c2ecf20Sopenharmony_ci		buf_offs += blen;
5278c2ecf20Sopenharmony_ci		if (next_len) {
5288c2ecf20Sopenharmony_ci			if (buf_offs + next_len > c->leb_size) {
5298c2ecf20Sopenharmony_ci				err = ubifs_update_one_lp(c, lnum,
5308c2ecf20Sopenharmony_ci					c->leb_size - buf_offs, blen - used,
5318c2ecf20Sopenharmony_ci					0, 0);
5328c2ecf20Sopenharmony_ci				if (err)
5338c2ecf20Sopenharmony_ci					return err;
5348c2ecf20Sopenharmony_ci				lnum = -1;
5358c2ecf20Sopenharmony_ci			}
5368c2ecf20Sopenharmony_ci			used -= blen;
5378c2ecf20Sopenharmony_ci			if (used < 0)
5388c2ecf20Sopenharmony_ci				used = 0;
5398c2ecf20Sopenharmony_ci			avail = buf_len - used;
5408c2ecf20Sopenharmony_ci			continue;
5418c2ecf20Sopenharmony_ci		}
5428c2ecf20Sopenharmony_ci		err = ubifs_update_one_lp(c, lnum, c->leb_size - buf_offs,
5438c2ecf20Sopenharmony_ci					  blen - used, 0, 0);
5448c2ecf20Sopenharmony_ci		if (err)
5458c2ecf20Sopenharmony_ci			return err;
5468c2ecf20Sopenharmony_ci		break;
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	c->dbg->new_ihead_lnum = lnum;
5508c2ecf20Sopenharmony_ci	c->dbg->new_ihead_offs = buf_offs;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	return 0;
5538c2ecf20Sopenharmony_ci}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci/**
5568c2ecf20Sopenharmony_ci * layout_commit - determine positions of index nodes to commit.
5578c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
5588c2ecf20Sopenharmony_ci * @no_space: indicates that insufficient empty LEBs were allocated
5598c2ecf20Sopenharmony_ci * @cnt: number of znodes to commit
5608c2ecf20Sopenharmony_ci *
5618c2ecf20Sopenharmony_ci * Calculate and update the positions of index nodes to commit.  If there were
5628c2ecf20Sopenharmony_ci * an insufficient number of empty LEBs allocated, then index nodes are placed
5638c2ecf20Sopenharmony_ci * into the gaps created by obsolete index nodes in non-empty index LEBs.  For
5648c2ecf20Sopenharmony_ci * this purpose, an obsolete index node is one that was not in the index as at
5658c2ecf20Sopenharmony_ci * the end of the last commit.  To write "in-the-gaps" requires that those index
5668c2ecf20Sopenharmony_ci * LEBs are updated atomically in-place.
5678c2ecf20Sopenharmony_ci */
5688c2ecf20Sopenharmony_cistatic int layout_commit(struct ubifs_info *c, int no_space, int cnt)
5698c2ecf20Sopenharmony_ci{
5708c2ecf20Sopenharmony_ci	int err;
5718c2ecf20Sopenharmony_ci
5728c2ecf20Sopenharmony_ci	if (no_space) {
5738c2ecf20Sopenharmony_ci		err = layout_in_gaps(c, cnt);
5748c2ecf20Sopenharmony_ci		if (err)
5758c2ecf20Sopenharmony_ci			return err;
5768c2ecf20Sopenharmony_ci	}
5778c2ecf20Sopenharmony_ci	err = layout_in_empty_space(c);
5788c2ecf20Sopenharmony_ci	return err;
5798c2ecf20Sopenharmony_ci}
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci/**
5828c2ecf20Sopenharmony_ci * find_first_dirty - find first dirty znode.
5838c2ecf20Sopenharmony_ci * @znode: znode to begin searching from
5848c2ecf20Sopenharmony_ci */
5858c2ecf20Sopenharmony_cistatic struct ubifs_znode *find_first_dirty(struct ubifs_znode *znode)
5868c2ecf20Sopenharmony_ci{
5878c2ecf20Sopenharmony_ci	int i, cont;
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	if (!znode)
5908c2ecf20Sopenharmony_ci		return NULL;
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	while (1) {
5938c2ecf20Sopenharmony_ci		if (znode->level == 0) {
5948c2ecf20Sopenharmony_ci			if (ubifs_zn_dirty(znode))
5958c2ecf20Sopenharmony_ci				return znode;
5968c2ecf20Sopenharmony_ci			return NULL;
5978c2ecf20Sopenharmony_ci		}
5988c2ecf20Sopenharmony_ci		cont = 0;
5998c2ecf20Sopenharmony_ci		for (i = 0; i < znode->child_cnt; i++) {
6008c2ecf20Sopenharmony_ci			struct ubifs_zbranch *zbr = &znode->zbranch[i];
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci			if (zbr->znode && ubifs_zn_dirty(zbr->znode)) {
6038c2ecf20Sopenharmony_ci				znode = zbr->znode;
6048c2ecf20Sopenharmony_ci				cont = 1;
6058c2ecf20Sopenharmony_ci				break;
6068c2ecf20Sopenharmony_ci			}
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci		if (!cont) {
6098c2ecf20Sopenharmony_ci			if (ubifs_zn_dirty(znode))
6108c2ecf20Sopenharmony_ci				return znode;
6118c2ecf20Sopenharmony_ci			return NULL;
6128c2ecf20Sopenharmony_ci		}
6138c2ecf20Sopenharmony_ci	}
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci/**
6178c2ecf20Sopenharmony_ci * find_next_dirty - find next dirty znode.
6188c2ecf20Sopenharmony_ci * @znode: znode to begin searching from
6198c2ecf20Sopenharmony_ci */
6208c2ecf20Sopenharmony_cistatic struct ubifs_znode *find_next_dirty(struct ubifs_znode *znode)
6218c2ecf20Sopenharmony_ci{
6228c2ecf20Sopenharmony_ci	int n = znode->iip + 1;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	znode = znode->parent;
6258c2ecf20Sopenharmony_ci	if (!znode)
6268c2ecf20Sopenharmony_ci		return NULL;
6278c2ecf20Sopenharmony_ci	for (; n < znode->child_cnt; n++) {
6288c2ecf20Sopenharmony_ci		struct ubifs_zbranch *zbr = &znode->zbranch[n];
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci		if (zbr->znode && ubifs_zn_dirty(zbr->znode))
6318c2ecf20Sopenharmony_ci			return find_first_dirty(zbr->znode);
6328c2ecf20Sopenharmony_ci	}
6338c2ecf20Sopenharmony_ci	return znode;
6348c2ecf20Sopenharmony_ci}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci/**
6378c2ecf20Sopenharmony_ci * get_znodes_to_commit - create list of dirty znodes to commit.
6388c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
6398c2ecf20Sopenharmony_ci *
6408c2ecf20Sopenharmony_ci * This function returns the number of znodes to commit.
6418c2ecf20Sopenharmony_ci */
6428c2ecf20Sopenharmony_cistatic int get_znodes_to_commit(struct ubifs_info *c)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct ubifs_znode *znode, *cnext;
6458c2ecf20Sopenharmony_ci	int cnt = 0;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	c->cnext = find_first_dirty(c->zroot.znode);
6488c2ecf20Sopenharmony_ci	znode = c->enext = c->cnext;
6498c2ecf20Sopenharmony_ci	if (!znode) {
6508c2ecf20Sopenharmony_ci		dbg_cmt("no znodes to commit");
6518c2ecf20Sopenharmony_ci		return 0;
6528c2ecf20Sopenharmony_ci	}
6538c2ecf20Sopenharmony_ci	cnt += 1;
6548c2ecf20Sopenharmony_ci	while (1) {
6558c2ecf20Sopenharmony_ci		ubifs_assert(c, !ubifs_zn_cow(znode));
6568c2ecf20Sopenharmony_ci		__set_bit(COW_ZNODE, &znode->flags);
6578c2ecf20Sopenharmony_ci		znode->alt = 0;
6588c2ecf20Sopenharmony_ci		cnext = find_next_dirty(znode);
6598c2ecf20Sopenharmony_ci		if (!cnext) {
6608c2ecf20Sopenharmony_ci			znode->cnext = c->cnext;
6618c2ecf20Sopenharmony_ci			break;
6628c2ecf20Sopenharmony_ci		}
6638c2ecf20Sopenharmony_ci		znode->cparent = znode->parent;
6648c2ecf20Sopenharmony_ci		znode->ciip = znode->iip;
6658c2ecf20Sopenharmony_ci		znode->cnext = cnext;
6668c2ecf20Sopenharmony_ci		znode = cnext;
6678c2ecf20Sopenharmony_ci		cnt += 1;
6688c2ecf20Sopenharmony_ci	}
6698c2ecf20Sopenharmony_ci	dbg_cmt("committing %d znodes", cnt);
6708c2ecf20Sopenharmony_ci	ubifs_assert(c, cnt == atomic_long_read(&c->dirty_zn_cnt));
6718c2ecf20Sopenharmony_ci	return cnt;
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci/**
6758c2ecf20Sopenharmony_ci * alloc_idx_lebs - allocate empty LEBs to be used to commit.
6768c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
6778c2ecf20Sopenharmony_ci * @cnt: number of znodes to commit
6788c2ecf20Sopenharmony_ci *
6798c2ecf20Sopenharmony_ci * This function returns %-ENOSPC if it cannot allocate a sufficient number of
6808c2ecf20Sopenharmony_ci * empty LEBs.  %0 is returned on success, otherwise a negative error code
6818c2ecf20Sopenharmony_ci * is returned.
6828c2ecf20Sopenharmony_ci */
6838c2ecf20Sopenharmony_cistatic int alloc_idx_lebs(struct ubifs_info *c, int cnt)
6848c2ecf20Sopenharmony_ci{
6858c2ecf20Sopenharmony_ci	int i, leb_cnt, lnum;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	c->ileb_cnt = 0;
6888c2ecf20Sopenharmony_ci	c->ileb_nxt = 0;
6898c2ecf20Sopenharmony_ci	leb_cnt = get_leb_cnt(c, cnt);
6908c2ecf20Sopenharmony_ci	dbg_cmt("need about %d empty LEBS for TNC commit", leb_cnt);
6918c2ecf20Sopenharmony_ci	if (!leb_cnt)
6928c2ecf20Sopenharmony_ci		return 0;
6938c2ecf20Sopenharmony_ci	c->ilebs = kmalloc_array(leb_cnt, sizeof(int), GFP_NOFS);
6948c2ecf20Sopenharmony_ci	if (!c->ilebs)
6958c2ecf20Sopenharmony_ci		return -ENOMEM;
6968c2ecf20Sopenharmony_ci	for (i = 0; i < leb_cnt; i++) {
6978c2ecf20Sopenharmony_ci		lnum = ubifs_find_free_leb_for_idx(c);
6988c2ecf20Sopenharmony_ci		if (lnum < 0)
6998c2ecf20Sopenharmony_ci			return lnum;
7008c2ecf20Sopenharmony_ci		c->ilebs[c->ileb_cnt++] = lnum;
7018c2ecf20Sopenharmony_ci		dbg_cmt("LEB %d", lnum);
7028c2ecf20Sopenharmony_ci	}
7038c2ecf20Sopenharmony_ci	if (dbg_is_chk_index(c) && !(prandom_u32() & 7))
7048c2ecf20Sopenharmony_ci		return -ENOSPC;
7058c2ecf20Sopenharmony_ci	return 0;
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci/**
7098c2ecf20Sopenharmony_ci * free_unused_idx_lebs - free unused LEBs that were allocated for the commit.
7108c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
7118c2ecf20Sopenharmony_ci *
7128c2ecf20Sopenharmony_ci * It is possible that we allocate more empty LEBs for the commit than we need.
7138c2ecf20Sopenharmony_ci * This functions frees the surplus.
7148c2ecf20Sopenharmony_ci *
7158c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
7168c2ecf20Sopenharmony_ci */
7178c2ecf20Sopenharmony_cistatic int free_unused_idx_lebs(struct ubifs_info *c)
7188c2ecf20Sopenharmony_ci{
7198c2ecf20Sopenharmony_ci	int i, err = 0, lnum, er;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	for (i = c->ileb_nxt; i < c->ileb_cnt; i++) {
7228c2ecf20Sopenharmony_ci		lnum = c->ilebs[i];
7238c2ecf20Sopenharmony_ci		dbg_cmt("LEB %d", lnum);
7248c2ecf20Sopenharmony_ci		er = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0,
7258c2ecf20Sopenharmony_ci					 LPROPS_INDEX | LPROPS_TAKEN, 0);
7268c2ecf20Sopenharmony_ci		if (!err)
7278c2ecf20Sopenharmony_ci			err = er;
7288c2ecf20Sopenharmony_ci	}
7298c2ecf20Sopenharmony_ci	return err;
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci/**
7338c2ecf20Sopenharmony_ci * free_idx_lebs - free unused LEBs after commit end.
7348c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
7358c2ecf20Sopenharmony_ci *
7368c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure.
7378c2ecf20Sopenharmony_ci */
7388c2ecf20Sopenharmony_cistatic int free_idx_lebs(struct ubifs_info *c)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	int err;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	err = free_unused_idx_lebs(c);
7438c2ecf20Sopenharmony_ci	kfree(c->ilebs);
7448c2ecf20Sopenharmony_ci	c->ilebs = NULL;
7458c2ecf20Sopenharmony_ci	return err;
7468c2ecf20Sopenharmony_ci}
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci/**
7498c2ecf20Sopenharmony_ci * ubifs_tnc_start_commit - start TNC commit.
7508c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
7518c2ecf20Sopenharmony_ci * @zroot: new index root position is returned here
7528c2ecf20Sopenharmony_ci *
7538c2ecf20Sopenharmony_ci * This function prepares the list of indexing nodes to commit and lays out
7548c2ecf20Sopenharmony_ci * their positions on flash. If there is not enough free space it uses the
7558c2ecf20Sopenharmony_ci * in-gap commit method. Returns zero in case of success and a negative error
7568c2ecf20Sopenharmony_ci * code in case of failure.
7578c2ecf20Sopenharmony_ci */
7588c2ecf20Sopenharmony_ciint ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot)
7598c2ecf20Sopenharmony_ci{
7608c2ecf20Sopenharmony_ci	int err = 0, cnt;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	mutex_lock(&c->tnc_mutex);
7638c2ecf20Sopenharmony_ci	err = dbg_check_tnc(c, 1);
7648c2ecf20Sopenharmony_ci	if (err)
7658c2ecf20Sopenharmony_ci		goto out;
7668c2ecf20Sopenharmony_ci	cnt = get_znodes_to_commit(c);
7678c2ecf20Sopenharmony_ci	if (cnt != 0) {
7688c2ecf20Sopenharmony_ci		int no_space = 0;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci		err = alloc_idx_lebs(c, cnt);
7718c2ecf20Sopenharmony_ci		if (err == -ENOSPC)
7728c2ecf20Sopenharmony_ci			no_space = 1;
7738c2ecf20Sopenharmony_ci		else if (err)
7748c2ecf20Sopenharmony_ci			goto out_free;
7758c2ecf20Sopenharmony_ci		err = layout_commit(c, no_space, cnt);
7768c2ecf20Sopenharmony_ci		if (err)
7778c2ecf20Sopenharmony_ci			goto out_free;
7788c2ecf20Sopenharmony_ci		ubifs_assert(c, atomic_long_read(&c->dirty_zn_cnt) == 0);
7798c2ecf20Sopenharmony_ci		err = free_unused_idx_lebs(c);
7808c2ecf20Sopenharmony_ci		if (err)
7818c2ecf20Sopenharmony_ci			goto out;
7828c2ecf20Sopenharmony_ci	}
7838c2ecf20Sopenharmony_ci	destroy_old_idx(c);
7848c2ecf20Sopenharmony_ci	memcpy(zroot, &c->zroot, sizeof(struct ubifs_zbranch));
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	err = ubifs_save_dirty_idx_lnums(c);
7878c2ecf20Sopenharmony_ci	if (err)
7888c2ecf20Sopenharmony_ci		goto out;
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	spin_lock(&c->space_lock);
7918c2ecf20Sopenharmony_ci	/*
7928c2ecf20Sopenharmony_ci	 * Although we have not finished committing yet, update size of the
7938c2ecf20Sopenharmony_ci	 * committed index ('c->bi.old_idx_sz') and zero out the index growth
7948c2ecf20Sopenharmony_ci	 * budget. It is OK to do this now, because we've reserved all the
7958c2ecf20Sopenharmony_ci	 * space which is needed to commit the index, and it is save for the
7968c2ecf20Sopenharmony_ci	 * budgeting subsystem to assume the index is already committed,
7978c2ecf20Sopenharmony_ci	 * even though it is not.
7988c2ecf20Sopenharmony_ci	 */
7998c2ecf20Sopenharmony_ci	ubifs_assert(c, c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c));
8008c2ecf20Sopenharmony_ci	c->bi.old_idx_sz = c->calc_idx_sz;
8018c2ecf20Sopenharmony_ci	c->bi.uncommitted_idx = 0;
8028c2ecf20Sopenharmony_ci	c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c);
8038c2ecf20Sopenharmony_ci	spin_unlock(&c->space_lock);
8048c2ecf20Sopenharmony_ci	mutex_unlock(&c->tnc_mutex);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	dbg_cmt("number of index LEBs %d", c->lst.idx_lebs);
8078c2ecf20Sopenharmony_ci	dbg_cmt("size of index %llu", c->calc_idx_sz);
8088c2ecf20Sopenharmony_ci	return err;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ciout_free:
8118c2ecf20Sopenharmony_ci	free_idx_lebs(c);
8128c2ecf20Sopenharmony_ciout:
8138c2ecf20Sopenharmony_ci	mutex_unlock(&c->tnc_mutex);
8148c2ecf20Sopenharmony_ci	return err;
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci/**
8188c2ecf20Sopenharmony_ci * write_index - write index nodes.
8198c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
8208c2ecf20Sopenharmony_ci *
8218c2ecf20Sopenharmony_ci * This function writes the index nodes whose positions were laid out in the
8228c2ecf20Sopenharmony_ci * layout_in_empty_space function.
8238c2ecf20Sopenharmony_ci */
8248c2ecf20Sopenharmony_cistatic int write_index(struct ubifs_info *c)
8258c2ecf20Sopenharmony_ci{
8268c2ecf20Sopenharmony_ci	struct ubifs_idx_node *idx;
8278c2ecf20Sopenharmony_ci	struct ubifs_znode *znode, *cnext;
8288c2ecf20Sopenharmony_ci	int i, lnum, offs, len, next_len, buf_len, buf_offs, used;
8298c2ecf20Sopenharmony_ci	int avail, wlen, err, lnum_pos = 0, blen, nxt_offs;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	cnext = c->enext;
8328c2ecf20Sopenharmony_ci	if (!cnext)
8338c2ecf20Sopenharmony_ci		return 0;
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	/*
8368c2ecf20Sopenharmony_ci	 * Always write index nodes to the index head so that index nodes and
8378c2ecf20Sopenharmony_ci	 * other types of nodes are never mixed in the same erase block.
8388c2ecf20Sopenharmony_ci	 */
8398c2ecf20Sopenharmony_ci	lnum = c->ihead_lnum;
8408c2ecf20Sopenharmony_ci	buf_offs = c->ihead_offs;
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	/* Allocate commit buffer */
8438c2ecf20Sopenharmony_ci	buf_len = ALIGN(c->max_idx_node_sz, c->min_io_size);
8448c2ecf20Sopenharmony_ci	used = 0;
8458c2ecf20Sopenharmony_ci	avail = buf_len;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	/* Ensure there is enough room for first write */
8488c2ecf20Sopenharmony_ci	next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
8498c2ecf20Sopenharmony_ci	if (buf_offs + next_len > c->leb_size) {
8508c2ecf20Sopenharmony_ci		err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0, 0,
8518c2ecf20Sopenharmony_ci					  LPROPS_TAKEN);
8528c2ecf20Sopenharmony_ci		if (err)
8538c2ecf20Sopenharmony_ci			return err;
8548c2ecf20Sopenharmony_ci		lnum = -1;
8558c2ecf20Sopenharmony_ci	}
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	while (1) {
8588c2ecf20Sopenharmony_ci		u8 hash[UBIFS_HASH_ARR_SZ];
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci		cond_resched();
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci		znode = cnext;
8638c2ecf20Sopenharmony_ci		idx = c->cbuf + used;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci		/* Make index node */
8668c2ecf20Sopenharmony_ci		idx->ch.node_type = UBIFS_IDX_NODE;
8678c2ecf20Sopenharmony_ci		idx->child_cnt = cpu_to_le16(znode->child_cnt);
8688c2ecf20Sopenharmony_ci		idx->level = cpu_to_le16(znode->level);
8698c2ecf20Sopenharmony_ci		for (i = 0; i < znode->child_cnt; i++) {
8708c2ecf20Sopenharmony_ci			struct ubifs_branch *br = ubifs_idx_branch(c, idx, i);
8718c2ecf20Sopenharmony_ci			struct ubifs_zbranch *zbr = &znode->zbranch[i];
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ci			key_write_idx(c, &zbr->key, &br->key);
8748c2ecf20Sopenharmony_ci			br->lnum = cpu_to_le32(zbr->lnum);
8758c2ecf20Sopenharmony_ci			br->offs = cpu_to_le32(zbr->offs);
8768c2ecf20Sopenharmony_ci			br->len = cpu_to_le32(zbr->len);
8778c2ecf20Sopenharmony_ci			ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br));
8788c2ecf20Sopenharmony_ci			if (!zbr->lnum || !zbr->len) {
8798c2ecf20Sopenharmony_ci				ubifs_err(c, "bad ref in znode");
8808c2ecf20Sopenharmony_ci				ubifs_dump_znode(c, znode);
8818c2ecf20Sopenharmony_ci				if (zbr->znode)
8828c2ecf20Sopenharmony_ci					ubifs_dump_znode(c, zbr->znode);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci				return -EINVAL;
8858c2ecf20Sopenharmony_ci			}
8868c2ecf20Sopenharmony_ci		}
8878c2ecf20Sopenharmony_ci		len = ubifs_idx_node_sz(c, znode->child_cnt);
8888c2ecf20Sopenharmony_ci		ubifs_prepare_node(c, idx, len, 0);
8898c2ecf20Sopenharmony_ci		ubifs_node_calc_hash(c, idx, hash);
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci		mutex_lock(&c->tnc_mutex);
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci		if (znode->cparent)
8948c2ecf20Sopenharmony_ci			ubifs_copy_hash(c, hash,
8958c2ecf20Sopenharmony_ci					znode->cparent->zbranch[znode->ciip].hash);
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci		if (znode->parent) {
8988c2ecf20Sopenharmony_ci			if (!ubifs_zn_obsolete(znode))
8998c2ecf20Sopenharmony_ci				ubifs_copy_hash(c, hash,
9008c2ecf20Sopenharmony_ci					znode->parent->zbranch[znode->iip].hash);
9018c2ecf20Sopenharmony_ci		} else {
9028c2ecf20Sopenharmony_ci			ubifs_copy_hash(c, hash, c->zroot.hash);
9038c2ecf20Sopenharmony_ci		}
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci		mutex_unlock(&c->tnc_mutex);
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_ci		/* Determine the index node position */
9088c2ecf20Sopenharmony_ci		if (lnum == -1) {
9098c2ecf20Sopenharmony_ci			lnum = c->ilebs[lnum_pos++];
9108c2ecf20Sopenharmony_ci			buf_offs = 0;
9118c2ecf20Sopenharmony_ci			used = 0;
9128c2ecf20Sopenharmony_ci			avail = buf_len;
9138c2ecf20Sopenharmony_ci		}
9148c2ecf20Sopenharmony_ci		offs = buf_offs + used;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci		if (lnum != znode->lnum || offs != znode->offs ||
9178c2ecf20Sopenharmony_ci		    len != znode->len) {
9188c2ecf20Sopenharmony_ci			ubifs_err(c, "inconsistent znode posn");
9198c2ecf20Sopenharmony_ci			return -EINVAL;
9208c2ecf20Sopenharmony_ci		}
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci		/* Grab some stuff from znode while we still can */
9238c2ecf20Sopenharmony_ci		cnext = znode->cnext;
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci		ubifs_assert(c, ubifs_zn_dirty(znode));
9268c2ecf20Sopenharmony_ci		ubifs_assert(c, ubifs_zn_cow(znode));
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci		/*
9298c2ecf20Sopenharmony_ci		 * It is important that other threads should see %DIRTY_ZNODE
9308c2ecf20Sopenharmony_ci		 * flag cleared before %COW_ZNODE. Specifically, it matters in
9318c2ecf20Sopenharmony_ci		 * the 'dirty_cow_znode()' function. This is the reason for the
9328c2ecf20Sopenharmony_ci		 * first barrier. Also, we want the bit changes to be seen to
9338c2ecf20Sopenharmony_ci		 * other threads ASAP, to avoid unnecesarry copying, which is
9348c2ecf20Sopenharmony_ci		 * the reason for the second barrier.
9358c2ecf20Sopenharmony_ci		 */
9368c2ecf20Sopenharmony_ci		clear_bit(DIRTY_ZNODE, &znode->flags);
9378c2ecf20Sopenharmony_ci		smp_mb__before_atomic();
9388c2ecf20Sopenharmony_ci		clear_bit(COW_ZNODE, &znode->flags);
9398c2ecf20Sopenharmony_ci		smp_mb__after_atomic();
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci		/*
9428c2ecf20Sopenharmony_ci		 * We have marked the znode as clean but have not updated the
9438c2ecf20Sopenharmony_ci		 * @c->clean_zn_cnt counter. If this znode becomes dirty again
9448c2ecf20Sopenharmony_ci		 * before 'free_obsolete_znodes()' is called, then
9458c2ecf20Sopenharmony_ci		 * @c->clean_zn_cnt will be decremented before it gets
9468c2ecf20Sopenharmony_ci		 * incremented (resulting in 2 decrements for the same znode).
9478c2ecf20Sopenharmony_ci		 * This means that @c->clean_zn_cnt may become negative for a
9488c2ecf20Sopenharmony_ci		 * while.
9498c2ecf20Sopenharmony_ci		 *
9508c2ecf20Sopenharmony_ci		 * Q: why we cannot increment @c->clean_zn_cnt?
9518c2ecf20Sopenharmony_ci		 * A: because we do not have the @c->tnc_mutex locked, and the
9528c2ecf20Sopenharmony_ci		 *    following code would be racy and buggy:
9538c2ecf20Sopenharmony_ci		 *
9548c2ecf20Sopenharmony_ci		 *    if (!ubifs_zn_obsolete(znode)) {
9558c2ecf20Sopenharmony_ci		 *            atomic_long_inc(&c->clean_zn_cnt);
9568c2ecf20Sopenharmony_ci		 *            atomic_long_inc(&ubifs_clean_zn_cnt);
9578c2ecf20Sopenharmony_ci		 *    }
9588c2ecf20Sopenharmony_ci		 *
9598c2ecf20Sopenharmony_ci		 *    Thus, we just delay the @c->clean_zn_cnt update until we
9608c2ecf20Sopenharmony_ci		 *    have the mutex locked.
9618c2ecf20Sopenharmony_ci		 */
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci		/* Do not access znode from this point on */
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci		/* Update buffer positions */
9668c2ecf20Sopenharmony_ci		wlen = used + len;
9678c2ecf20Sopenharmony_ci		used += ALIGN(len, 8);
9688c2ecf20Sopenharmony_ci		avail -= ALIGN(len, 8);
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci		/*
9718c2ecf20Sopenharmony_ci		 * Calculate the next index node length to see if there is
9728c2ecf20Sopenharmony_ci		 * enough room for it
9738c2ecf20Sopenharmony_ci		 */
9748c2ecf20Sopenharmony_ci		if (cnext == c->cnext)
9758c2ecf20Sopenharmony_ci			next_len = 0;
9768c2ecf20Sopenharmony_ci		else
9778c2ecf20Sopenharmony_ci			next_len = ubifs_idx_node_sz(c, cnext->child_cnt);
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci		nxt_offs = buf_offs + used + next_len;
9808c2ecf20Sopenharmony_ci		if (next_len && nxt_offs <= c->leb_size) {
9818c2ecf20Sopenharmony_ci			if (avail > 0)
9828c2ecf20Sopenharmony_ci				continue;
9838c2ecf20Sopenharmony_ci			else
9848c2ecf20Sopenharmony_ci				blen = buf_len;
9858c2ecf20Sopenharmony_ci		} else {
9868c2ecf20Sopenharmony_ci			wlen = ALIGN(wlen, 8);
9878c2ecf20Sopenharmony_ci			blen = ALIGN(wlen, c->min_io_size);
9888c2ecf20Sopenharmony_ci			ubifs_pad(c, c->cbuf + wlen, blen - wlen);
9898c2ecf20Sopenharmony_ci		}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci		/* The buffer is full or there are no more znodes to do */
9928c2ecf20Sopenharmony_ci		err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen);
9938c2ecf20Sopenharmony_ci		if (err)
9948c2ecf20Sopenharmony_ci			return err;
9958c2ecf20Sopenharmony_ci		buf_offs += blen;
9968c2ecf20Sopenharmony_ci		if (next_len) {
9978c2ecf20Sopenharmony_ci			if (nxt_offs > c->leb_size) {
9988c2ecf20Sopenharmony_ci				err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0,
9998c2ecf20Sopenharmony_ci							  0, LPROPS_TAKEN);
10008c2ecf20Sopenharmony_ci				if (err)
10018c2ecf20Sopenharmony_ci					return err;
10028c2ecf20Sopenharmony_ci				lnum = -1;
10038c2ecf20Sopenharmony_ci			}
10048c2ecf20Sopenharmony_ci			used -= blen;
10058c2ecf20Sopenharmony_ci			if (used < 0)
10068c2ecf20Sopenharmony_ci				used = 0;
10078c2ecf20Sopenharmony_ci			avail = buf_len - used;
10088c2ecf20Sopenharmony_ci			memmove(c->cbuf, c->cbuf + blen, used);
10098c2ecf20Sopenharmony_ci			continue;
10108c2ecf20Sopenharmony_ci		}
10118c2ecf20Sopenharmony_ci		break;
10128c2ecf20Sopenharmony_ci	}
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if (lnum != c->dbg->new_ihead_lnum ||
10158c2ecf20Sopenharmony_ci	    buf_offs != c->dbg->new_ihead_offs) {
10168c2ecf20Sopenharmony_ci		ubifs_err(c, "inconsistent ihead");
10178c2ecf20Sopenharmony_ci		return -EINVAL;
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	c->ihead_lnum = lnum;
10218c2ecf20Sopenharmony_ci	c->ihead_offs = buf_offs;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci	return 0;
10248c2ecf20Sopenharmony_ci}
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci/**
10278c2ecf20Sopenharmony_ci * free_obsolete_znodes - free obsolete znodes.
10288c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
10298c2ecf20Sopenharmony_ci *
10308c2ecf20Sopenharmony_ci * At the end of commit end, obsolete znodes are freed.
10318c2ecf20Sopenharmony_ci */
10328c2ecf20Sopenharmony_cistatic void free_obsolete_znodes(struct ubifs_info *c)
10338c2ecf20Sopenharmony_ci{
10348c2ecf20Sopenharmony_ci	struct ubifs_znode *znode, *cnext;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	cnext = c->cnext;
10378c2ecf20Sopenharmony_ci	do {
10388c2ecf20Sopenharmony_ci		znode = cnext;
10398c2ecf20Sopenharmony_ci		cnext = znode->cnext;
10408c2ecf20Sopenharmony_ci		if (ubifs_zn_obsolete(znode))
10418c2ecf20Sopenharmony_ci			kfree(znode);
10428c2ecf20Sopenharmony_ci		else {
10438c2ecf20Sopenharmony_ci			znode->cnext = NULL;
10448c2ecf20Sopenharmony_ci			atomic_long_inc(&c->clean_zn_cnt);
10458c2ecf20Sopenharmony_ci			atomic_long_inc(&ubifs_clean_zn_cnt);
10468c2ecf20Sopenharmony_ci		}
10478c2ecf20Sopenharmony_ci	} while (cnext != c->cnext);
10488c2ecf20Sopenharmony_ci}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci/**
10518c2ecf20Sopenharmony_ci * return_gap_lebs - return LEBs used by the in-gap commit method.
10528c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
10538c2ecf20Sopenharmony_ci *
10548c2ecf20Sopenharmony_ci * This function clears the "taken" flag for the LEBs which were used by the
10558c2ecf20Sopenharmony_ci * "commit in-the-gaps" method.
10568c2ecf20Sopenharmony_ci */
10578c2ecf20Sopenharmony_cistatic int return_gap_lebs(struct ubifs_info *c)
10588c2ecf20Sopenharmony_ci{
10598c2ecf20Sopenharmony_ci	int *p, err;
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_ci	if (!c->gap_lebs)
10628c2ecf20Sopenharmony_ci		return 0;
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	dbg_cmt("");
10658c2ecf20Sopenharmony_ci	for (p = c->gap_lebs; *p != -1; p++) {
10668c2ecf20Sopenharmony_ci		err = ubifs_change_one_lp(c, *p, LPROPS_NC, LPROPS_NC, 0,
10678c2ecf20Sopenharmony_ci					  LPROPS_TAKEN, 0);
10688c2ecf20Sopenharmony_ci		if (err)
10698c2ecf20Sopenharmony_ci			return err;
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	kfree(c->gap_lebs);
10738c2ecf20Sopenharmony_ci	c->gap_lebs = NULL;
10748c2ecf20Sopenharmony_ci	return 0;
10758c2ecf20Sopenharmony_ci}
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci/**
10788c2ecf20Sopenharmony_ci * ubifs_tnc_end_commit - update the TNC for commit end.
10798c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object
10808c2ecf20Sopenharmony_ci *
10818c2ecf20Sopenharmony_ci * Write the dirty znodes.
10828c2ecf20Sopenharmony_ci */
10838c2ecf20Sopenharmony_ciint ubifs_tnc_end_commit(struct ubifs_info *c)
10848c2ecf20Sopenharmony_ci{
10858c2ecf20Sopenharmony_ci	int err;
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	if (!c->cnext)
10888c2ecf20Sopenharmony_ci		return 0;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	err = return_gap_lebs(c);
10918c2ecf20Sopenharmony_ci	if (err)
10928c2ecf20Sopenharmony_ci		return err;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	err = write_index(c);
10958c2ecf20Sopenharmony_ci	if (err)
10968c2ecf20Sopenharmony_ci		return err;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	mutex_lock(&c->tnc_mutex);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	dbg_cmt("TNC height is %d", c->zroot.znode->level + 1);
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	free_obsolete_znodes(c);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	c->cnext = NULL;
11058c2ecf20Sopenharmony_ci	kfree(c->ilebs);
11068c2ecf20Sopenharmony_ci	c->ilebs = NULL;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	mutex_unlock(&c->tnc_mutex);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	return 0;
11118c2ecf20Sopenharmony_ci}
1112