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/* This file implements TNC functions for committing */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/random.h> 1462306a36Sopenharmony_ci#include "ubifs.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/** 1762306a36Sopenharmony_ci * make_idx_node - make an index node for fill-the-gaps method of TNC commit. 1862306a36Sopenharmony_ci * @c: UBIFS file-system description object 1962306a36Sopenharmony_ci * @idx: buffer in which to place new index node 2062306a36Sopenharmony_ci * @znode: znode from which to make new index node 2162306a36Sopenharmony_ci * @lnum: LEB number where new index node will be written 2262306a36Sopenharmony_ci * @offs: offset where new index node will be written 2362306a36Sopenharmony_ci * @len: length of new index node 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_cistatic int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, 2662306a36Sopenharmony_ci struct ubifs_znode *znode, int lnum, int offs, int len) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct ubifs_znode *zp; 2962306a36Sopenharmony_ci u8 hash[UBIFS_HASH_ARR_SZ]; 3062306a36Sopenharmony_ci int i, err; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci /* Make index node */ 3362306a36Sopenharmony_ci idx->ch.node_type = UBIFS_IDX_NODE; 3462306a36Sopenharmony_ci idx->child_cnt = cpu_to_le16(znode->child_cnt); 3562306a36Sopenharmony_ci idx->level = cpu_to_le16(znode->level); 3662306a36Sopenharmony_ci for (i = 0; i < znode->child_cnt; i++) { 3762306a36Sopenharmony_ci struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); 3862306a36Sopenharmony_ci struct ubifs_zbranch *zbr = &znode->zbranch[i]; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci key_write_idx(c, &zbr->key, &br->key); 4162306a36Sopenharmony_ci br->lnum = cpu_to_le32(zbr->lnum); 4262306a36Sopenharmony_ci br->offs = cpu_to_le32(zbr->offs); 4362306a36Sopenharmony_ci br->len = cpu_to_le32(zbr->len); 4462306a36Sopenharmony_ci ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br)); 4562306a36Sopenharmony_ci if (!zbr->lnum || !zbr->len) { 4662306a36Sopenharmony_ci ubifs_err(c, "bad ref in znode"); 4762306a36Sopenharmony_ci ubifs_dump_znode(c, znode); 4862306a36Sopenharmony_ci if (zbr->znode) 4962306a36Sopenharmony_ci ubifs_dump_znode(c, zbr->znode); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return -EINVAL; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci ubifs_prepare_node(c, idx, len, 0); 5562306a36Sopenharmony_ci ubifs_node_calc_hash(c, idx, hash); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci znode->lnum = lnum; 5862306a36Sopenharmony_ci znode->offs = offs; 5962306a36Sopenharmony_ci znode->len = len; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci err = insert_old_idx_znode(c, znode); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci /* Update the parent */ 6462306a36Sopenharmony_ci zp = znode->parent; 6562306a36Sopenharmony_ci if (zp) { 6662306a36Sopenharmony_ci struct ubifs_zbranch *zbr; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci zbr = &zp->zbranch[znode->iip]; 6962306a36Sopenharmony_ci zbr->lnum = lnum; 7062306a36Sopenharmony_ci zbr->offs = offs; 7162306a36Sopenharmony_ci zbr->len = len; 7262306a36Sopenharmony_ci ubifs_copy_hash(c, hash, zbr->hash); 7362306a36Sopenharmony_ci } else { 7462306a36Sopenharmony_ci c->zroot.lnum = lnum; 7562306a36Sopenharmony_ci c->zroot.offs = offs; 7662306a36Sopenharmony_ci c->zroot.len = len; 7762306a36Sopenharmony_ci ubifs_copy_hash(c, hash, c->zroot.hash); 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci c->calc_idx_sz += ALIGN(len, 8); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci atomic_long_dec(&c->dirty_zn_cnt); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci ubifs_assert(c, ubifs_zn_dirty(znode)); 8462306a36Sopenharmony_ci ubifs_assert(c, ubifs_zn_cow(znode)); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * Note, unlike 'write_index()' we do not add memory barriers here 8862306a36Sopenharmony_ci * because this function is called with @c->tnc_mutex locked. 8962306a36Sopenharmony_ci */ 9062306a36Sopenharmony_ci __clear_bit(DIRTY_ZNODE, &znode->flags); 9162306a36Sopenharmony_ci __clear_bit(COW_ZNODE, &znode->flags); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci return err; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/** 9762306a36Sopenharmony_ci * fill_gap - make index nodes in gaps in dirty index LEBs. 9862306a36Sopenharmony_ci * @c: UBIFS file-system description object 9962306a36Sopenharmony_ci * @lnum: LEB number that gap appears in 10062306a36Sopenharmony_ci * @gap_start: offset of start of gap 10162306a36Sopenharmony_ci * @gap_end: offset of end of gap 10262306a36Sopenharmony_ci * @dirt: adds dirty space to this 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * This function returns the number of index nodes written into the gap. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cistatic int fill_gap(struct ubifs_info *c, int lnum, int gap_start, int gap_end, 10762306a36Sopenharmony_ci int *dirt) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci int len, gap_remains, gap_pos, written, pad_len; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ubifs_assert(c, (gap_start & 7) == 0); 11262306a36Sopenharmony_ci ubifs_assert(c, (gap_end & 7) == 0); 11362306a36Sopenharmony_ci ubifs_assert(c, gap_end >= gap_start); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci gap_remains = gap_end - gap_start; 11662306a36Sopenharmony_ci if (!gap_remains) 11762306a36Sopenharmony_ci return 0; 11862306a36Sopenharmony_ci gap_pos = gap_start; 11962306a36Sopenharmony_ci written = 0; 12062306a36Sopenharmony_ci while (c->enext) { 12162306a36Sopenharmony_ci len = ubifs_idx_node_sz(c, c->enext->child_cnt); 12262306a36Sopenharmony_ci if (len < gap_remains) { 12362306a36Sopenharmony_ci struct ubifs_znode *znode = c->enext; 12462306a36Sopenharmony_ci const int alen = ALIGN(len, 8); 12562306a36Sopenharmony_ci int err; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci ubifs_assert(c, alen <= gap_remains); 12862306a36Sopenharmony_ci err = make_idx_node(c, c->ileb_buf + gap_pos, znode, 12962306a36Sopenharmony_ci lnum, gap_pos, len); 13062306a36Sopenharmony_ci if (err) 13162306a36Sopenharmony_ci return err; 13262306a36Sopenharmony_ci gap_remains -= alen; 13362306a36Sopenharmony_ci gap_pos += alen; 13462306a36Sopenharmony_ci c->enext = znode->cnext; 13562306a36Sopenharmony_ci if (c->enext == c->cnext) 13662306a36Sopenharmony_ci c->enext = NULL; 13762306a36Sopenharmony_ci written += 1; 13862306a36Sopenharmony_ci } else 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci } 14162306a36Sopenharmony_ci if (gap_end == c->leb_size) { 14262306a36Sopenharmony_ci c->ileb_len = ALIGN(gap_pos, c->min_io_size); 14362306a36Sopenharmony_ci /* Pad to end of min_io_size */ 14462306a36Sopenharmony_ci pad_len = c->ileb_len - gap_pos; 14562306a36Sopenharmony_ci } else 14662306a36Sopenharmony_ci /* Pad to end of gap */ 14762306a36Sopenharmony_ci pad_len = gap_remains; 14862306a36Sopenharmony_ci dbg_gc("LEB %d:%d to %d len %d nodes written %d wasted bytes %d", 14962306a36Sopenharmony_ci lnum, gap_start, gap_end, gap_end - gap_start, written, pad_len); 15062306a36Sopenharmony_ci ubifs_pad(c, c->ileb_buf + gap_pos, pad_len); 15162306a36Sopenharmony_ci *dirt += pad_len; 15262306a36Sopenharmony_ci return written; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/** 15662306a36Sopenharmony_ci * find_old_idx - find an index node obsoleted since the last commit start. 15762306a36Sopenharmony_ci * @c: UBIFS file-system description object 15862306a36Sopenharmony_ci * @lnum: LEB number of obsoleted index node 15962306a36Sopenharmony_ci * @offs: offset of obsoleted index node 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * Returns %1 if found and %0 otherwise. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cistatic int find_old_idx(struct ubifs_info *c, int lnum, int offs) 16462306a36Sopenharmony_ci{ 16562306a36Sopenharmony_ci struct ubifs_old_idx *o; 16662306a36Sopenharmony_ci struct rb_node *p; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci p = c->old_idx.rb_node; 16962306a36Sopenharmony_ci while (p) { 17062306a36Sopenharmony_ci o = rb_entry(p, struct ubifs_old_idx, rb); 17162306a36Sopenharmony_ci if (lnum < o->lnum) 17262306a36Sopenharmony_ci p = p->rb_left; 17362306a36Sopenharmony_ci else if (lnum > o->lnum) 17462306a36Sopenharmony_ci p = p->rb_right; 17562306a36Sopenharmony_ci else if (offs < o->offs) 17662306a36Sopenharmony_ci p = p->rb_left; 17762306a36Sopenharmony_ci else if (offs > o->offs) 17862306a36Sopenharmony_ci p = p->rb_right; 17962306a36Sopenharmony_ci else 18062306a36Sopenharmony_ci return 1; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci/** 18662306a36Sopenharmony_ci * is_idx_node_in_use - determine if an index node can be overwritten. 18762306a36Sopenharmony_ci * @c: UBIFS file-system description object 18862306a36Sopenharmony_ci * @key: key of index node 18962306a36Sopenharmony_ci * @level: index node level 19062306a36Sopenharmony_ci * @lnum: LEB number of index node 19162306a36Sopenharmony_ci * @offs: offset of index node 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * If @key / @lnum / @offs identify an index node that was not part of the old 19462306a36Sopenharmony_ci * index, then this function returns %0 (obsolete). Else if the index node was 19562306a36Sopenharmony_ci * part of the old index but is now dirty %1 is returned, else if it is clean %2 19662306a36Sopenharmony_ci * is returned. A negative error code is returned on failure. 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_cistatic int is_idx_node_in_use(struct ubifs_info *c, union ubifs_key *key, 19962306a36Sopenharmony_ci int level, int lnum, int offs) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci int ret; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci ret = is_idx_node_in_tnc(c, key, level, lnum, offs); 20462306a36Sopenharmony_ci if (ret < 0) 20562306a36Sopenharmony_ci return ret; /* Error code */ 20662306a36Sopenharmony_ci if (ret == 0) 20762306a36Sopenharmony_ci if (find_old_idx(c, lnum, offs)) 20862306a36Sopenharmony_ci return 1; 20962306a36Sopenharmony_ci return ret; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/** 21362306a36Sopenharmony_ci * layout_leb_in_gaps - layout index nodes using in-the-gaps method. 21462306a36Sopenharmony_ci * @c: UBIFS file-system description object 21562306a36Sopenharmony_ci * @p: return LEB number in @c->gap_lebs[p] 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * This function lays out new index nodes for dirty znodes using in-the-gaps 21862306a36Sopenharmony_ci * method of TNC commit. 21962306a36Sopenharmony_ci * This function merely puts the next znode into the next gap, making no attempt 22062306a36Sopenharmony_ci * to try to maximise the number of znodes that fit. 22162306a36Sopenharmony_ci * This function returns the number of index nodes written into the gaps, or a 22262306a36Sopenharmony_ci * negative error code on failure. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cistatic int layout_leb_in_gaps(struct ubifs_info *c, int p) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct ubifs_scan_leb *sleb; 22762306a36Sopenharmony_ci struct ubifs_scan_node *snod; 22862306a36Sopenharmony_ci int lnum, dirt = 0, gap_start, gap_end, err, written, tot_written; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci tot_written = 0; 23162306a36Sopenharmony_ci /* Get an index LEB with lots of obsolete index nodes */ 23262306a36Sopenharmony_ci lnum = ubifs_find_dirty_idx_leb(c); 23362306a36Sopenharmony_ci if (lnum < 0) 23462306a36Sopenharmony_ci /* 23562306a36Sopenharmony_ci * There also may be dirt in the index head that could be 23662306a36Sopenharmony_ci * filled, however we do not check there at present. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci return lnum; /* Error code */ 23962306a36Sopenharmony_ci c->gap_lebs[p] = lnum; 24062306a36Sopenharmony_ci dbg_gc("LEB %d", lnum); 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * Scan the index LEB. We use the generic scan for this even though 24362306a36Sopenharmony_ci * it is more comprehensive and less efficient than is needed for this 24462306a36Sopenharmony_ci * purpose. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci sleb = ubifs_scan(c, lnum, 0, c->ileb_buf, 0); 24762306a36Sopenharmony_ci c->ileb_len = 0; 24862306a36Sopenharmony_ci if (IS_ERR(sleb)) 24962306a36Sopenharmony_ci return PTR_ERR(sleb); 25062306a36Sopenharmony_ci gap_start = 0; 25162306a36Sopenharmony_ci list_for_each_entry(snod, &sleb->nodes, list) { 25262306a36Sopenharmony_ci struct ubifs_idx_node *idx; 25362306a36Sopenharmony_ci int in_use, level; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci ubifs_assert(c, snod->type == UBIFS_IDX_NODE); 25662306a36Sopenharmony_ci idx = snod->node; 25762306a36Sopenharmony_ci key_read(c, ubifs_idx_key(c, idx), &snod->key); 25862306a36Sopenharmony_ci level = le16_to_cpu(idx->level); 25962306a36Sopenharmony_ci /* Determine if the index node is in use (not obsolete) */ 26062306a36Sopenharmony_ci in_use = is_idx_node_in_use(c, &snod->key, level, lnum, 26162306a36Sopenharmony_ci snod->offs); 26262306a36Sopenharmony_ci if (in_use < 0) { 26362306a36Sopenharmony_ci ubifs_scan_destroy(sleb); 26462306a36Sopenharmony_ci return in_use; /* Error code */ 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci if (in_use) { 26762306a36Sopenharmony_ci if (in_use == 1) 26862306a36Sopenharmony_ci dirt += ALIGN(snod->len, 8); 26962306a36Sopenharmony_ci /* 27062306a36Sopenharmony_ci * The obsolete index nodes form gaps that can be 27162306a36Sopenharmony_ci * overwritten. This gap has ended because we have 27262306a36Sopenharmony_ci * found an index node that is still in use 27362306a36Sopenharmony_ci * i.e. not obsolete 27462306a36Sopenharmony_ci */ 27562306a36Sopenharmony_ci gap_end = snod->offs; 27662306a36Sopenharmony_ci /* Try to fill gap */ 27762306a36Sopenharmony_ci written = fill_gap(c, lnum, gap_start, gap_end, &dirt); 27862306a36Sopenharmony_ci if (written < 0) { 27962306a36Sopenharmony_ci ubifs_scan_destroy(sleb); 28062306a36Sopenharmony_ci return written; /* Error code */ 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci tot_written += written; 28362306a36Sopenharmony_ci gap_start = ALIGN(snod->offs + snod->len, 8); 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci ubifs_scan_destroy(sleb); 28762306a36Sopenharmony_ci c->ileb_len = c->leb_size; 28862306a36Sopenharmony_ci gap_end = c->leb_size; 28962306a36Sopenharmony_ci /* Try to fill gap */ 29062306a36Sopenharmony_ci written = fill_gap(c, lnum, gap_start, gap_end, &dirt); 29162306a36Sopenharmony_ci if (written < 0) 29262306a36Sopenharmony_ci return written; /* Error code */ 29362306a36Sopenharmony_ci tot_written += written; 29462306a36Sopenharmony_ci if (tot_written == 0) { 29562306a36Sopenharmony_ci struct ubifs_lprops lp; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written); 29862306a36Sopenharmony_ci err = ubifs_read_one_lp(c, lnum, &lp); 29962306a36Sopenharmony_ci if (err) 30062306a36Sopenharmony_ci return err; 30162306a36Sopenharmony_ci if (lp.free == c->leb_size) { 30262306a36Sopenharmony_ci /* 30362306a36Sopenharmony_ci * We must have snatched this LEB from the idx_gc list 30462306a36Sopenharmony_ci * so we need to correct the free and dirty space. 30562306a36Sopenharmony_ci */ 30662306a36Sopenharmony_ci err = ubifs_change_one_lp(c, lnum, 30762306a36Sopenharmony_ci c->leb_size - c->ileb_len, 30862306a36Sopenharmony_ci dirt, 0, 0, 0); 30962306a36Sopenharmony_ci if (err) 31062306a36Sopenharmony_ci return err; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci err = ubifs_change_one_lp(c, lnum, c->leb_size - c->ileb_len, dirt, 31562306a36Sopenharmony_ci 0, 0, 0); 31662306a36Sopenharmony_ci if (err) 31762306a36Sopenharmony_ci return err; 31862306a36Sopenharmony_ci err = ubifs_leb_change(c, lnum, c->ileb_buf, c->ileb_len); 31962306a36Sopenharmony_ci if (err) 32062306a36Sopenharmony_ci return err; 32162306a36Sopenharmony_ci dbg_gc("LEB %d wrote %d index nodes", lnum, tot_written); 32262306a36Sopenharmony_ci return tot_written; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/** 32662306a36Sopenharmony_ci * get_leb_cnt - calculate the number of empty LEBs needed to commit. 32762306a36Sopenharmony_ci * @c: UBIFS file-system description object 32862306a36Sopenharmony_ci * @cnt: number of znodes to commit 32962306a36Sopenharmony_ci * 33062306a36Sopenharmony_ci * This function returns the number of empty LEBs needed to commit @cnt znodes 33162306a36Sopenharmony_ci * to the current index head. The number is not exact and may be more than 33262306a36Sopenharmony_ci * needed. 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_cistatic int get_leb_cnt(struct ubifs_info *c, int cnt) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci int d; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci /* Assume maximum index node size (i.e. overestimate space needed) */ 33962306a36Sopenharmony_ci cnt -= (c->leb_size - c->ihead_offs) / c->max_idx_node_sz; 34062306a36Sopenharmony_ci if (cnt < 0) 34162306a36Sopenharmony_ci cnt = 0; 34262306a36Sopenharmony_ci d = c->leb_size / c->max_idx_node_sz; 34362306a36Sopenharmony_ci return DIV_ROUND_UP(cnt, d); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/** 34762306a36Sopenharmony_ci * layout_in_gaps - in-the-gaps method of committing TNC. 34862306a36Sopenharmony_ci * @c: UBIFS file-system description object 34962306a36Sopenharmony_ci * @cnt: number of dirty znodes to commit. 35062306a36Sopenharmony_ci * 35162306a36Sopenharmony_ci * This function lays out new index nodes for dirty znodes using in-the-gaps 35262306a36Sopenharmony_ci * method of TNC commit. 35362306a36Sopenharmony_ci * 35462306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 35562306a36Sopenharmony_ci */ 35662306a36Sopenharmony_cistatic int layout_in_gaps(struct ubifs_info *c, int cnt) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci int err, leb_needed_cnt, written, p = 0, old_idx_lebs, *gap_lebs; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci dbg_gc("%d znodes to write", cnt); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci c->gap_lebs = kmalloc_array(c->lst.idx_lebs + 1, sizeof(int), 36362306a36Sopenharmony_ci GFP_NOFS); 36462306a36Sopenharmony_ci if (!c->gap_lebs) 36562306a36Sopenharmony_ci return -ENOMEM; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci old_idx_lebs = c->lst.idx_lebs; 36862306a36Sopenharmony_ci do { 36962306a36Sopenharmony_ci ubifs_assert(c, p < c->lst.idx_lebs); 37062306a36Sopenharmony_ci written = layout_leb_in_gaps(c, p); 37162306a36Sopenharmony_ci if (written < 0) { 37262306a36Sopenharmony_ci err = written; 37362306a36Sopenharmony_ci if (err != -ENOSPC) { 37462306a36Sopenharmony_ci kfree(c->gap_lebs); 37562306a36Sopenharmony_ci c->gap_lebs = NULL; 37662306a36Sopenharmony_ci return err; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci if (!dbg_is_chk_index(c)) { 37962306a36Sopenharmony_ci /* 38062306a36Sopenharmony_ci * Do not print scary warnings if the debugging 38162306a36Sopenharmony_ci * option which forces in-the-gaps is enabled. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ci ubifs_warn(c, "out of space"); 38462306a36Sopenharmony_ci ubifs_dump_budg(c, &c->bi); 38562306a36Sopenharmony_ci ubifs_dump_lprops(c); 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci /* Try to commit anyway */ 38862306a36Sopenharmony_ci break; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci p++; 39162306a36Sopenharmony_ci cnt -= written; 39262306a36Sopenharmony_ci leb_needed_cnt = get_leb_cnt(c, cnt); 39362306a36Sopenharmony_ci dbg_gc("%d znodes remaining, need %d LEBs, have %d", cnt, 39462306a36Sopenharmony_ci leb_needed_cnt, c->ileb_cnt); 39562306a36Sopenharmony_ci /* 39662306a36Sopenharmony_ci * Dynamically change the size of @c->gap_lebs to prevent 39762306a36Sopenharmony_ci * oob, because @c->lst.idx_lebs could be increased by 39862306a36Sopenharmony_ci * function @get_idx_gc_leb (called by layout_leb_in_gaps-> 39962306a36Sopenharmony_ci * ubifs_find_dirty_idx_leb) during loop. Only enlarge 40062306a36Sopenharmony_ci * @c->gap_lebs when needed. 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci */ 40362306a36Sopenharmony_ci if (leb_needed_cnt > c->ileb_cnt && p >= old_idx_lebs && 40462306a36Sopenharmony_ci old_idx_lebs < c->lst.idx_lebs) { 40562306a36Sopenharmony_ci old_idx_lebs = c->lst.idx_lebs; 40662306a36Sopenharmony_ci gap_lebs = krealloc(c->gap_lebs, sizeof(int) * 40762306a36Sopenharmony_ci (old_idx_lebs + 1), GFP_NOFS); 40862306a36Sopenharmony_ci if (!gap_lebs) { 40962306a36Sopenharmony_ci kfree(c->gap_lebs); 41062306a36Sopenharmony_ci c->gap_lebs = NULL; 41162306a36Sopenharmony_ci return -ENOMEM; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci c->gap_lebs = gap_lebs; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci } while (leb_needed_cnt > c->ileb_cnt); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci c->gap_lebs[p] = -1; 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci/** 42262306a36Sopenharmony_ci * layout_in_empty_space - layout index nodes in empty space. 42362306a36Sopenharmony_ci * @c: UBIFS file-system description object 42462306a36Sopenharmony_ci * 42562306a36Sopenharmony_ci * This function lays out new index nodes for dirty znodes using empty LEBs. 42662306a36Sopenharmony_ci * 42762306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_cistatic int layout_in_empty_space(struct ubifs_info *c) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci struct ubifs_znode *znode, *cnext, *zp; 43262306a36Sopenharmony_ci int lnum, offs, len, next_len, buf_len, buf_offs, used, avail; 43362306a36Sopenharmony_ci int wlen, blen, err; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci cnext = c->enext; 43662306a36Sopenharmony_ci if (!cnext) 43762306a36Sopenharmony_ci return 0; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci lnum = c->ihead_lnum; 44062306a36Sopenharmony_ci buf_offs = c->ihead_offs; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci buf_len = ubifs_idx_node_sz(c, c->fanout); 44362306a36Sopenharmony_ci buf_len = ALIGN(buf_len, c->min_io_size); 44462306a36Sopenharmony_ci used = 0; 44562306a36Sopenharmony_ci avail = buf_len; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci /* Ensure there is enough room for first write */ 44862306a36Sopenharmony_ci next_len = ubifs_idx_node_sz(c, cnext->child_cnt); 44962306a36Sopenharmony_ci if (buf_offs + next_len > c->leb_size) 45062306a36Sopenharmony_ci lnum = -1; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci while (1) { 45362306a36Sopenharmony_ci znode = cnext; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci len = ubifs_idx_node_sz(c, znode->child_cnt); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* Determine the index node position */ 45862306a36Sopenharmony_ci if (lnum == -1) { 45962306a36Sopenharmony_ci if (c->ileb_nxt >= c->ileb_cnt) { 46062306a36Sopenharmony_ci ubifs_err(c, "out of space"); 46162306a36Sopenharmony_ci return -ENOSPC; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci lnum = c->ilebs[c->ileb_nxt++]; 46462306a36Sopenharmony_ci buf_offs = 0; 46562306a36Sopenharmony_ci used = 0; 46662306a36Sopenharmony_ci avail = buf_len; 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci offs = buf_offs + used; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci znode->lnum = lnum; 47262306a36Sopenharmony_ci znode->offs = offs; 47362306a36Sopenharmony_ci znode->len = len; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci /* Update the parent */ 47662306a36Sopenharmony_ci zp = znode->parent; 47762306a36Sopenharmony_ci if (zp) { 47862306a36Sopenharmony_ci struct ubifs_zbranch *zbr; 47962306a36Sopenharmony_ci int i; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci i = znode->iip; 48262306a36Sopenharmony_ci zbr = &zp->zbranch[i]; 48362306a36Sopenharmony_ci zbr->lnum = lnum; 48462306a36Sopenharmony_ci zbr->offs = offs; 48562306a36Sopenharmony_ci zbr->len = len; 48662306a36Sopenharmony_ci } else { 48762306a36Sopenharmony_ci c->zroot.lnum = lnum; 48862306a36Sopenharmony_ci c->zroot.offs = offs; 48962306a36Sopenharmony_ci c->zroot.len = len; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci c->calc_idx_sz += ALIGN(len, 8); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* 49462306a36Sopenharmony_ci * Once lprops is updated, we can decrease the dirty znode count 49562306a36Sopenharmony_ci * but it is easier to just do it here. 49662306a36Sopenharmony_ci */ 49762306a36Sopenharmony_ci atomic_long_dec(&c->dirty_zn_cnt); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* 50062306a36Sopenharmony_ci * Calculate the next index node length to see if there is 50162306a36Sopenharmony_ci * enough room for it 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_ci cnext = znode->cnext; 50462306a36Sopenharmony_ci if (cnext == c->cnext) 50562306a36Sopenharmony_ci next_len = 0; 50662306a36Sopenharmony_ci else 50762306a36Sopenharmony_ci next_len = ubifs_idx_node_sz(c, cnext->child_cnt); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* Update buffer positions */ 51062306a36Sopenharmony_ci wlen = used + len; 51162306a36Sopenharmony_ci used += ALIGN(len, 8); 51262306a36Sopenharmony_ci avail -= ALIGN(len, 8); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (next_len != 0 && 51562306a36Sopenharmony_ci buf_offs + used + next_len <= c->leb_size && 51662306a36Sopenharmony_ci avail > 0) 51762306a36Sopenharmony_ci continue; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (avail <= 0 && next_len && 52062306a36Sopenharmony_ci buf_offs + used + next_len <= c->leb_size) 52162306a36Sopenharmony_ci blen = buf_len; 52262306a36Sopenharmony_ci else 52362306a36Sopenharmony_ci blen = ALIGN(wlen, c->min_io_size); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* The buffer is full or there are no more znodes to do */ 52662306a36Sopenharmony_ci buf_offs += blen; 52762306a36Sopenharmony_ci if (next_len) { 52862306a36Sopenharmony_ci if (buf_offs + next_len > c->leb_size) { 52962306a36Sopenharmony_ci err = ubifs_update_one_lp(c, lnum, 53062306a36Sopenharmony_ci c->leb_size - buf_offs, blen - used, 53162306a36Sopenharmony_ci 0, 0); 53262306a36Sopenharmony_ci if (err) 53362306a36Sopenharmony_ci return err; 53462306a36Sopenharmony_ci lnum = -1; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci used -= blen; 53762306a36Sopenharmony_ci if (used < 0) 53862306a36Sopenharmony_ci used = 0; 53962306a36Sopenharmony_ci avail = buf_len - used; 54062306a36Sopenharmony_ci continue; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci err = ubifs_update_one_lp(c, lnum, c->leb_size - buf_offs, 54362306a36Sopenharmony_ci blen - used, 0, 0); 54462306a36Sopenharmony_ci if (err) 54562306a36Sopenharmony_ci return err; 54662306a36Sopenharmony_ci break; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci c->dbg->new_ihead_lnum = lnum; 55062306a36Sopenharmony_ci c->dbg->new_ihead_offs = buf_offs; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return 0; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci/** 55662306a36Sopenharmony_ci * layout_commit - determine positions of index nodes to commit. 55762306a36Sopenharmony_ci * @c: UBIFS file-system description object 55862306a36Sopenharmony_ci * @no_space: indicates that insufficient empty LEBs were allocated 55962306a36Sopenharmony_ci * @cnt: number of znodes to commit 56062306a36Sopenharmony_ci * 56162306a36Sopenharmony_ci * Calculate and update the positions of index nodes to commit. If there were 56262306a36Sopenharmony_ci * an insufficient number of empty LEBs allocated, then index nodes are placed 56362306a36Sopenharmony_ci * into the gaps created by obsolete index nodes in non-empty index LEBs. For 56462306a36Sopenharmony_ci * this purpose, an obsolete index node is one that was not in the index as at 56562306a36Sopenharmony_ci * the end of the last commit. To write "in-the-gaps" requires that those index 56662306a36Sopenharmony_ci * LEBs are updated atomically in-place. 56762306a36Sopenharmony_ci */ 56862306a36Sopenharmony_cistatic int layout_commit(struct ubifs_info *c, int no_space, int cnt) 56962306a36Sopenharmony_ci{ 57062306a36Sopenharmony_ci int err; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (no_space) { 57362306a36Sopenharmony_ci err = layout_in_gaps(c, cnt); 57462306a36Sopenharmony_ci if (err) 57562306a36Sopenharmony_ci return err; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci err = layout_in_empty_space(c); 57862306a36Sopenharmony_ci return err; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci/** 58262306a36Sopenharmony_ci * find_first_dirty - find first dirty znode. 58362306a36Sopenharmony_ci * @znode: znode to begin searching from 58462306a36Sopenharmony_ci */ 58562306a36Sopenharmony_cistatic struct ubifs_znode *find_first_dirty(struct ubifs_znode *znode) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci int i, cont; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (!znode) 59062306a36Sopenharmony_ci return NULL; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci while (1) { 59362306a36Sopenharmony_ci if (znode->level == 0) { 59462306a36Sopenharmony_ci if (ubifs_zn_dirty(znode)) 59562306a36Sopenharmony_ci return znode; 59662306a36Sopenharmony_ci return NULL; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci cont = 0; 59962306a36Sopenharmony_ci for (i = 0; i < znode->child_cnt; i++) { 60062306a36Sopenharmony_ci struct ubifs_zbranch *zbr = &znode->zbranch[i]; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci if (zbr->znode && ubifs_zn_dirty(zbr->znode)) { 60362306a36Sopenharmony_ci znode = zbr->znode; 60462306a36Sopenharmony_ci cont = 1; 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci if (!cont) { 60962306a36Sopenharmony_ci if (ubifs_zn_dirty(znode)) 61062306a36Sopenharmony_ci return znode; 61162306a36Sopenharmony_ci return NULL; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci} 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci/** 61762306a36Sopenharmony_ci * find_next_dirty - find next dirty znode. 61862306a36Sopenharmony_ci * @znode: znode to begin searching from 61962306a36Sopenharmony_ci */ 62062306a36Sopenharmony_cistatic struct ubifs_znode *find_next_dirty(struct ubifs_znode *znode) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci int n = znode->iip + 1; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci znode = znode->parent; 62562306a36Sopenharmony_ci if (!znode) 62662306a36Sopenharmony_ci return NULL; 62762306a36Sopenharmony_ci for (; n < znode->child_cnt; n++) { 62862306a36Sopenharmony_ci struct ubifs_zbranch *zbr = &znode->zbranch[n]; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (zbr->znode && ubifs_zn_dirty(zbr->znode)) 63162306a36Sopenharmony_ci return find_first_dirty(zbr->znode); 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci return znode; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci/** 63762306a36Sopenharmony_ci * get_znodes_to_commit - create list of dirty znodes to commit. 63862306a36Sopenharmony_ci * @c: UBIFS file-system description object 63962306a36Sopenharmony_ci * 64062306a36Sopenharmony_ci * This function returns the number of znodes to commit. 64162306a36Sopenharmony_ci */ 64262306a36Sopenharmony_cistatic int get_znodes_to_commit(struct ubifs_info *c) 64362306a36Sopenharmony_ci{ 64462306a36Sopenharmony_ci struct ubifs_znode *znode, *cnext; 64562306a36Sopenharmony_ci int cnt = 0; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci c->cnext = find_first_dirty(c->zroot.znode); 64862306a36Sopenharmony_ci znode = c->enext = c->cnext; 64962306a36Sopenharmony_ci if (!znode) { 65062306a36Sopenharmony_ci dbg_cmt("no znodes to commit"); 65162306a36Sopenharmony_ci return 0; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci cnt += 1; 65462306a36Sopenharmony_ci while (1) { 65562306a36Sopenharmony_ci ubifs_assert(c, !ubifs_zn_cow(znode)); 65662306a36Sopenharmony_ci __set_bit(COW_ZNODE, &znode->flags); 65762306a36Sopenharmony_ci znode->alt = 0; 65862306a36Sopenharmony_ci cnext = find_next_dirty(znode); 65962306a36Sopenharmony_ci if (!cnext) { 66062306a36Sopenharmony_ci znode->cnext = c->cnext; 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci znode->cparent = znode->parent; 66462306a36Sopenharmony_ci znode->ciip = znode->iip; 66562306a36Sopenharmony_ci znode->cnext = cnext; 66662306a36Sopenharmony_ci znode = cnext; 66762306a36Sopenharmony_ci cnt += 1; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci dbg_cmt("committing %d znodes", cnt); 67062306a36Sopenharmony_ci ubifs_assert(c, cnt == atomic_long_read(&c->dirty_zn_cnt)); 67162306a36Sopenharmony_ci return cnt; 67262306a36Sopenharmony_ci} 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci/** 67562306a36Sopenharmony_ci * alloc_idx_lebs - allocate empty LEBs to be used to commit. 67662306a36Sopenharmony_ci * @c: UBIFS file-system description object 67762306a36Sopenharmony_ci * @cnt: number of znodes to commit 67862306a36Sopenharmony_ci * 67962306a36Sopenharmony_ci * This function returns %-ENOSPC if it cannot allocate a sufficient number of 68062306a36Sopenharmony_ci * empty LEBs. %0 is returned on success, otherwise a negative error code 68162306a36Sopenharmony_ci * is returned. 68262306a36Sopenharmony_ci */ 68362306a36Sopenharmony_cistatic int alloc_idx_lebs(struct ubifs_info *c, int cnt) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci int i, leb_cnt, lnum; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci c->ileb_cnt = 0; 68862306a36Sopenharmony_ci c->ileb_nxt = 0; 68962306a36Sopenharmony_ci leb_cnt = get_leb_cnt(c, cnt); 69062306a36Sopenharmony_ci dbg_cmt("need about %d empty LEBS for TNC commit", leb_cnt); 69162306a36Sopenharmony_ci if (!leb_cnt) 69262306a36Sopenharmony_ci return 0; 69362306a36Sopenharmony_ci c->ilebs = kmalloc_array(leb_cnt, sizeof(int), GFP_NOFS); 69462306a36Sopenharmony_ci if (!c->ilebs) 69562306a36Sopenharmony_ci return -ENOMEM; 69662306a36Sopenharmony_ci for (i = 0; i < leb_cnt; i++) { 69762306a36Sopenharmony_ci lnum = ubifs_find_free_leb_for_idx(c); 69862306a36Sopenharmony_ci if (lnum < 0) 69962306a36Sopenharmony_ci return lnum; 70062306a36Sopenharmony_ci c->ilebs[c->ileb_cnt++] = lnum; 70162306a36Sopenharmony_ci dbg_cmt("LEB %d", lnum); 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci if (dbg_is_chk_index(c) && !get_random_u32_below(8)) 70462306a36Sopenharmony_ci return -ENOSPC; 70562306a36Sopenharmony_ci return 0; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci/** 70962306a36Sopenharmony_ci * free_unused_idx_lebs - free unused LEBs that were allocated for the commit. 71062306a36Sopenharmony_ci * @c: UBIFS file-system description object 71162306a36Sopenharmony_ci * 71262306a36Sopenharmony_ci * It is possible that we allocate more empty LEBs for the commit than we need. 71362306a36Sopenharmony_ci * This functions frees the surplus. 71462306a36Sopenharmony_ci * 71562306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 71662306a36Sopenharmony_ci */ 71762306a36Sopenharmony_cistatic int free_unused_idx_lebs(struct ubifs_info *c) 71862306a36Sopenharmony_ci{ 71962306a36Sopenharmony_ci int i, err = 0, lnum, er; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci for (i = c->ileb_nxt; i < c->ileb_cnt; i++) { 72262306a36Sopenharmony_ci lnum = c->ilebs[i]; 72362306a36Sopenharmony_ci dbg_cmt("LEB %d", lnum); 72462306a36Sopenharmony_ci er = ubifs_change_one_lp(c, lnum, LPROPS_NC, LPROPS_NC, 0, 72562306a36Sopenharmony_ci LPROPS_INDEX | LPROPS_TAKEN, 0); 72662306a36Sopenharmony_ci if (!err) 72762306a36Sopenharmony_ci err = er; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci return err; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci/** 73362306a36Sopenharmony_ci * free_idx_lebs - free unused LEBs after commit end. 73462306a36Sopenharmony_ci * @c: UBIFS file-system description object 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 73762306a36Sopenharmony_ci */ 73862306a36Sopenharmony_cistatic int free_idx_lebs(struct ubifs_info *c) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci int err; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci err = free_unused_idx_lebs(c); 74362306a36Sopenharmony_ci kfree(c->ilebs); 74462306a36Sopenharmony_ci c->ilebs = NULL; 74562306a36Sopenharmony_ci return err; 74662306a36Sopenharmony_ci} 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci/** 74962306a36Sopenharmony_ci * ubifs_tnc_start_commit - start TNC commit. 75062306a36Sopenharmony_ci * @c: UBIFS file-system description object 75162306a36Sopenharmony_ci * @zroot: new index root position is returned here 75262306a36Sopenharmony_ci * 75362306a36Sopenharmony_ci * This function prepares the list of indexing nodes to commit and lays out 75462306a36Sopenharmony_ci * their positions on flash. If there is not enough free space it uses the 75562306a36Sopenharmony_ci * in-gap commit method. Returns zero in case of success and a negative error 75662306a36Sopenharmony_ci * code in case of failure. 75762306a36Sopenharmony_ci */ 75862306a36Sopenharmony_ciint ubifs_tnc_start_commit(struct ubifs_info *c, struct ubifs_zbranch *zroot) 75962306a36Sopenharmony_ci{ 76062306a36Sopenharmony_ci int err = 0, cnt; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci mutex_lock(&c->tnc_mutex); 76362306a36Sopenharmony_ci err = dbg_check_tnc(c, 1); 76462306a36Sopenharmony_ci if (err) 76562306a36Sopenharmony_ci goto out; 76662306a36Sopenharmony_ci cnt = get_znodes_to_commit(c); 76762306a36Sopenharmony_ci if (cnt != 0) { 76862306a36Sopenharmony_ci int no_space = 0; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci err = alloc_idx_lebs(c, cnt); 77162306a36Sopenharmony_ci if (err == -ENOSPC) 77262306a36Sopenharmony_ci no_space = 1; 77362306a36Sopenharmony_ci else if (err) 77462306a36Sopenharmony_ci goto out_free; 77562306a36Sopenharmony_ci err = layout_commit(c, no_space, cnt); 77662306a36Sopenharmony_ci if (err) 77762306a36Sopenharmony_ci goto out_free; 77862306a36Sopenharmony_ci ubifs_assert(c, atomic_long_read(&c->dirty_zn_cnt) == 0); 77962306a36Sopenharmony_ci err = free_unused_idx_lebs(c); 78062306a36Sopenharmony_ci if (err) 78162306a36Sopenharmony_ci goto out; 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci destroy_old_idx(c); 78462306a36Sopenharmony_ci memcpy(zroot, &c->zroot, sizeof(struct ubifs_zbranch)); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci err = ubifs_save_dirty_idx_lnums(c); 78762306a36Sopenharmony_ci if (err) 78862306a36Sopenharmony_ci goto out; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci spin_lock(&c->space_lock); 79162306a36Sopenharmony_ci /* 79262306a36Sopenharmony_ci * Although we have not finished committing yet, update size of the 79362306a36Sopenharmony_ci * committed index ('c->bi.old_idx_sz') and zero out the index growth 79462306a36Sopenharmony_ci * budget. It is OK to do this now, because we've reserved all the 79562306a36Sopenharmony_ci * space which is needed to commit the index, and it is save for the 79662306a36Sopenharmony_ci * budgeting subsystem to assume the index is already committed, 79762306a36Sopenharmony_ci * even though it is not. 79862306a36Sopenharmony_ci */ 79962306a36Sopenharmony_ci ubifs_assert(c, c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c)); 80062306a36Sopenharmony_ci c->bi.old_idx_sz = c->calc_idx_sz; 80162306a36Sopenharmony_ci c->bi.uncommitted_idx = 0; 80262306a36Sopenharmony_ci c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c); 80362306a36Sopenharmony_ci spin_unlock(&c->space_lock); 80462306a36Sopenharmony_ci mutex_unlock(&c->tnc_mutex); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci dbg_cmt("number of index LEBs %d", c->lst.idx_lebs); 80762306a36Sopenharmony_ci dbg_cmt("size of index %llu", c->calc_idx_sz); 80862306a36Sopenharmony_ci return err; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ciout_free: 81162306a36Sopenharmony_ci free_idx_lebs(c); 81262306a36Sopenharmony_ciout: 81362306a36Sopenharmony_ci mutex_unlock(&c->tnc_mutex); 81462306a36Sopenharmony_ci return err; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci/** 81862306a36Sopenharmony_ci * write_index - write index nodes. 81962306a36Sopenharmony_ci * @c: UBIFS file-system description object 82062306a36Sopenharmony_ci * 82162306a36Sopenharmony_ci * This function writes the index nodes whose positions were laid out in the 82262306a36Sopenharmony_ci * layout_in_empty_space function. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_cistatic int write_index(struct ubifs_info *c) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci struct ubifs_idx_node *idx; 82762306a36Sopenharmony_ci struct ubifs_znode *znode, *cnext; 82862306a36Sopenharmony_ci int i, lnum, offs, len, next_len, buf_len, buf_offs, used; 82962306a36Sopenharmony_ci int avail, wlen, err, lnum_pos = 0, blen, nxt_offs; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci cnext = c->enext; 83262306a36Sopenharmony_ci if (!cnext) 83362306a36Sopenharmony_ci return 0; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci /* 83662306a36Sopenharmony_ci * Always write index nodes to the index head so that index nodes and 83762306a36Sopenharmony_ci * other types of nodes are never mixed in the same erase block. 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_ci lnum = c->ihead_lnum; 84062306a36Sopenharmony_ci buf_offs = c->ihead_offs; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* Allocate commit buffer */ 84362306a36Sopenharmony_ci buf_len = ALIGN(c->max_idx_node_sz, c->min_io_size); 84462306a36Sopenharmony_ci used = 0; 84562306a36Sopenharmony_ci avail = buf_len; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* Ensure there is enough room for first write */ 84862306a36Sopenharmony_ci next_len = ubifs_idx_node_sz(c, cnext->child_cnt); 84962306a36Sopenharmony_ci if (buf_offs + next_len > c->leb_size) { 85062306a36Sopenharmony_ci err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0, 0, 85162306a36Sopenharmony_ci LPROPS_TAKEN); 85262306a36Sopenharmony_ci if (err) 85362306a36Sopenharmony_ci return err; 85462306a36Sopenharmony_ci lnum = -1; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci while (1) { 85862306a36Sopenharmony_ci u8 hash[UBIFS_HASH_ARR_SZ]; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci cond_resched(); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci znode = cnext; 86362306a36Sopenharmony_ci idx = c->cbuf + used; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci /* Make index node */ 86662306a36Sopenharmony_ci idx->ch.node_type = UBIFS_IDX_NODE; 86762306a36Sopenharmony_ci idx->child_cnt = cpu_to_le16(znode->child_cnt); 86862306a36Sopenharmony_ci idx->level = cpu_to_le16(znode->level); 86962306a36Sopenharmony_ci for (i = 0; i < znode->child_cnt; i++) { 87062306a36Sopenharmony_ci struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); 87162306a36Sopenharmony_ci struct ubifs_zbranch *zbr = &znode->zbranch[i]; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci key_write_idx(c, &zbr->key, &br->key); 87462306a36Sopenharmony_ci br->lnum = cpu_to_le32(zbr->lnum); 87562306a36Sopenharmony_ci br->offs = cpu_to_le32(zbr->offs); 87662306a36Sopenharmony_ci br->len = cpu_to_le32(zbr->len); 87762306a36Sopenharmony_ci ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br)); 87862306a36Sopenharmony_ci if (!zbr->lnum || !zbr->len) { 87962306a36Sopenharmony_ci ubifs_err(c, "bad ref in znode"); 88062306a36Sopenharmony_ci ubifs_dump_znode(c, znode); 88162306a36Sopenharmony_ci if (zbr->znode) 88262306a36Sopenharmony_ci ubifs_dump_znode(c, zbr->znode); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci return -EINVAL; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci } 88762306a36Sopenharmony_ci len = ubifs_idx_node_sz(c, znode->child_cnt); 88862306a36Sopenharmony_ci ubifs_prepare_node(c, idx, len, 0); 88962306a36Sopenharmony_ci ubifs_node_calc_hash(c, idx, hash); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci mutex_lock(&c->tnc_mutex); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci if (znode->cparent) 89462306a36Sopenharmony_ci ubifs_copy_hash(c, hash, 89562306a36Sopenharmony_ci znode->cparent->zbranch[znode->ciip].hash); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci if (znode->parent) { 89862306a36Sopenharmony_ci if (!ubifs_zn_obsolete(znode)) 89962306a36Sopenharmony_ci ubifs_copy_hash(c, hash, 90062306a36Sopenharmony_ci znode->parent->zbranch[znode->iip].hash); 90162306a36Sopenharmony_ci } else { 90262306a36Sopenharmony_ci ubifs_copy_hash(c, hash, c->zroot.hash); 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci mutex_unlock(&c->tnc_mutex); 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* Determine the index node position */ 90862306a36Sopenharmony_ci if (lnum == -1) { 90962306a36Sopenharmony_ci lnum = c->ilebs[lnum_pos++]; 91062306a36Sopenharmony_ci buf_offs = 0; 91162306a36Sopenharmony_ci used = 0; 91262306a36Sopenharmony_ci avail = buf_len; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci offs = buf_offs + used; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci if (lnum != znode->lnum || offs != znode->offs || 91762306a36Sopenharmony_ci len != znode->len) { 91862306a36Sopenharmony_ci ubifs_err(c, "inconsistent znode posn"); 91962306a36Sopenharmony_ci return -EINVAL; 92062306a36Sopenharmony_ci } 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* Grab some stuff from znode while we still can */ 92362306a36Sopenharmony_ci cnext = znode->cnext; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci ubifs_assert(c, ubifs_zn_dirty(znode)); 92662306a36Sopenharmony_ci ubifs_assert(c, ubifs_zn_cow(znode)); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* 92962306a36Sopenharmony_ci * It is important that other threads should see %DIRTY_ZNODE 93062306a36Sopenharmony_ci * flag cleared before %COW_ZNODE. Specifically, it matters in 93162306a36Sopenharmony_ci * the 'dirty_cow_znode()' function. This is the reason for the 93262306a36Sopenharmony_ci * first barrier. Also, we want the bit changes to be seen to 93362306a36Sopenharmony_ci * other threads ASAP, to avoid unnecessary copying, which is 93462306a36Sopenharmony_ci * the reason for the second barrier. 93562306a36Sopenharmony_ci */ 93662306a36Sopenharmony_ci clear_bit(DIRTY_ZNODE, &znode->flags); 93762306a36Sopenharmony_ci smp_mb__before_atomic(); 93862306a36Sopenharmony_ci clear_bit(COW_ZNODE, &znode->flags); 93962306a36Sopenharmony_ci smp_mb__after_atomic(); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* 94262306a36Sopenharmony_ci * We have marked the znode as clean but have not updated the 94362306a36Sopenharmony_ci * @c->clean_zn_cnt counter. If this znode becomes dirty again 94462306a36Sopenharmony_ci * before 'free_obsolete_znodes()' is called, then 94562306a36Sopenharmony_ci * @c->clean_zn_cnt will be decremented before it gets 94662306a36Sopenharmony_ci * incremented (resulting in 2 decrements for the same znode). 94762306a36Sopenharmony_ci * This means that @c->clean_zn_cnt may become negative for a 94862306a36Sopenharmony_ci * while. 94962306a36Sopenharmony_ci * 95062306a36Sopenharmony_ci * Q: why we cannot increment @c->clean_zn_cnt? 95162306a36Sopenharmony_ci * A: because we do not have the @c->tnc_mutex locked, and the 95262306a36Sopenharmony_ci * following code would be racy and buggy: 95362306a36Sopenharmony_ci * 95462306a36Sopenharmony_ci * if (!ubifs_zn_obsolete(znode)) { 95562306a36Sopenharmony_ci * atomic_long_inc(&c->clean_zn_cnt); 95662306a36Sopenharmony_ci * atomic_long_inc(&ubifs_clean_zn_cnt); 95762306a36Sopenharmony_ci * } 95862306a36Sopenharmony_ci * 95962306a36Sopenharmony_ci * Thus, we just delay the @c->clean_zn_cnt update until we 96062306a36Sopenharmony_ci * have the mutex locked. 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci /* Do not access znode from this point on */ 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* Update buffer positions */ 96662306a36Sopenharmony_ci wlen = used + len; 96762306a36Sopenharmony_ci used += ALIGN(len, 8); 96862306a36Sopenharmony_ci avail -= ALIGN(len, 8); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci /* 97162306a36Sopenharmony_ci * Calculate the next index node length to see if there is 97262306a36Sopenharmony_ci * enough room for it 97362306a36Sopenharmony_ci */ 97462306a36Sopenharmony_ci if (cnext == c->cnext) 97562306a36Sopenharmony_ci next_len = 0; 97662306a36Sopenharmony_ci else 97762306a36Sopenharmony_ci next_len = ubifs_idx_node_sz(c, cnext->child_cnt); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci nxt_offs = buf_offs + used + next_len; 98062306a36Sopenharmony_ci if (next_len && nxt_offs <= c->leb_size) { 98162306a36Sopenharmony_ci if (avail > 0) 98262306a36Sopenharmony_ci continue; 98362306a36Sopenharmony_ci else 98462306a36Sopenharmony_ci blen = buf_len; 98562306a36Sopenharmony_ci } else { 98662306a36Sopenharmony_ci wlen = ALIGN(wlen, 8); 98762306a36Sopenharmony_ci blen = ALIGN(wlen, c->min_io_size); 98862306a36Sopenharmony_ci ubifs_pad(c, c->cbuf + wlen, blen - wlen); 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci /* The buffer is full or there are no more znodes to do */ 99262306a36Sopenharmony_ci err = ubifs_leb_write(c, lnum, c->cbuf, buf_offs, blen); 99362306a36Sopenharmony_ci if (err) 99462306a36Sopenharmony_ci return err; 99562306a36Sopenharmony_ci buf_offs += blen; 99662306a36Sopenharmony_ci if (next_len) { 99762306a36Sopenharmony_ci if (nxt_offs > c->leb_size) { 99862306a36Sopenharmony_ci err = ubifs_update_one_lp(c, lnum, LPROPS_NC, 0, 99962306a36Sopenharmony_ci 0, LPROPS_TAKEN); 100062306a36Sopenharmony_ci if (err) 100162306a36Sopenharmony_ci return err; 100262306a36Sopenharmony_ci lnum = -1; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci used -= blen; 100562306a36Sopenharmony_ci if (used < 0) 100662306a36Sopenharmony_ci used = 0; 100762306a36Sopenharmony_ci avail = buf_len - used; 100862306a36Sopenharmony_ci memmove(c->cbuf, c->cbuf + blen, used); 100962306a36Sopenharmony_ci continue; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci break; 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci if (lnum != c->dbg->new_ihead_lnum || 101562306a36Sopenharmony_ci buf_offs != c->dbg->new_ihead_offs) { 101662306a36Sopenharmony_ci ubifs_err(c, "inconsistent ihead"); 101762306a36Sopenharmony_ci return -EINVAL; 101862306a36Sopenharmony_ci } 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci c->ihead_lnum = lnum; 102162306a36Sopenharmony_ci c->ihead_offs = buf_offs; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci return 0; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci/** 102762306a36Sopenharmony_ci * free_obsolete_znodes - free obsolete znodes. 102862306a36Sopenharmony_ci * @c: UBIFS file-system description object 102962306a36Sopenharmony_ci * 103062306a36Sopenharmony_ci * At the end of commit end, obsolete znodes are freed. 103162306a36Sopenharmony_ci */ 103262306a36Sopenharmony_cistatic void free_obsolete_znodes(struct ubifs_info *c) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci struct ubifs_znode *znode, *cnext; 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci cnext = c->cnext; 103762306a36Sopenharmony_ci do { 103862306a36Sopenharmony_ci znode = cnext; 103962306a36Sopenharmony_ci cnext = znode->cnext; 104062306a36Sopenharmony_ci if (ubifs_zn_obsolete(znode)) 104162306a36Sopenharmony_ci kfree(znode); 104262306a36Sopenharmony_ci else { 104362306a36Sopenharmony_ci znode->cnext = NULL; 104462306a36Sopenharmony_ci atomic_long_inc(&c->clean_zn_cnt); 104562306a36Sopenharmony_ci atomic_long_inc(&ubifs_clean_zn_cnt); 104662306a36Sopenharmony_ci } 104762306a36Sopenharmony_ci } while (cnext != c->cnext); 104862306a36Sopenharmony_ci} 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci/** 105162306a36Sopenharmony_ci * return_gap_lebs - return LEBs used by the in-gap commit method. 105262306a36Sopenharmony_ci * @c: UBIFS file-system description object 105362306a36Sopenharmony_ci * 105462306a36Sopenharmony_ci * This function clears the "taken" flag for the LEBs which were used by the 105562306a36Sopenharmony_ci * "commit in-the-gaps" method. 105662306a36Sopenharmony_ci */ 105762306a36Sopenharmony_cistatic int return_gap_lebs(struct ubifs_info *c) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci int *p, err; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (!c->gap_lebs) 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci dbg_cmt(""); 106562306a36Sopenharmony_ci for (p = c->gap_lebs; *p != -1; p++) { 106662306a36Sopenharmony_ci err = ubifs_change_one_lp(c, *p, LPROPS_NC, LPROPS_NC, 0, 106762306a36Sopenharmony_ci LPROPS_TAKEN, 0); 106862306a36Sopenharmony_ci if (err) 106962306a36Sopenharmony_ci return err; 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci kfree(c->gap_lebs); 107362306a36Sopenharmony_ci c->gap_lebs = NULL; 107462306a36Sopenharmony_ci return 0; 107562306a36Sopenharmony_ci} 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci/** 107862306a36Sopenharmony_ci * ubifs_tnc_end_commit - update the TNC for commit end. 107962306a36Sopenharmony_ci * @c: UBIFS file-system description object 108062306a36Sopenharmony_ci * 108162306a36Sopenharmony_ci * Write the dirty znodes. 108262306a36Sopenharmony_ci */ 108362306a36Sopenharmony_ciint ubifs_tnc_end_commit(struct ubifs_info *c) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci int err; 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci if (!c->cnext) 108862306a36Sopenharmony_ci return 0; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci err = return_gap_lebs(c); 109162306a36Sopenharmony_ci if (err) 109262306a36Sopenharmony_ci return err; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci err = write_index(c); 109562306a36Sopenharmony_ci if (err) 109662306a36Sopenharmony_ci return err; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci mutex_lock(&c->tnc_mutex); 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci dbg_cmt("TNC height is %d", c->zroot.znode->level + 1); 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci free_obsolete_znodes(c); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci c->cnext = NULL; 110562306a36Sopenharmony_ci kfree(c->ilebs); 110662306a36Sopenharmony_ci c->ilebs = NULL; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci mutex_unlock(&c->tnc_mutex); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci return 0; 111162306a36Sopenharmony_ci} 1112