18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of UBIFS. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2006-2008 Nokia Corporation. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Adrian Hunter 88c2ecf20Sopenharmony_ci * Artem Bityutskiy (Битюцкий Артём) 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci/* 128c2ecf20Sopenharmony_ci * This file implements functions that manage the running of the commit process. 138c2ecf20Sopenharmony_ci * Each affected module has its own functions to accomplish their part in the 148c2ecf20Sopenharmony_ci * commit and those functions are called here. 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * The commit is the process whereby all updates to the index and LEB properties 178c2ecf20Sopenharmony_ci * are written out together and the journal becomes empty. This keeps the 188c2ecf20Sopenharmony_ci * file system consistent - at all times the state can be recreated by reading 198c2ecf20Sopenharmony_ci * the index and LEB properties and then replaying the journal. 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * The commit is split into two parts named "commit start" and "commit end". 228c2ecf20Sopenharmony_ci * During commit start, the commit process has exclusive access to the journal 238c2ecf20Sopenharmony_ci * by holding the commit semaphore down for writing. As few I/O operations as 248c2ecf20Sopenharmony_ci * possible are performed during commit start, instead the nodes that are to be 258c2ecf20Sopenharmony_ci * written are merely identified. During commit end, the commit semaphore is no 268c2ecf20Sopenharmony_ci * longer held and the journal is again in operation, allowing users to continue 278c2ecf20Sopenharmony_ci * to use the file system while the bulk of the commit I/O is performed. The 288c2ecf20Sopenharmony_ci * purpose of this two-step approach is to prevent the commit from causing any 298c2ecf20Sopenharmony_ci * latency blips. Note that in any case, the commit does not prevent lookups 308c2ecf20Sopenharmony_ci * (as permitted by the TNC mutex), or access to VFS data structures e.g. page 318c2ecf20Sopenharmony_ci * cache. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#include <linux/freezer.h> 358c2ecf20Sopenharmony_ci#include <linux/kthread.h> 368c2ecf20Sopenharmony_ci#include <linux/slab.h> 378c2ecf20Sopenharmony_ci#include "ubifs.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* 408c2ecf20Sopenharmony_ci * nothing_to_commit - check if there is nothing to commit. 418c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * This is a helper function which checks if there is anything to commit. It is 448c2ecf20Sopenharmony_ci * used as an optimization to avoid starting the commit if it is not really 458c2ecf20Sopenharmony_ci * necessary. Indeed, the commit operation always assumes flash I/O (e.g., 468c2ecf20Sopenharmony_ci * writing the commit start node to the log), and it is better to avoid doing 478c2ecf20Sopenharmony_ci * this unnecessarily. E.g., 'ubifs_sync_fs()' runs the commit, but if there is 488c2ecf20Sopenharmony_ci * nothing to commit, it is more optimal to avoid any flash I/O. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * This function has to be called with @c->commit_sem locked for writing - 518c2ecf20Sopenharmony_ci * this function does not take LPT/TNC locks because the @c->commit_sem 528c2ecf20Sopenharmony_ci * guarantees that we have exclusive access to the TNC and LPT data structures. 538c2ecf20Sopenharmony_ci * 548c2ecf20Sopenharmony_ci * This function returns %1 if there is nothing to commit and %0 otherwise. 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistatic int nothing_to_commit(struct ubifs_info *c) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci /* 598c2ecf20Sopenharmony_ci * During mounting or remounting from R/O mode to R/W mode we may 608c2ecf20Sopenharmony_ci * commit for various recovery-related reasons. 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_ci if (c->mounting || c->remounting_rw) 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* 668c2ecf20Sopenharmony_ci * If the root TNC node is dirty, we definitely have something to 678c2ecf20Sopenharmony_ci * commit. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode)) 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* 738c2ecf20Sopenharmony_ci * Even though the TNC is clean, the LPT tree may have dirty nodes. For 748c2ecf20Sopenharmony_ci * example, this may happen if the budgeting subsystem invoked GC to 758c2ecf20Sopenharmony_ci * make some free space, and the GC found an LEB with only dirty and 768c2ecf20Sopenharmony_ci * free space. In this case GC would just change the lprops of this 778c2ecf20Sopenharmony_ci * LEB (by turning all space into free space) and unmap it. 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags)) 808c2ecf20Sopenharmony_ci return 0; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci ubifs_assert(c, atomic_long_read(&c->dirty_zn_cnt) == 0); 838c2ecf20Sopenharmony_ci ubifs_assert(c, c->dirty_pn_cnt == 0); 848c2ecf20Sopenharmony_ci ubifs_assert(c, c->dirty_nn_cnt == 0); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return 1; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/** 908c2ecf20Sopenharmony_ci * do_commit - commit the journal. 918c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 928c2ecf20Sopenharmony_ci * 938c2ecf20Sopenharmony_ci * This function implements UBIFS commit. It has to be called with commit lock 948c2ecf20Sopenharmony_ci * locked. Returns zero in case of success and a negative error code in case of 958c2ecf20Sopenharmony_ci * failure. 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_cistatic int do_commit(struct ubifs_info *c) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci int err, new_ltail_lnum, old_ltail_lnum, i; 1008c2ecf20Sopenharmony_ci struct ubifs_zbranch zroot; 1018c2ecf20Sopenharmony_ci struct ubifs_lp_stats lst; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci dbg_cmt("start"); 1048c2ecf20Sopenharmony_ci ubifs_assert(c, !c->ro_media && !c->ro_mount); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (c->ro_error) { 1078c2ecf20Sopenharmony_ci err = -EROFS; 1088c2ecf20Sopenharmony_ci goto out_up; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (nothing_to_commit(c)) { 1128c2ecf20Sopenharmony_ci up_write(&c->commit_sem); 1138c2ecf20Sopenharmony_ci err = 0; 1148c2ecf20Sopenharmony_ci goto out_cancel; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Sync all write buffers (necessary for recovery) */ 1188c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) { 1198c2ecf20Sopenharmony_ci err = ubifs_wbuf_sync(&c->jheads[i].wbuf); 1208c2ecf20Sopenharmony_ci if (err) 1218c2ecf20Sopenharmony_ci goto out_up; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci c->cmt_no += 1; 1258c2ecf20Sopenharmony_ci err = ubifs_gc_start_commit(c); 1268c2ecf20Sopenharmony_ci if (err) 1278c2ecf20Sopenharmony_ci goto out_up; 1288c2ecf20Sopenharmony_ci err = dbg_check_lprops(c); 1298c2ecf20Sopenharmony_ci if (err) 1308c2ecf20Sopenharmony_ci goto out_up; 1318c2ecf20Sopenharmony_ci err = ubifs_log_start_commit(c, &new_ltail_lnum); 1328c2ecf20Sopenharmony_ci if (err) 1338c2ecf20Sopenharmony_ci goto out_up; 1348c2ecf20Sopenharmony_ci err = ubifs_tnc_start_commit(c, &zroot); 1358c2ecf20Sopenharmony_ci if (err) 1368c2ecf20Sopenharmony_ci goto out_up; 1378c2ecf20Sopenharmony_ci err = ubifs_lpt_start_commit(c); 1388c2ecf20Sopenharmony_ci if (err) 1398c2ecf20Sopenharmony_ci goto out_up; 1408c2ecf20Sopenharmony_ci err = ubifs_orphan_start_commit(c); 1418c2ecf20Sopenharmony_ci if (err) 1428c2ecf20Sopenharmony_ci goto out_up; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci ubifs_get_lp_stats(c, &lst); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci up_write(&c->commit_sem); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci err = ubifs_tnc_end_commit(c); 1498c2ecf20Sopenharmony_ci if (err) 1508c2ecf20Sopenharmony_ci goto out; 1518c2ecf20Sopenharmony_ci err = ubifs_lpt_end_commit(c); 1528c2ecf20Sopenharmony_ci if (err) 1538c2ecf20Sopenharmony_ci goto out; 1548c2ecf20Sopenharmony_ci err = ubifs_orphan_end_commit(c); 1558c2ecf20Sopenharmony_ci if (err) 1568c2ecf20Sopenharmony_ci goto out; 1578c2ecf20Sopenharmony_ci err = dbg_check_old_index(c, &zroot); 1588c2ecf20Sopenharmony_ci if (err) 1598c2ecf20Sopenharmony_ci goto out; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci c->mst_node->cmt_no = cpu_to_le64(c->cmt_no); 1628c2ecf20Sopenharmony_ci c->mst_node->log_lnum = cpu_to_le32(new_ltail_lnum); 1638c2ecf20Sopenharmony_ci c->mst_node->root_lnum = cpu_to_le32(zroot.lnum); 1648c2ecf20Sopenharmony_ci c->mst_node->root_offs = cpu_to_le32(zroot.offs); 1658c2ecf20Sopenharmony_ci c->mst_node->root_len = cpu_to_le32(zroot.len); 1668c2ecf20Sopenharmony_ci c->mst_node->ihead_lnum = cpu_to_le32(c->ihead_lnum); 1678c2ecf20Sopenharmony_ci c->mst_node->ihead_offs = cpu_to_le32(c->ihead_offs); 1688c2ecf20Sopenharmony_ci c->mst_node->index_size = cpu_to_le64(c->bi.old_idx_sz); 1698c2ecf20Sopenharmony_ci c->mst_node->lpt_lnum = cpu_to_le32(c->lpt_lnum); 1708c2ecf20Sopenharmony_ci c->mst_node->lpt_offs = cpu_to_le32(c->lpt_offs); 1718c2ecf20Sopenharmony_ci c->mst_node->nhead_lnum = cpu_to_le32(c->nhead_lnum); 1728c2ecf20Sopenharmony_ci c->mst_node->nhead_offs = cpu_to_le32(c->nhead_offs); 1738c2ecf20Sopenharmony_ci c->mst_node->ltab_lnum = cpu_to_le32(c->ltab_lnum); 1748c2ecf20Sopenharmony_ci c->mst_node->ltab_offs = cpu_to_le32(c->ltab_offs); 1758c2ecf20Sopenharmony_ci c->mst_node->lsave_lnum = cpu_to_le32(c->lsave_lnum); 1768c2ecf20Sopenharmony_ci c->mst_node->lsave_offs = cpu_to_le32(c->lsave_offs); 1778c2ecf20Sopenharmony_ci c->mst_node->lscan_lnum = cpu_to_le32(c->lscan_lnum); 1788c2ecf20Sopenharmony_ci c->mst_node->empty_lebs = cpu_to_le32(lst.empty_lebs); 1798c2ecf20Sopenharmony_ci c->mst_node->idx_lebs = cpu_to_le32(lst.idx_lebs); 1808c2ecf20Sopenharmony_ci c->mst_node->total_free = cpu_to_le64(lst.total_free); 1818c2ecf20Sopenharmony_ci c->mst_node->total_dirty = cpu_to_le64(lst.total_dirty); 1828c2ecf20Sopenharmony_ci c->mst_node->total_used = cpu_to_le64(lst.total_used); 1838c2ecf20Sopenharmony_ci c->mst_node->total_dead = cpu_to_le64(lst.total_dead); 1848c2ecf20Sopenharmony_ci c->mst_node->total_dark = cpu_to_le64(lst.total_dark); 1858c2ecf20Sopenharmony_ci if (c->no_orphs) 1868c2ecf20Sopenharmony_ci c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS); 1878c2ecf20Sopenharmony_ci else 1888c2ecf20Sopenharmony_ci c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_NO_ORPHS); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci old_ltail_lnum = c->ltail_lnum; 1918c2ecf20Sopenharmony_ci err = ubifs_log_end_commit(c, new_ltail_lnum); 1928c2ecf20Sopenharmony_ci if (err) 1938c2ecf20Sopenharmony_ci goto out; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci err = ubifs_log_post_commit(c, old_ltail_lnum); 1968c2ecf20Sopenharmony_ci if (err) 1978c2ecf20Sopenharmony_ci goto out; 1988c2ecf20Sopenharmony_ci err = ubifs_gc_end_commit(c); 1998c2ecf20Sopenharmony_ci if (err) 2008c2ecf20Sopenharmony_ci goto out; 2018c2ecf20Sopenharmony_ci err = ubifs_lpt_post_commit(c); 2028c2ecf20Sopenharmony_ci if (err) 2038c2ecf20Sopenharmony_ci goto out; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ciout_cancel: 2068c2ecf20Sopenharmony_ci spin_lock(&c->cs_lock); 2078c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_RESTING; 2088c2ecf20Sopenharmony_ci wake_up(&c->cmt_wq); 2098c2ecf20Sopenharmony_ci dbg_cmt("commit end"); 2108c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 2118c2ecf20Sopenharmony_ci return 0; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ciout_up: 2148c2ecf20Sopenharmony_ci up_write(&c->commit_sem); 2158c2ecf20Sopenharmony_ciout: 2168c2ecf20Sopenharmony_ci ubifs_err(c, "commit failed, error %d", err); 2178c2ecf20Sopenharmony_ci spin_lock(&c->cs_lock); 2188c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_BROKEN; 2198c2ecf20Sopenharmony_ci wake_up(&c->cmt_wq); 2208c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 2218c2ecf20Sopenharmony_ci ubifs_ro_mode(c, err); 2228c2ecf20Sopenharmony_ci return err; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/** 2268c2ecf20Sopenharmony_ci * run_bg_commit - run background commit if it is needed. 2278c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 2288c2ecf20Sopenharmony_ci * 2298c2ecf20Sopenharmony_ci * This function runs background commit if it is needed. Returns zero in case 2308c2ecf20Sopenharmony_ci * of success and a negative error code in case of failure. 2318c2ecf20Sopenharmony_ci */ 2328c2ecf20Sopenharmony_cistatic int run_bg_commit(struct ubifs_info *c) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci spin_lock(&c->cs_lock); 2358c2ecf20Sopenharmony_ci /* 2368c2ecf20Sopenharmony_ci * Run background commit only if background commit was requested or if 2378c2ecf20Sopenharmony_ci * commit is required. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci if (c->cmt_state != COMMIT_BACKGROUND && 2408c2ecf20Sopenharmony_ci c->cmt_state != COMMIT_REQUIRED) 2418c2ecf20Sopenharmony_ci goto out; 2428c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci down_write(&c->commit_sem); 2458c2ecf20Sopenharmony_ci spin_lock(&c->cs_lock); 2468c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_REQUIRED) 2478c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_RUNNING_REQUIRED; 2488c2ecf20Sopenharmony_ci else if (c->cmt_state == COMMIT_BACKGROUND) 2498c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_RUNNING_BACKGROUND; 2508c2ecf20Sopenharmony_ci else 2518c2ecf20Sopenharmony_ci goto out_cmt_unlock; 2528c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return do_commit(c); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciout_cmt_unlock: 2578c2ecf20Sopenharmony_ci up_write(&c->commit_sem); 2588c2ecf20Sopenharmony_ciout: 2598c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/** 2648c2ecf20Sopenharmony_ci * ubifs_bg_thread - UBIFS background thread function. 2658c2ecf20Sopenharmony_ci * @info: points to the file-system description object 2668c2ecf20Sopenharmony_ci * 2678c2ecf20Sopenharmony_ci * This function implements various file-system background activities: 2688c2ecf20Sopenharmony_ci * o when a write-buffer timer expires it synchronizes the appropriate 2698c2ecf20Sopenharmony_ci * write-buffer; 2708c2ecf20Sopenharmony_ci * o when the journal is about to be full, it starts in-advance commit. 2718c2ecf20Sopenharmony_ci * 2728c2ecf20Sopenharmony_ci * Note, other stuff like background garbage collection may be added here in 2738c2ecf20Sopenharmony_ci * future. 2748c2ecf20Sopenharmony_ci */ 2758c2ecf20Sopenharmony_ciint ubifs_bg_thread(void *info) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci int err; 2788c2ecf20Sopenharmony_ci struct ubifs_info *c = info; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ubifs_msg(c, "background thread \"%s\" started, PID %d", 2818c2ecf20Sopenharmony_ci c->bgt_name, current->pid); 2828c2ecf20Sopenharmony_ci set_freezable(); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci while (1) { 2858c2ecf20Sopenharmony_ci if (kthread_should_stop()) 2868c2ecf20Sopenharmony_ci break; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (try_to_freeze()) 2898c2ecf20Sopenharmony_ci continue; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 2928c2ecf20Sopenharmony_ci /* Check if there is something to do */ 2938c2ecf20Sopenharmony_ci if (!c->need_bgt) { 2948c2ecf20Sopenharmony_ci /* 2958c2ecf20Sopenharmony_ci * Nothing prevents us from going sleep now and 2968c2ecf20Sopenharmony_ci * be never woken up and block the task which 2978c2ecf20Sopenharmony_ci * could wait in 'kthread_stop()' forever. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci if (kthread_should_stop()) 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci schedule(); 3028c2ecf20Sopenharmony_ci continue; 3038c2ecf20Sopenharmony_ci } else 3048c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci c->need_bgt = 0; 3078c2ecf20Sopenharmony_ci err = ubifs_bg_wbufs_sync(c); 3088c2ecf20Sopenharmony_ci if (err) 3098c2ecf20Sopenharmony_ci ubifs_ro_mode(c, err); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci run_bg_commit(c); 3128c2ecf20Sopenharmony_ci cond_resched(); 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci ubifs_msg(c, "background thread \"%s\" stops", c->bgt_name); 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/** 3208c2ecf20Sopenharmony_ci * ubifs_commit_required - set commit state to "required". 3218c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3228c2ecf20Sopenharmony_ci * 3238c2ecf20Sopenharmony_ci * This function is called if a commit is required but cannot be done from the 3248c2ecf20Sopenharmony_ci * calling function, so it is just flagged instead. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_civoid ubifs_commit_required(struct ubifs_info *c) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci spin_lock(&c->cs_lock); 3298c2ecf20Sopenharmony_ci switch (c->cmt_state) { 3308c2ecf20Sopenharmony_ci case COMMIT_RESTING: 3318c2ecf20Sopenharmony_ci case COMMIT_BACKGROUND: 3328c2ecf20Sopenharmony_ci dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state), 3338c2ecf20Sopenharmony_ci dbg_cstate(COMMIT_REQUIRED)); 3348c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_REQUIRED; 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case COMMIT_RUNNING_BACKGROUND: 3378c2ecf20Sopenharmony_ci dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state), 3388c2ecf20Sopenharmony_ci dbg_cstate(COMMIT_RUNNING_REQUIRED)); 3398c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_RUNNING_REQUIRED; 3408c2ecf20Sopenharmony_ci break; 3418c2ecf20Sopenharmony_ci case COMMIT_REQUIRED: 3428c2ecf20Sopenharmony_ci case COMMIT_RUNNING_REQUIRED: 3438c2ecf20Sopenharmony_ci case COMMIT_BROKEN: 3448c2ecf20Sopenharmony_ci break; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci/** 3508c2ecf20Sopenharmony_ci * ubifs_request_bg_commit - notify the background thread to do a commit. 3518c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3528c2ecf20Sopenharmony_ci * 3538c2ecf20Sopenharmony_ci * This function is called if the journal is full enough to make a commit 3548c2ecf20Sopenharmony_ci * worthwhile, so background thread is kicked to start it. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_civoid ubifs_request_bg_commit(struct ubifs_info *c) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci spin_lock(&c->cs_lock); 3598c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_RESTING) { 3608c2ecf20Sopenharmony_ci dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state), 3618c2ecf20Sopenharmony_ci dbg_cstate(COMMIT_BACKGROUND)); 3628c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_BACKGROUND; 3638c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 3648c2ecf20Sopenharmony_ci ubifs_wake_up_bgt(c); 3658c2ecf20Sopenharmony_ci } else 3668c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci/** 3708c2ecf20Sopenharmony_ci * wait_for_commit - wait for commit. 3718c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3728c2ecf20Sopenharmony_ci * 3738c2ecf20Sopenharmony_ci * This function sleeps until the commit operation is no longer running. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_cistatic int wait_for_commit(struct ubifs_info *c) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci dbg_cmt("pid %d goes sleep", current->pid); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci /* 3808c2ecf20Sopenharmony_ci * The following sleeps if the condition is false, and will be woken 3818c2ecf20Sopenharmony_ci * when the commit ends. It is possible, although very unlikely, that we 3828c2ecf20Sopenharmony_ci * will wake up and see the subsequent commit running, rather than the 3838c2ecf20Sopenharmony_ci * one we were waiting for, and go back to sleep. However, we will be 3848c2ecf20Sopenharmony_ci * woken again, so there is no danger of sleeping forever. 3858c2ecf20Sopenharmony_ci */ 3868c2ecf20Sopenharmony_ci wait_event(c->cmt_wq, c->cmt_state != COMMIT_RUNNING_BACKGROUND && 3878c2ecf20Sopenharmony_ci c->cmt_state != COMMIT_RUNNING_REQUIRED); 3888c2ecf20Sopenharmony_ci dbg_cmt("commit finished, pid %d woke up", current->pid); 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci/** 3938c2ecf20Sopenharmony_ci * ubifs_run_commit - run or wait for commit. 3948c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3958c2ecf20Sopenharmony_ci * 3968c2ecf20Sopenharmony_ci * This function runs commit and returns zero in case of success and a negative 3978c2ecf20Sopenharmony_ci * error code in case of failure. 3988c2ecf20Sopenharmony_ci */ 3998c2ecf20Sopenharmony_ciint ubifs_run_commit(struct ubifs_info *c) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci int err = 0; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci spin_lock(&c->cs_lock); 4048c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_BROKEN) { 4058c2ecf20Sopenharmony_ci err = -EROFS; 4068c2ecf20Sopenharmony_ci goto out; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_RUNNING_BACKGROUND) 4108c2ecf20Sopenharmony_ci /* 4118c2ecf20Sopenharmony_ci * We set the commit state to 'running required' to indicate 4128c2ecf20Sopenharmony_ci * that we want it to complete as quickly as possible. 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_RUNNING_REQUIRED; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_RUNNING_REQUIRED) { 4178c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 4188c2ecf20Sopenharmony_ci return wait_for_commit(c); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* Ok, the commit is indeed needed */ 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci down_write(&c->commit_sem); 4258c2ecf20Sopenharmony_ci spin_lock(&c->cs_lock); 4268c2ecf20Sopenharmony_ci /* 4278c2ecf20Sopenharmony_ci * Since we unlocked 'c->cs_lock', the state may have changed, so 4288c2ecf20Sopenharmony_ci * re-check it. 4298c2ecf20Sopenharmony_ci */ 4308c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_BROKEN) { 4318c2ecf20Sopenharmony_ci err = -EROFS; 4328c2ecf20Sopenharmony_ci goto out_cmt_unlock; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_RUNNING_BACKGROUND) 4368c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_RUNNING_REQUIRED; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_RUNNING_REQUIRED) { 4398c2ecf20Sopenharmony_ci up_write(&c->commit_sem); 4408c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 4418c2ecf20Sopenharmony_ci return wait_for_commit(c); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_RUNNING_REQUIRED; 4448c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci err = do_commit(c); 4478c2ecf20Sopenharmony_ci return err; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ciout_cmt_unlock: 4508c2ecf20Sopenharmony_ci up_write(&c->commit_sem); 4518c2ecf20Sopenharmony_ciout: 4528c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 4538c2ecf20Sopenharmony_ci return err; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci/** 4578c2ecf20Sopenharmony_ci * ubifs_gc_should_commit - determine if it is time for GC to run commit. 4588c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 4598c2ecf20Sopenharmony_ci * 4608c2ecf20Sopenharmony_ci * This function is called by garbage collection to determine if commit should 4618c2ecf20Sopenharmony_ci * be run. If commit state is @COMMIT_BACKGROUND, which means that the journal 4628c2ecf20Sopenharmony_ci * is full enough to start commit, this function returns true. It is not 4638c2ecf20Sopenharmony_ci * absolutely necessary to commit yet, but it feels like this should be better 4648c2ecf20Sopenharmony_ci * then to keep doing GC. This function returns %1 if GC has to initiate commit 4658c2ecf20Sopenharmony_ci * and %0 if not. 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_ciint ubifs_gc_should_commit(struct ubifs_info *c) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci int ret = 0; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci spin_lock(&c->cs_lock); 4728c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_BACKGROUND) { 4738c2ecf20Sopenharmony_ci dbg_cmt("commit required now"); 4748c2ecf20Sopenharmony_ci c->cmt_state = COMMIT_REQUIRED; 4758c2ecf20Sopenharmony_ci } else 4768c2ecf20Sopenharmony_ci dbg_cmt("commit not requested"); 4778c2ecf20Sopenharmony_ci if (c->cmt_state == COMMIT_REQUIRED) 4788c2ecf20Sopenharmony_ci ret = 1; 4798c2ecf20Sopenharmony_ci spin_unlock(&c->cs_lock); 4808c2ecf20Sopenharmony_ci return ret; 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci/* 4848c2ecf20Sopenharmony_ci * Everything below is related to debugging. 4858c2ecf20Sopenharmony_ci */ 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci/** 4888c2ecf20Sopenharmony_ci * struct idx_node - hold index nodes during index tree traversal. 4898c2ecf20Sopenharmony_ci * @list: list 4908c2ecf20Sopenharmony_ci * @iip: index in parent (slot number of this indexing node in the parent 4918c2ecf20Sopenharmony_ci * indexing node) 4928c2ecf20Sopenharmony_ci * @upper_key: all keys in this indexing node have to be less or equivalent to 4938c2ecf20Sopenharmony_ci * this key 4948c2ecf20Sopenharmony_ci * @idx: index node (8-byte aligned because all node structures must be 8-byte 4958c2ecf20Sopenharmony_ci * aligned) 4968c2ecf20Sopenharmony_ci */ 4978c2ecf20Sopenharmony_cistruct idx_node { 4988c2ecf20Sopenharmony_ci struct list_head list; 4998c2ecf20Sopenharmony_ci int iip; 5008c2ecf20Sopenharmony_ci union ubifs_key upper_key; 5018c2ecf20Sopenharmony_ci struct ubifs_idx_node idx __aligned(8); 5028c2ecf20Sopenharmony_ci}; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci/** 5058c2ecf20Sopenharmony_ci * dbg_old_index_check_init - get information for the next old index check. 5068c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5078c2ecf20Sopenharmony_ci * @zroot: root of the index 5088c2ecf20Sopenharmony_ci * 5098c2ecf20Sopenharmony_ci * This function records information about the index that will be needed for the 5108c2ecf20Sopenharmony_ci * next old index check i.e. 'dbg_check_old_index()'. 5118c2ecf20Sopenharmony_ci * 5128c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ciint dbg_old_index_check_init(struct ubifs_info *c, struct ubifs_zbranch *zroot) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci struct ubifs_idx_node *idx; 5178c2ecf20Sopenharmony_ci int lnum, offs, len, err = 0; 5188c2ecf20Sopenharmony_ci struct ubifs_debug_info *d = c->dbg; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci d->old_zroot = *zroot; 5218c2ecf20Sopenharmony_ci lnum = d->old_zroot.lnum; 5228c2ecf20Sopenharmony_ci offs = d->old_zroot.offs; 5238c2ecf20Sopenharmony_ci len = d->old_zroot.len; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci idx = kmalloc(c->max_idx_node_sz, GFP_NOFS); 5268c2ecf20Sopenharmony_ci if (!idx) 5278c2ecf20Sopenharmony_ci return -ENOMEM; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); 5308c2ecf20Sopenharmony_ci if (err) 5318c2ecf20Sopenharmony_ci goto out; 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci d->old_zroot_level = le16_to_cpu(idx->level); 5348c2ecf20Sopenharmony_ci d->old_zroot_sqnum = le64_to_cpu(idx->ch.sqnum); 5358c2ecf20Sopenharmony_ciout: 5368c2ecf20Sopenharmony_ci kfree(idx); 5378c2ecf20Sopenharmony_ci return err; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci/** 5418c2ecf20Sopenharmony_ci * dbg_check_old_index - check the old copy of the index. 5428c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5438c2ecf20Sopenharmony_ci * @zroot: root of the new index 5448c2ecf20Sopenharmony_ci * 5458c2ecf20Sopenharmony_ci * In order to be able to recover from an unclean unmount, a complete copy of 5468c2ecf20Sopenharmony_ci * the index must exist on flash. This is the "old" index. The commit process 5478c2ecf20Sopenharmony_ci * must write the "new" index to flash without overwriting or destroying any 5488c2ecf20Sopenharmony_ci * part of the old index. This function is run at commit end in order to check 5498c2ecf20Sopenharmony_ci * that the old index does indeed exist completely intact. 5508c2ecf20Sopenharmony_ci * 5518c2ecf20Sopenharmony_ci * This function returns %0 on success and a negative error code on failure. 5528c2ecf20Sopenharmony_ci */ 5538c2ecf20Sopenharmony_ciint dbg_check_old_index(struct ubifs_info *c, struct ubifs_zbranch *zroot) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci int lnum, offs, len, err = 0, last_level, child_cnt; 5568c2ecf20Sopenharmony_ci int first = 1, iip; 5578c2ecf20Sopenharmony_ci struct ubifs_debug_info *d = c->dbg; 5588c2ecf20Sopenharmony_ci union ubifs_key lower_key, upper_key, l_key, u_key; 5598c2ecf20Sopenharmony_ci unsigned long long last_sqnum; 5608c2ecf20Sopenharmony_ci struct ubifs_idx_node *idx; 5618c2ecf20Sopenharmony_ci struct list_head list; 5628c2ecf20Sopenharmony_ci struct idx_node *i; 5638c2ecf20Sopenharmony_ci size_t sz; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci if (!dbg_is_chk_index(c)) 5668c2ecf20Sopenharmony_ci return 0; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&list); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci sz = sizeof(struct idx_node) + ubifs_idx_node_sz(c, c->fanout) - 5718c2ecf20Sopenharmony_ci UBIFS_IDX_NODE_SZ; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* Start at the old zroot */ 5748c2ecf20Sopenharmony_ci lnum = d->old_zroot.lnum; 5758c2ecf20Sopenharmony_ci offs = d->old_zroot.offs; 5768c2ecf20Sopenharmony_ci len = d->old_zroot.len; 5778c2ecf20Sopenharmony_ci iip = 0; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* 5808c2ecf20Sopenharmony_ci * Traverse the index tree preorder depth-first i.e. do a node and then 5818c2ecf20Sopenharmony_ci * its subtrees from left to right. 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ci while (1) { 5848c2ecf20Sopenharmony_ci struct ubifs_branch *br; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci /* Get the next index node */ 5878c2ecf20Sopenharmony_ci i = kmalloc(sz, GFP_NOFS); 5888c2ecf20Sopenharmony_ci if (!i) { 5898c2ecf20Sopenharmony_ci err = -ENOMEM; 5908c2ecf20Sopenharmony_ci goto out_free; 5918c2ecf20Sopenharmony_ci } 5928c2ecf20Sopenharmony_ci i->iip = iip; 5938c2ecf20Sopenharmony_ci /* Keep the index nodes on our path in a linked list */ 5948c2ecf20Sopenharmony_ci list_add_tail(&i->list, &list); 5958c2ecf20Sopenharmony_ci /* Read the index node */ 5968c2ecf20Sopenharmony_ci idx = &i->idx; 5978c2ecf20Sopenharmony_ci err = ubifs_read_node(c, idx, UBIFS_IDX_NODE, len, lnum, offs); 5988c2ecf20Sopenharmony_ci if (err) 5998c2ecf20Sopenharmony_ci goto out_free; 6008c2ecf20Sopenharmony_ci /* Validate index node */ 6018c2ecf20Sopenharmony_ci child_cnt = le16_to_cpu(idx->child_cnt); 6028c2ecf20Sopenharmony_ci if (child_cnt < 1 || child_cnt > c->fanout) { 6038c2ecf20Sopenharmony_ci err = 1; 6048c2ecf20Sopenharmony_ci goto out_dump; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci if (first) { 6078c2ecf20Sopenharmony_ci first = 0; 6088c2ecf20Sopenharmony_ci /* Check root level and sqnum */ 6098c2ecf20Sopenharmony_ci if (le16_to_cpu(idx->level) != d->old_zroot_level) { 6108c2ecf20Sopenharmony_ci err = 2; 6118c2ecf20Sopenharmony_ci goto out_dump; 6128c2ecf20Sopenharmony_ci } 6138c2ecf20Sopenharmony_ci if (le64_to_cpu(idx->ch.sqnum) != d->old_zroot_sqnum) { 6148c2ecf20Sopenharmony_ci err = 3; 6158c2ecf20Sopenharmony_ci goto out_dump; 6168c2ecf20Sopenharmony_ci } 6178c2ecf20Sopenharmony_ci /* Set last values as though root had a parent */ 6188c2ecf20Sopenharmony_ci last_level = le16_to_cpu(idx->level) + 1; 6198c2ecf20Sopenharmony_ci last_sqnum = le64_to_cpu(idx->ch.sqnum) + 1; 6208c2ecf20Sopenharmony_ci key_read(c, ubifs_idx_key(c, idx), &lower_key); 6218c2ecf20Sopenharmony_ci highest_ino_key(c, &upper_key, INUM_WATERMARK); 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci key_copy(c, &upper_key, &i->upper_key); 6248c2ecf20Sopenharmony_ci if (le16_to_cpu(idx->level) != last_level - 1) { 6258c2ecf20Sopenharmony_ci err = 3; 6268c2ecf20Sopenharmony_ci goto out_dump; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci /* 6298c2ecf20Sopenharmony_ci * The index is always written bottom up hence a child's sqnum 6308c2ecf20Sopenharmony_ci * is always less than the parents. 6318c2ecf20Sopenharmony_ci */ 6328c2ecf20Sopenharmony_ci if (le64_to_cpu(idx->ch.sqnum) >= last_sqnum) { 6338c2ecf20Sopenharmony_ci err = 4; 6348c2ecf20Sopenharmony_ci goto out_dump; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci /* Check key range */ 6378c2ecf20Sopenharmony_ci key_read(c, ubifs_idx_key(c, idx), &l_key); 6388c2ecf20Sopenharmony_ci br = ubifs_idx_branch(c, idx, child_cnt - 1); 6398c2ecf20Sopenharmony_ci key_read(c, &br->key, &u_key); 6408c2ecf20Sopenharmony_ci if (keys_cmp(c, &lower_key, &l_key) > 0) { 6418c2ecf20Sopenharmony_ci err = 5; 6428c2ecf20Sopenharmony_ci goto out_dump; 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci if (keys_cmp(c, &upper_key, &u_key) < 0) { 6458c2ecf20Sopenharmony_ci err = 6; 6468c2ecf20Sopenharmony_ci goto out_dump; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci if (keys_cmp(c, &upper_key, &u_key) == 0) 6498c2ecf20Sopenharmony_ci if (!is_hash_key(c, &u_key)) { 6508c2ecf20Sopenharmony_ci err = 7; 6518c2ecf20Sopenharmony_ci goto out_dump; 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci /* Go to next index node */ 6548c2ecf20Sopenharmony_ci if (le16_to_cpu(idx->level) == 0) { 6558c2ecf20Sopenharmony_ci /* At the bottom, so go up until can go right */ 6568c2ecf20Sopenharmony_ci while (1) { 6578c2ecf20Sopenharmony_ci /* Drop the bottom of the list */ 6588c2ecf20Sopenharmony_ci list_del(&i->list); 6598c2ecf20Sopenharmony_ci kfree(i); 6608c2ecf20Sopenharmony_ci /* No more list means we are done */ 6618c2ecf20Sopenharmony_ci if (list_empty(&list)) 6628c2ecf20Sopenharmony_ci goto out; 6638c2ecf20Sopenharmony_ci /* Look at the new bottom */ 6648c2ecf20Sopenharmony_ci i = list_entry(list.prev, struct idx_node, 6658c2ecf20Sopenharmony_ci list); 6668c2ecf20Sopenharmony_ci idx = &i->idx; 6678c2ecf20Sopenharmony_ci /* Can we go right */ 6688c2ecf20Sopenharmony_ci if (iip + 1 < le16_to_cpu(idx->child_cnt)) { 6698c2ecf20Sopenharmony_ci iip = iip + 1; 6708c2ecf20Sopenharmony_ci break; 6718c2ecf20Sopenharmony_ci } else 6728c2ecf20Sopenharmony_ci /* Nope, so go up again */ 6738c2ecf20Sopenharmony_ci iip = i->iip; 6748c2ecf20Sopenharmony_ci } 6758c2ecf20Sopenharmony_ci } else 6768c2ecf20Sopenharmony_ci /* Go down left */ 6778c2ecf20Sopenharmony_ci iip = 0; 6788c2ecf20Sopenharmony_ci /* 6798c2ecf20Sopenharmony_ci * We have the parent in 'idx' and now we set up for reading the 6808c2ecf20Sopenharmony_ci * child pointed to by slot 'iip'. 6818c2ecf20Sopenharmony_ci */ 6828c2ecf20Sopenharmony_ci last_level = le16_to_cpu(idx->level); 6838c2ecf20Sopenharmony_ci last_sqnum = le64_to_cpu(idx->ch.sqnum); 6848c2ecf20Sopenharmony_ci br = ubifs_idx_branch(c, idx, iip); 6858c2ecf20Sopenharmony_ci lnum = le32_to_cpu(br->lnum); 6868c2ecf20Sopenharmony_ci offs = le32_to_cpu(br->offs); 6878c2ecf20Sopenharmony_ci len = le32_to_cpu(br->len); 6888c2ecf20Sopenharmony_ci key_read(c, &br->key, &lower_key); 6898c2ecf20Sopenharmony_ci if (iip + 1 < le16_to_cpu(idx->child_cnt)) { 6908c2ecf20Sopenharmony_ci br = ubifs_idx_branch(c, idx, iip + 1); 6918c2ecf20Sopenharmony_ci key_read(c, &br->key, &upper_key); 6928c2ecf20Sopenharmony_ci } else 6938c2ecf20Sopenharmony_ci key_copy(c, &i->upper_key, &upper_key); 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ciout: 6968c2ecf20Sopenharmony_ci err = dbg_old_index_check_init(c, zroot); 6978c2ecf20Sopenharmony_ci if (err) 6988c2ecf20Sopenharmony_ci goto out_free; 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci return 0; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ciout_dump: 7038c2ecf20Sopenharmony_ci ubifs_err(c, "dumping index node (iip=%d)", i->iip); 7048c2ecf20Sopenharmony_ci ubifs_dump_node(c, idx, ubifs_idx_node_sz(c, c->fanout)); 7058c2ecf20Sopenharmony_ci list_del(&i->list); 7068c2ecf20Sopenharmony_ci kfree(i); 7078c2ecf20Sopenharmony_ci if (!list_empty(&list)) { 7088c2ecf20Sopenharmony_ci i = list_entry(list.prev, struct idx_node, list); 7098c2ecf20Sopenharmony_ci ubifs_err(c, "dumping parent index node"); 7108c2ecf20Sopenharmony_ci ubifs_dump_node(c, &i->idx, ubifs_idx_node_sz(c, c->fanout)); 7118c2ecf20Sopenharmony_ci } 7128c2ecf20Sopenharmony_ciout_free: 7138c2ecf20Sopenharmony_ci while (!list_empty(&list)) { 7148c2ecf20Sopenharmony_ci i = list_entry(list.next, struct idx_node, list); 7158c2ecf20Sopenharmony_ci list_del(&i->list); 7168c2ecf20Sopenharmony_ci kfree(i); 7178c2ecf20Sopenharmony_ci } 7188c2ecf20Sopenharmony_ci ubifs_err(c, "failed, error %d", err); 7198c2ecf20Sopenharmony_ci if (err > 0) 7208c2ecf20Sopenharmony_ci err = -EINVAL; 7218c2ecf20Sopenharmony_ci return err; 7228c2ecf20Sopenharmony_ci} 723