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: Artem Bityutskiy (Битюцкий Артём) 88c2ecf20Sopenharmony_ci * Adrian Hunter 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * This file is a part of UBIFS journal implementation and contains various 138c2ecf20Sopenharmony_ci * functions which manipulate the log. The log is a fixed area on the flash 148c2ecf20Sopenharmony_ci * which does not contain any data but refers to buds. The log is a part of the 158c2ecf20Sopenharmony_ci * journal. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "ubifs.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic int dbg_check_bud_bytes(struct ubifs_info *c); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/** 238c2ecf20Sopenharmony_ci * ubifs_search_bud - search bud LEB. 248c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 258c2ecf20Sopenharmony_ci * @lnum: logical eraseblock number to search 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * This function searches bud LEB @lnum. Returns bud description object in case 288c2ecf20Sopenharmony_ci * of success and %NULL if there is no bud with this LEB number. 298c2ecf20Sopenharmony_ci */ 308c2ecf20Sopenharmony_cistruct ubifs_bud *ubifs_search_bud(struct ubifs_info *c, int lnum) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct rb_node *p; 338c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci spin_lock(&c->buds_lock); 368c2ecf20Sopenharmony_ci p = c->buds.rb_node; 378c2ecf20Sopenharmony_ci while (p) { 388c2ecf20Sopenharmony_ci bud = rb_entry(p, struct ubifs_bud, rb); 398c2ecf20Sopenharmony_ci if (lnum < bud->lnum) 408c2ecf20Sopenharmony_ci p = p->rb_left; 418c2ecf20Sopenharmony_ci else if (lnum > bud->lnum) 428c2ecf20Sopenharmony_ci p = p->rb_right; 438c2ecf20Sopenharmony_ci else { 448c2ecf20Sopenharmony_ci spin_unlock(&c->buds_lock); 458c2ecf20Sopenharmony_ci return bud; 468c2ecf20Sopenharmony_ci } 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci spin_unlock(&c->buds_lock); 498c2ecf20Sopenharmony_ci return NULL; 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/** 538c2ecf20Sopenharmony_ci * ubifs_get_wbuf - get the wbuf associated with a LEB, if there is one. 548c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 558c2ecf20Sopenharmony_ci * @lnum: logical eraseblock number to search 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * This functions returns the wbuf for @lnum or %NULL if there is not one. 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_cistruct ubifs_wbuf *ubifs_get_wbuf(struct ubifs_info *c, int lnum) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct rb_node *p; 628c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 638c2ecf20Sopenharmony_ci int jhead; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci if (!c->jheads) 668c2ecf20Sopenharmony_ci return NULL; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci spin_lock(&c->buds_lock); 698c2ecf20Sopenharmony_ci p = c->buds.rb_node; 708c2ecf20Sopenharmony_ci while (p) { 718c2ecf20Sopenharmony_ci bud = rb_entry(p, struct ubifs_bud, rb); 728c2ecf20Sopenharmony_ci if (lnum < bud->lnum) 738c2ecf20Sopenharmony_ci p = p->rb_left; 748c2ecf20Sopenharmony_ci else if (lnum > bud->lnum) 758c2ecf20Sopenharmony_ci p = p->rb_right; 768c2ecf20Sopenharmony_ci else { 778c2ecf20Sopenharmony_ci jhead = bud->jhead; 788c2ecf20Sopenharmony_ci spin_unlock(&c->buds_lock); 798c2ecf20Sopenharmony_ci return &c->jheads[jhead].wbuf; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci spin_unlock(&c->buds_lock); 838c2ecf20Sopenharmony_ci return NULL; 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci/** 878c2ecf20Sopenharmony_ci * empty_log_bytes - calculate amount of empty space in the log. 888c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cistatic inline long long empty_log_bytes(const struct ubifs_info *c) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci long long h, t; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci h = (long long)c->lhead_lnum * c->leb_size + c->lhead_offs; 958c2ecf20Sopenharmony_ci t = (long long)c->ltail_lnum * c->leb_size; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (h > t) 988c2ecf20Sopenharmony_ci return c->log_bytes - h + t; 998c2ecf20Sopenharmony_ci else if (h != t) 1008c2ecf20Sopenharmony_ci return t - h; 1018c2ecf20Sopenharmony_ci else if (c->lhead_lnum != c->ltail_lnum) 1028c2ecf20Sopenharmony_ci return 0; 1038c2ecf20Sopenharmony_ci else 1048c2ecf20Sopenharmony_ci return c->log_bytes; 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/** 1088c2ecf20Sopenharmony_ci * ubifs_add_bud - add bud LEB to the tree of buds and its journal head list. 1098c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 1108c2ecf20Sopenharmony_ci * @bud: the bud to add 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_civoid ubifs_add_bud(struct ubifs_info *c, struct ubifs_bud *bud) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct rb_node **p, *parent = NULL; 1158c2ecf20Sopenharmony_ci struct ubifs_bud *b; 1168c2ecf20Sopenharmony_ci struct ubifs_jhead *jhead; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci spin_lock(&c->buds_lock); 1198c2ecf20Sopenharmony_ci p = &c->buds.rb_node; 1208c2ecf20Sopenharmony_ci while (*p) { 1218c2ecf20Sopenharmony_ci parent = *p; 1228c2ecf20Sopenharmony_ci b = rb_entry(parent, struct ubifs_bud, rb); 1238c2ecf20Sopenharmony_ci ubifs_assert(c, bud->lnum != b->lnum); 1248c2ecf20Sopenharmony_ci if (bud->lnum < b->lnum) 1258c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 1268c2ecf20Sopenharmony_ci else 1278c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci rb_link_node(&bud->rb, parent, p); 1318c2ecf20Sopenharmony_ci rb_insert_color(&bud->rb, &c->buds); 1328c2ecf20Sopenharmony_ci if (c->jheads) { 1338c2ecf20Sopenharmony_ci jhead = &c->jheads[bud->jhead]; 1348c2ecf20Sopenharmony_ci list_add_tail(&bud->list, &jhead->buds_list); 1358c2ecf20Sopenharmony_ci } else 1368c2ecf20Sopenharmony_ci ubifs_assert(c, c->replaying && c->ro_mount); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * Note, although this is a new bud, we anyway account this space now, 1408c2ecf20Sopenharmony_ci * before any data has been written to it, because this is about to 1418c2ecf20Sopenharmony_ci * guarantee fixed mount time, and this bud will anyway be read and 1428c2ecf20Sopenharmony_ci * scanned. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci c->bud_bytes += c->leb_size - bud->start; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci dbg_log("LEB %d:%d, jhead %s, bud_bytes %lld", bud->lnum, 1478c2ecf20Sopenharmony_ci bud->start, dbg_jhead(bud->jhead), c->bud_bytes); 1488c2ecf20Sopenharmony_ci spin_unlock(&c->buds_lock); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci/** 1528c2ecf20Sopenharmony_ci * ubifs_add_bud_to_log - add a new bud to the log. 1538c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 1548c2ecf20Sopenharmony_ci * @jhead: journal head the bud belongs to 1558c2ecf20Sopenharmony_ci * @lnum: LEB number of the bud 1568c2ecf20Sopenharmony_ci * @offs: starting offset of the bud 1578c2ecf20Sopenharmony_ci * 1588c2ecf20Sopenharmony_ci * This function writes a reference node for the new bud LEB @lnum to the log, 1598c2ecf20Sopenharmony_ci * and adds it to the buds trees. It also makes sure that log size does not 1608c2ecf20Sopenharmony_ci * exceed the 'c->max_bud_bytes' limit. Returns zero in case of success, 1618c2ecf20Sopenharmony_ci * %-EAGAIN if commit is required, and a negative error code in case of 1628c2ecf20Sopenharmony_ci * failure. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_ciint ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci int err; 1678c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 1688c2ecf20Sopenharmony_ci struct ubifs_ref_node *ref; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci bud = kmalloc(sizeof(struct ubifs_bud), GFP_NOFS); 1718c2ecf20Sopenharmony_ci if (!bud) 1728c2ecf20Sopenharmony_ci return -ENOMEM; 1738c2ecf20Sopenharmony_ci ref = kzalloc(c->ref_node_alsz, GFP_NOFS); 1748c2ecf20Sopenharmony_ci if (!ref) { 1758c2ecf20Sopenharmony_ci kfree(bud); 1768c2ecf20Sopenharmony_ci return -ENOMEM; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci mutex_lock(&c->log_mutex); 1808c2ecf20Sopenharmony_ci ubifs_assert(c, !c->ro_media && !c->ro_mount); 1818c2ecf20Sopenharmony_ci if (c->ro_error) { 1828c2ecf20Sopenharmony_ci err = -EROFS; 1838c2ecf20Sopenharmony_ci goto out_unlock; 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* Make sure we have enough space in the log */ 1878c2ecf20Sopenharmony_ci if (empty_log_bytes(c) - c->ref_node_alsz < c->min_log_bytes) { 1888c2ecf20Sopenharmony_ci dbg_log("not enough log space - %lld, required %d", 1898c2ecf20Sopenharmony_ci empty_log_bytes(c), c->min_log_bytes); 1908c2ecf20Sopenharmony_ci ubifs_commit_required(c); 1918c2ecf20Sopenharmony_ci err = -EAGAIN; 1928c2ecf20Sopenharmony_ci goto out_unlock; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* 1968c2ecf20Sopenharmony_ci * Make sure the amount of space in buds will not exceed the 1978c2ecf20Sopenharmony_ci * 'c->max_bud_bytes' limit, because we want to guarantee mount time 1988c2ecf20Sopenharmony_ci * limits. 1998c2ecf20Sopenharmony_ci * 2008c2ecf20Sopenharmony_ci * It is not necessary to hold @c->buds_lock when reading @c->bud_bytes 2018c2ecf20Sopenharmony_ci * because we are holding @c->log_mutex. All @c->bud_bytes take place 2028c2ecf20Sopenharmony_ci * when both @c->log_mutex and @c->bud_bytes are locked. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci if (c->bud_bytes + c->leb_size - offs > c->max_bud_bytes) { 2058c2ecf20Sopenharmony_ci dbg_log("bud bytes %lld (%lld max), require commit", 2068c2ecf20Sopenharmony_ci c->bud_bytes, c->max_bud_bytes); 2078c2ecf20Sopenharmony_ci ubifs_commit_required(c); 2088c2ecf20Sopenharmony_ci err = -EAGAIN; 2098c2ecf20Sopenharmony_ci goto out_unlock; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * If the journal is full enough - start background commit. Note, it is 2148c2ecf20Sopenharmony_ci * OK to read 'c->cmt_state' without spinlock because integer reads 2158c2ecf20Sopenharmony_ci * are atomic in the kernel. 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci if (c->bud_bytes >= c->bg_bud_bytes && 2188c2ecf20Sopenharmony_ci c->cmt_state == COMMIT_RESTING) { 2198c2ecf20Sopenharmony_ci dbg_log("bud bytes %lld (%lld max), initiate BG commit", 2208c2ecf20Sopenharmony_ci c->bud_bytes, c->max_bud_bytes); 2218c2ecf20Sopenharmony_ci ubifs_request_bg_commit(c); 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci bud->lnum = lnum; 2258c2ecf20Sopenharmony_ci bud->start = offs; 2268c2ecf20Sopenharmony_ci bud->jhead = jhead; 2278c2ecf20Sopenharmony_ci bud->log_hash = NULL; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci ref->ch.node_type = UBIFS_REF_NODE; 2308c2ecf20Sopenharmony_ci ref->lnum = cpu_to_le32(bud->lnum); 2318c2ecf20Sopenharmony_ci ref->offs = cpu_to_le32(bud->start); 2328c2ecf20Sopenharmony_ci ref->jhead = cpu_to_le32(jhead); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (c->lhead_offs > c->leb_size - c->ref_node_alsz) { 2358c2ecf20Sopenharmony_ci c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum); 2368c2ecf20Sopenharmony_ci ubifs_assert(c, c->lhead_lnum != c->ltail_lnum); 2378c2ecf20Sopenharmony_ci c->lhead_offs = 0; 2388c2ecf20Sopenharmony_ci } 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci if (c->lhead_offs == 0) { 2418c2ecf20Sopenharmony_ci /* Must ensure next log LEB has been unmapped */ 2428c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, c->lhead_lnum); 2438c2ecf20Sopenharmony_ci if (err) 2448c2ecf20Sopenharmony_ci goto out_unlock; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (bud->start == 0) { 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * Before writing the LEB reference which refers an empty LEB 2508c2ecf20Sopenharmony_ci * to the log, we have to make sure it is mapped, because 2518c2ecf20Sopenharmony_ci * otherwise we'd risk to refer an LEB with garbage in case of 2528c2ecf20Sopenharmony_ci * an unclean reboot, because the target LEB might have been 2538c2ecf20Sopenharmony_ci * unmapped, but not yet physically erased. 2548c2ecf20Sopenharmony_ci */ 2558c2ecf20Sopenharmony_ci err = ubifs_leb_map(c, bud->lnum); 2568c2ecf20Sopenharmony_ci if (err) 2578c2ecf20Sopenharmony_ci goto out_unlock; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci dbg_log("write ref LEB %d:%d", 2618c2ecf20Sopenharmony_ci c->lhead_lnum, c->lhead_offs); 2628c2ecf20Sopenharmony_ci err = ubifs_write_node(c, ref, UBIFS_REF_NODE_SZ, c->lhead_lnum, 2638c2ecf20Sopenharmony_ci c->lhead_offs); 2648c2ecf20Sopenharmony_ci if (err) 2658c2ecf20Sopenharmony_ci goto out_unlock; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci err = ubifs_shash_update(c, c->log_hash, ref, UBIFS_REF_NODE_SZ); 2688c2ecf20Sopenharmony_ci if (err) 2698c2ecf20Sopenharmony_ci goto out_unlock; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci err = ubifs_shash_copy_state(c, c->log_hash, c->jheads[jhead].log_hash); 2728c2ecf20Sopenharmony_ci if (err) 2738c2ecf20Sopenharmony_ci goto out_unlock; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci c->lhead_offs += c->ref_node_alsz; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci ubifs_add_bud(c, bud); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci mutex_unlock(&c->log_mutex); 2808c2ecf20Sopenharmony_ci kfree(ref); 2818c2ecf20Sopenharmony_ci return 0; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ciout_unlock: 2848c2ecf20Sopenharmony_ci mutex_unlock(&c->log_mutex); 2858c2ecf20Sopenharmony_ci kfree(ref); 2868c2ecf20Sopenharmony_ci kfree(bud); 2878c2ecf20Sopenharmony_ci return err; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci/** 2918c2ecf20Sopenharmony_ci * remove_buds - remove used buds. 2928c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 2938c2ecf20Sopenharmony_ci * 2948c2ecf20Sopenharmony_ci * This function removes use buds from the buds tree. It does not remove the 2958c2ecf20Sopenharmony_ci * buds which are pointed to by journal heads. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_cistatic void remove_buds(struct ubifs_info *c) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci struct rb_node *p; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci ubifs_assert(c, list_empty(&c->old_buds)); 3028c2ecf20Sopenharmony_ci c->cmt_bud_bytes = 0; 3038c2ecf20Sopenharmony_ci spin_lock(&c->buds_lock); 3048c2ecf20Sopenharmony_ci p = rb_first(&c->buds); 3058c2ecf20Sopenharmony_ci while (p) { 3068c2ecf20Sopenharmony_ci struct rb_node *p1 = p; 3078c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 3088c2ecf20Sopenharmony_ci struct ubifs_wbuf *wbuf; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci p = rb_next(p); 3118c2ecf20Sopenharmony_ci bud = rb_entry(p1, struct ubifs_bud, rb); 3128c2ecf20Sopenharmony_ci wbuf = &c->jheads[bud->jhead].wbuf; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (wbuf->lnum == bud->lnum) { 3158c2ecf20Sopenharmony_ci /* 3168c2ecf20Sopenharmony_ci * Do not remove buds which are pointed to by journal 3178c2ecf20Sopenharmony_ci * heads (non-closed buds). 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_ci c->cmt_bud_bytes += wbuf->offs - bud->start; 3208c2ecf20Sopenharmony_ci dbg_log("preserve %d:%d, jhead %s, bud bytes %d, cmt_bud_bytes %lld", 3218c2ecf20Sopenharmony_ci bud->lnum, bud->start, dbg_jhead(bud->jhead), 3228c2ecf20Sopenharmony_ci wbuf->offs - bud->start, c->cmt_bud_bytes); 3238c2ecf20Sopenharmony_ci bud->start = wbuf->offs; 3248c2ecf20Sopenharmony_ci } else { 3258c2ecf20Sopenharmony_ci c->cmt_bud_bytes += c->leb_size - bud->start; 3268c2ecf20Sopenharmony_ci dbg_log("remove %d:%d, jhead %s, bud bytes %d, cmt_bud_bytes %lld", 3278c2ecf20Sopenharmony_ci bud->lnum, bud->start, dbg_jhead(bud->jhead), 3288c2ecf20Sopenharmony_ci c->leb_size - bud->start, c->cmt_bud_bytes); 3298c2ecf20Sopenharmony_ci rb_erase(p1, &c->buds); 3308c2ecf20Sopenharmony_ci /* 3318c2ecf20Sopenharmony_ci * If the commit does not finish, the recovery will need 3328c2ecf20Sopenharmony_ci * to replay the journal, in which case the old buds 3338c2ecf20Sopenharmony_ci * must be unchanged. Do not release them until post 3348c2ecf20Sopenharmony_ci * commit i.e. do not allow them to be garbage 3358c2ecf20Sopenharmony_ci * collected. 3368c2ecf20Sopenharmony_ci */ 3378c2ecf20Sopenharmony_ci list_move(&bud->list, &c->old_buds); 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci spin_unlock(&c->buds_lock); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci/** 3448c2ecf20Sopenharmony_ci * ubifs_log_start_commit - start commit. 3458c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3468c2ecf20Sopenharmony_ci * @ltail_lnum: return new log tail LEB number 3478c2ecf20Sopenharmony_ci * 3488c2ecf20Sopenharmony_ci * The commit operation starts with writing "commit start" node to the log and 3498c2ecf20Sopenharmony_ci * reference nodes for all journal heads which will define new journal after 3508c2ecf20Sopenharmony_ci * the commit has been finished. The commit start and reference nodes are 3518c2ecf20Sopenharmony_ci * written in one go to the nearest empty log LEB (hence, when commit is 3528c2ecf20Sopenharmony_ci * finished UBIFS may safely unmap all the previous log LEBs). This function 3538c2ecf20Sopenharmony_ci * returns zero in case of success and a negative error code in case of 3548c2ecf20Sopenharmony_ci * failure. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_ciint ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci void *buf; 3598c2ecf20Sopenharmony_ci struct ubifs_cs_node *cs; 3608c2ecf20Sopenharmony_ci struct ubifs_ref_node *ref; 3618c2ecf20Sopenharmony_ci int err, i, max_len, len; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci err = dbg_check_bud_bytes(c); 3648c2ecf20Sopenharmony_ci if (err) 3658c2ecf20Sopenharmony_ci return err; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci max_len = UBIFS_CS_NODE_SZ + c->jhead_cnt * UBIFS_REF_NODE_SZ; 3688c2ecf20Sopenharmony_ci max_len = ALIGN(max_len, c->min_io_size); 3698c2ecf20Sopenharmony_ci buf = cs = kmalloc(max_len, GFP_NOFS); 3708c2ecf20Sopenharmony_ci if (!buf) 3718c2ecf20Sopenharmony_ci return -ENOMEM; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci cs->ch.node_type = UBIFS_CS_NODE; 3748c2ecf20Sopenharmony_ci cs->cmt_no = cpu_to_le64(c->cmt_no); 3758c2ecf20Sopenharmony_ci ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci err = ubifs_shash_init(c, c->log_hash); 3788c2ecf20Sopenharmony_ci if (err) 3798c2ecf20Sopenharmony_ci goto out; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci err = ubifs_shash_update(c, c->log_hash, cs, UBIFS_CS_NODE_SZ); 3828c2ecf20Sopenharmony_ci if (err < 0) 3838c2ecf20Sopenharmony_ci goto out; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* 3868c2ecf20Sopenharmony_ci * Note, we do not lock 'c->log_mutex' because this is the commit start 3878c2ecf20Sopenharmony_ci * phase and we are exclusively using the log. And we do not lock 3888c2ecf20Sopenharmony_ci * write-buffer because nobody can write to the file-system at this 3898c2ecf20Sopenharmony_ci * phase. 3908c2ecf20Sopenharmony_ci */ 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci len = UBIFS_CS_NODE_SZ; 3938c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) { 3948c2ecf20Sopenharmony_ci int lnum = c->jheads[i].wbuf.lnum; 3958c2ecf20Sopenharmony_ci int offs = c->jheads[i].wbuf.offs; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (lnum == -1 || offs == c->leb_size) 3988c2ecf20Sopenharmony_ci continue; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci dbg_log("add ref to LEB %d:%d for jhead %s", 4018c2ecf20Sopenharmony_ci lnum, offs, dbg_jhead(i)); 4028c2ecf20Sopenharmony_ci ref = buf + len; 4038c2ecf20Sopenharmony_ci ref->ch.node_type = UBIFS_REF_NODE; 4048c2ecf20Sopenharmony_ci ref->lnum = cpu_to_le32(lnum); 4058c2ecf20Sopenharmony_ci ref->offs = cpu_to_le32(offs); 4068c2ecf20Sopenharmony_ci ref->jhead = cpu_to_le32(i); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0); 4098c2ecf20Sopenharmony_ci len += UBIFS_REF_NODE_SZ; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci err = ubifs_shash_update(c, c->log_hash, ref, 4128c2ecf20Sopenharmony_ci UBIFS_REF_NODE_SZ); 4138c2ecf20Sopenharmony_ci if (err) 4148c2ecf20Sopenharmony_ci goto out; 4158c2ecf20Sopenharmony_ci ubifs_shash_copy_state(c, c->log_hash, c->jheads[i].log_hash); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* Switch to the next log LEB */ 4218c2ecf20Sopenharmony_ci if (c->lhead_offs) { 4228c2ecf20Sopenharmony_ci c->lhead_lnum = ubifs_next_log_lnum(c, c->lhead_lnum); 4238c2ecf20Sopenharmony_ci ubifs_assert(c, c->lhead_lnum != c->ltail_lnum); 4248c2ecf20Sopenharmony_ci c->lhead_offs = 0; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* Must ensure next LEB has been unmapped */ 4288c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, c->lhead_lnum); 4298c2ecf20Sopenharmony_ci if (err) 4308c2ecf20Sopenharmony_ci goto out; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci len = ALIGN(len, c->min_io_size); 4338c2ecf20Sopenharmony_ci dbg_log("writing commit start at LEB %d:0, len %d", c->lhead_lnum, len); 4348c2ecf20Sopenharmony_ci err = ubifs_leb_write(c, c->lhead_lnum, cs, 0, len); 4358c2ecf20Sopenharmony_ci if (err) 4368c2ecf20Sopenharmony_ci goto out; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci *ltail_lnum = c->lhead_lnum; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci c->lhead_offs += len; 4418c2ecf20Sopenharmony_ci ubifs_assert(c, c->lhead_offs < c->leb_size); 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci remove_buds(c); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* 4468c2ecf20Sopenharmony_ci * We have started the commit and now users may use the rest of the log 4478c2ecf20Sopenharmony_ci * for new writes. 4488c2ecf20Sopenharmony_ci */ 4498c2ecf20Sopenharmony_ci c->min_log_bytes = 0; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ciout: 4528c2ecf20Sopenharmony_ci kfree(buf); 4538c2ecf20Sopenharmony_ci return err; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci/** 4578c2ecf20Sopenharmony_ci * ubifs_log_end_commit - end commit. 4588c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 4598c2ecf20Sopenharmony_ci * @ltail_lnum: new log tail LEB number 4608c2ecf20Sopenharmony_ci * 4618c2ecf20Sopenharmony_ci * This function is called on when the commit operation was finished. It 4628c2ecf20Sopenharmony_ci * moves log tail to new position and updates the master node so that it stores 4638c2ecf20Sopenharmony_ci * the new log tail LEB number. Returns zero in case of success and a negative 4648c2ecf20Sopenharmony_ci * error code in case of failure. 4658c2ecf20Sopenharmony_ci */ 4668c2ecf20Sopenharmony_ciint ubifs_log_end_commit(struct ubifs_info *c, int ltail_lnum) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci int err; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* 4718c2ecf20Sopenharmony_ci * At this phase we have to lock 'c->log_mutex' because UBIFS allows FS 4728c2ecf20Sopenharmony_ci * writes during commit. Its only short "commit" start phase when 4738c2ecf20Sopenharmony_ci * writers are blocked. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_ci mutex_lock(&c->log_mutex); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci dbg_log("old tail was LEB %d:0, new tail is LEB %d:0", 4788c2ecf20Sopenharmony_ci c->ltail_lnum, ltail_lnum); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci c->ltail_lnum = ltail_lnum; 4818c2ecf20Sopenharmony_ci /* 4828c2ecf20Sopenharmony_ci * The commit is finished and from now on it must be guaranteed that 4838c2ecf20Sopenharmony_ci * there is always enough space for the next commit. 4848c2ecf20Sopenharmony_ci */ 4858c2ecf20Sopenharmony_ci c->min_log_bytes = c->leb_size; 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci spin_lock(&c->buds_lock); 4888c2ecf20Sopenharmony_ci c->bud_bytes -= c->cmt_bud_bytes; 4898c2ecf20Sopenharmony_ci spin_unlock(&c->buds_lock); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci err = dbg_check_bud_bytes(c); 4928c2ecf20Sopenharmony_ci if (err) 4938c2ecf20Sopenharmony_ci goto out; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci err = ubifs_write_master(c); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ciout: 4988c2ecf20Sopenharmony_ci mutex_unlock(&c->log_mutex); 4998c2ecf20Sopenharmony_ci return err; 5008c2ecf20Sopenharmony_ci} 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci/** 5038c2ecf20Sopenharmony_ci * ubifs_log_post_commit - things to do after commit is completed. 5048c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5058c2ecf20Sopenharmony_ci * @old_ltail_lnum: old log tail LEB number 5068c2ecf20Sopenharmony_ci * 5078c2ecf20Sopenharmony_ci * Release buds only after commit is completed, because they must be unchanged 5088c2ecf20Sopenharmony_ci * if recovery is needed. 5098c2ecf20Sopenharmony_ci * 5108c2ecf20Sopenharmony_ci * Unmap log LEBs only after commit is completed, because they may be needed for 5118c2ecf20Sopenharmony_ci * recovery. 5128c2ecf20Sopenharmony_ci * 5138c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 5148c2ecf20Sopenharmony_ci */ 5158c2ecf20Sopenharmony_ciint ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci int lnum, err = 0; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci while (!list_empty(&c->old_buds)) { 5208c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci bud = list_entry(c->old_buds.next, struct ubifs_bud, list); 5238c2ecf20Sopenharmony_ci err = ubifs_return_leb(c, bud->lnum); 5248c2ecf20Sopenharmony_ci if (err) 5258c2ecf20Sopenharmony_ci return err; 5268c2ecf20Sopenharmony_ci list_del(&bud->list); 5278c2ecf20Sopenharmony_ci kfree(bud->log_hash); 5288c2ecf20Sopenharmony_ci kfree(bud); 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci mutex_lock(&c->log_mutex); 5318c2ecf20Sopenharmony_ci for (lnum = old_ltail_lnum; lnum != c->ltail_lnum; 5328c2ecf20Sopenharmony_ci lnum = ubifs_next_log_lnum(c, lnum)) { 5338c2ecf20Sopenharmony_ci dbg_log("unmap log LEB %d", lnum); 5348c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, lnum); 5358c2ecf20Sopenharmony_ci if (err) 5368c2ecf20Sopenharmony_ci goto out; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ciout: 5398c2ecf20Sopenharmony_ci mutex_unlock(&c->log_mutex); 5408c2ecf20Sopenharmony_ci return err; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/** 5448c2ecf20Sopenharmony_ci * struct done_ref - references that have been done. 5458c2ecf20Sopenharmony_ci * @rb: rb-tree node 5468c2ecf20Sopenharmony_ci * @lnum: LEB number 5478c2ecf20Sopenharmony_ci */ 5488c2ecf20Sopenharmony_cistruct done_ref { 5498c2ecf20Sopenharmony_ci struct rb_node rb; 5508c2ecf20Sopenharmony_ci int lnum; 5518c2ecf20Sopenharmony_ci}; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci/** 5548c2ecf20Sopenharmony_ci * done_already - determine if a reference has been done already. 5558c2ecf20Sopenharmony_ci * @done_tree: rb-tree to store references that have been done 5568c2ecf20Sopenharmony_ci * @lnum: LEB number of reference 5578c2ecf20Sopenharmony_ci * 5588c2ecf20Sopenharmony_ci * This function returns %1 if the reference has been done, %0 if not, otherwise 5598c2ecf20Sopenharmony_ci * a negative error code is returned. 5608c2ecf20Sopenharmony_ci */ 5618c2ecf20Sopenharmony_cistatic int done_already(struct rb_root *done_tree, int lnum) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct rb_node **p = &done_tree->rb_node, *parent = NULL; 5648c2ecf20Sopenharmony_ci struct done_ref *dr; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci while (*p) { 5678c2ecf20Sopenharmony_ci parent = *p; 5688c2ecf20Sopenharmony_ci dr = rb_entry(parent, struct done_ref, rb); 5698c2ecf20Sopenharmony_ci if (lnum < dr->lnum) 5708c2ecf20Sopenharmony_ci p = &(*p)->rb_left; 5718c2ecf20Sopenharmony_ci else if (lnum > dr->lnum) 5728c2ecf20Sopenharmony_ci p = &(*p)->rb_right; 5738c2ecf20Sopenharmony_ci else 5748c2ecf20Sopenharmony_ci return 1; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci dr = kzalloc(sizeof(struct done_ref), GFP_NOFS); 5788c2ecf20Sopenharmony_ci if (!dr) 5798c2ecf20Sopenharmony_ci return -ENOMEM; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci dr->lnum = lnum; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci rb_link_node(&dr->rb, parent, p); 5848c2ecf20Sopenharmony_ci rb_insert_color(&dr->rb, done_tree); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci return 0; 5878c2ecf20Sopenharmony_ci} 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci/** 5908c2ecf20Sopenharmony_ci * destroy_done_tree - destroy the done tree. 5918c2ecf20Sopenharmony_ci * @done_tree: done tree to destroy 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_cistatic void destroy_done_tree(struct rb_root *done_tree) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci struct done_ref *dr, *n; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci rbtree_postorder_for_each_entry_safe(dr, n, done_tree, rb) 5988c2ecf20Sopenharmony_ci kfree(dr); 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci/** 6028c2ecf20Sopenharmony_ci * add_node - add a node to the consolidated log. 6038c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 6048c2ecf20Sopenharmony_ci * @buf: buffer to which to add 6058c2ecf20Sopenharmony_ci * @lnum: LEB number to which to write is passed and returned here 6068c2ecf20Sopenharmony_ci * @offs: offset to where to write is passed and returned here 6078c2ecf20Sopenharmony_ci * @node: node to add 6088c2ecf20Sopenharmony_ci * 6098c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 6108c2ecf20Sopenharmony_ci */ 6118c2ecf20Sopenharmony_cistatic int add_node(struct ubifs_info *c, void *buf, int *lnum, int *offs, 6128c2ecf20Sopenharmony_ci void *node) 6138c2ecf20Sopenharmony_ci{ 6148c2ecf20Sopenharmony_ci struct ubifs_ch *ch = node; 6158c2ecf20Sopenharmony_ci int len = le32_to_cpu(ch->len), remains = c->leb_size - *offs; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (len > remains) { 6188c2ecf20Sopenharmony_ci int sz = ALIGN(*offs, c->min_io_size), err; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci ubifs_pad(c, buf + *offs, sz - *offs); 6218c2ecf20Sopenharmony_ci err = ubifs_leb_change(c, *lnum, buf, sz); 6228c2ecf20Sopenharmony_ci if (err) 6238c2ecf20Sopenharmony_ci return err; 6248c2ecf20Sopenharmony_ci *lnum = ubifs_next_log_lnum(c, *lnum); 6258c2ecf20Sopenharmony_ci *offs = 0; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci memcpy(buf + *offs, node, len); 6288c2ecf20Sopenharmony_ci *offs += ALIGN(len, 8); 6298c2ecf20Sopenharmony_ci return 0; 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci/** 6338c2ecf20Sopenharmony_ci * ubifs_consolidate_log - consolidate the log. 6348c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 6358c2ecf20Sopenharmony_ci * 6368c2ecf20Sopenharmony_ci * Repeated failed commits could cause the log to be full, but at least 1 LEB is 6378c2ecf20Sopenharmony_ci * needed for commit. This function rewrites the reference nodes in the log 6388c2ecf20Sopenharmony_ci * omitting duplicates, and failed CS nodes, and leaving no gaps. 6398c2ecf20Sopenharmony_ci * 6408c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_ciint ubifs_consolidate_log(struct ubifs_info *c) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci struct ubifs_scan_leb *sleb; 6458c2ecf20Sopenharmony_ci struct ubifs_scan_node *snod; 6468c2ecf20Sopenharmony_ci struct rb_root done_tree = RB_ROOT; 6478c2ecf20Sopenharmony_ci int lnum, err, first = 1, write_lnum, offs = 0; 6488c2ecf20Sopenharmony_ci void *buf; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci dbg_rcvry("log tail LEB %d, log head LEB %d", c->ltail_lnum, 6518c2ecf20Sopenharmony_ci c->lhead_lnum); 6528c2ecf20Sopenharmony_ci buf = vmalloc(c->leb_size); 6538c2ecf20Sopenharmony_ci if (!buf) 6548c2ecf20Sopenharmony_ci return -ENOMEM; 6558c2ecf20Sopenharmony_ci lnum = c->ltail_lnum; 6568c2ecf20Sopenharmony_ci write_lnum = lnum; 6578c2ecf20Sopenharmony_ci while (1) { 6588c2ecf20Sopenharmony_ci sleb = ubifs_scan(c, lnum, 0, c->sbuf, 0); 6598c2ecf20Sopenharmony_ci if (IS_ERR(sleb)) { 6608c2ecf20Sopenharmony_ci err = PTR_ERR(sleb); 6618c2ecf20Sopenharmony_ci goto out_free; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci list_for_each_entry(snod, &sleb->nodes, list) { 6648c2ecf20Sopenharmony_ci switch (snod->type) { 6658c2ecf20Sopenharmony_ci case UBIFS_REF_NODE: { 6668c2ecf20Sopenharmony_ci struct ubifs_ref_node *ref = snod->node; 6678c2ecf20Sopenharmony_ci int ref_lnum = le32_to_cpu(ref->lnum); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci err = done_already(&done_tree, ref_lnum); 6708c2ecf20Sopenharmony_ci if (err < 0) 6718c2ecf20Sopenharmony_ci goto out_scan; 6728c2ecf20Sopenharmony_ci if (err != 1) { 6738c2ecf20Sopenharmony_ci err = add_node(c, buf, &write_lnum, 6748c2ecf20Sopenharmony_ci &offs, snod->node); 6758c2ecf20Sopenharmony_ci if (err) 6768c2ecf20Sopenharmony_ci goto out_scan; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci break; 6798c2ecf20Sopenharmony_ci } 6808c2ecf20Sopenharmony_ci case UBIFS_CS_NODE: 6818c2ecf20Sopenharmony_ci if (!first) 6828c2ecf20Sopenharmony_ci break; 6838c2ecf20Sopenharmony_ci err = add_node(c, buf, &write_lnum, &offs, 6848c2ecf20Sopenharmony_ci snod->node); 6858c2ecf20Sopenharmony_ci if (err) 6868c2ecf20Sopenharmony_ci goto out_scan; 6878c2ecf20Sopenharmony_ci first = 0; 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 6928c2ecf20Sopenharmony_ci if (lnum == c->lhead_lnum) 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci lnum = ubifs_next_log_lnum(c, lnum); 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci if (offs) { 6978c2ecf20Sopenharmony_ci int sz = ALIGN(offs, c->min_io_size); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci ubifs_pad(c, buf + offs, sz - offs); 7008c2ecf20Sopenharmony_ci err = ubifs_leb_change(c, write_lnum, buf, sz); 7018c2ecf20Sopenharmony_ci if (err) 7028c2ecf20Sopenharmony_ci goto out_free; 7038c2ecf20Sopenharmony_ci offs = ALIGN(offs, c->min_io_size); 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci destroy_done_tree(&done_tree); 7068c2ecf20Sopenharmony_ci vfree(buf); 7078c2ecf20Sopenharmony_ci if (write_lnum == c->lhead_lnum) { 7088c2ecf20Sopenharmony_ci ubifs_err(c, "log is too full"); 7098c2ecf20Sopenharmony_ci return -EINVAL; 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci /* Unmap remaining LEBs */ 7128c2ecf20Sopenharmony_ci lnum = write_lnum; 7138c2ecf20Sopenharmony_ci do { 7148c2ecf20Sopenharmony_ci lnum = ubifs_next_log_lnum(c, lnum); 7158c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, lnum); 7168c2ecf20Sopenharmony_ci if (err) 7178c2ecf20Sopenharmony_ci return err; 7188c2ecf20Sopenharmony_ci } while (lnum != c->lhead_lnum); 7198c2ecf20Sopenharmony_ci c->lhead_lnum = write_lnum; 7208c2ecf20Sopenharmony_ci c->lhead_offs = offs; 7218c2ecf20Sopenharmony_ci dbg_rcvry("new log head at %d:%d", c->lhead_lnum, c->lhead_offs); 7228c2ecf20Sopenharmony_ci return 0; 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ciout_scan: 7258c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 7268c2ecf20Sopenharmony_ciout_free: 7278c2ecf20Sopenharmony_ci destroy_done_tree(&done_tree); 7288c2ecf20Sopenharmony_ci vfree(buf); 7298c2ecf20Sopenharmony_ci return err; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/** 7338c2ecf20Sopenharmony_ci * dbg_check_bud_bytes - make sure bud bytes calculation are all right. 7348c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 7358c2ecf20Sopenharmony_ci * 7368c2ecf20Sopenharmony_ci * This function makes sure the amount of flash space used by closed buds 7378c2ecf20Sopenharmony_ci * ('c->bud_bytes' is correct). Returns zero in case of success and %-EINVAL in 7388c2ecf20Sopenharmony_ci * case of failure. 7398c2ecf20Sopenharmony_ci */ 7408c2ecf20Sopenharmony_cistatic int dbg_check_bud_bytes(struct ubifs_info *c) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci int i, err = 0; 7438c2ecf20Sopenharmony_ci struct ubifs_bud *bud; 7448c2ecf20Sopenharmony_ci long long bud_bytes = 0; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (!dbg_is_chk_gen(c)) 7478c2ecf20Sopenharmony_ci return 0; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci spin_lock(&c->buds_lock); 7508c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) 7518c2ecf20Sopenharmony_ci list_for_each_entry(bud, &c->jheads[i].buds_list, list) 7528c2ecf20Sopenharmony_ci bud_bytes += c->leb_size - bud->start; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci if (c->bud_bytes != bud_bytes) { 7558c2ecf20Sopenharmony_ci ubifs_err(c, "bad bud_bytes %lld, calculated %lld", 7568c2ecf20Sopenharmony_ci c->bud_bytes, bud_bytes); 7578c2ecf20Sopenharmony_ci err = -EINVAL; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci spin_unlock(&c->buds_lock); 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return err; 7628c2ecf20Sopenharmony_ci} 763