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 garbage collection. The procedure for garbage collection 138c2ecf20Sopenharmony_ci * is different depending on whether a LEB as an index LEB (contains index 148c2ecf20Sopenharmony_ci * nodes) or not. For non-index LEBs, garbage collection finds a LEB which 158c2ecf20Sopenharmony_ci * contains a lot of dirty space (obsolete nodes), and copies the non-obsolete 168c2ecf20Sopenharmony_ci * nodes to the journal, at which point the garbage-collected LEB is free to be 178c2ecf20Sopenharmony_ci * reused. For index LEBs, garbage collection marks the non-obsolete index nodes 188c2ecf20Sopenharmony_ci * dirty in the TNC, and after the next commit, the garbage-collected LEB is 198c2ecf20Sopenharmony_ci * to be reused. Garbage collection will cause the number of dirty index nodes 208c2ecf20Sopenharmony_ci * to grow, however sufficient space is reserved for the index to ensure the 218c2ecf20Sopenharmony_ci * commit will never run out of space. 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Notes about dead watermark. At current UBIFS implementation we assume that 248c2ecf20Sopenharmony_ci * LEBs which have less than @c->dead_wm bytes of free + dirty space are full 258c2ecf20Sopenharmony_ci * and not worth garbage-collecting. The dead watermark is one min. I/O unit 268c2ecf20Sopenharmony_ci * size, or min. UBIFS node size, depending on what is greater. Indeed, UBIFS 278c2ecf20Sopenharmony_ci * Garbage Collector has to synchronize the GC head's write buffer before 288c2ecf20Sopenharmony_ci * returning, so this is about wasting one min. I/O unit. However, UBIFS GC can 298c2ecf20Sopenharmony_ci * actually reclaim even very small pieces of dirty space by garbage collecting 308c2ecf20Sopenharmony_ci * enough dirty LEBs, but we do not bother doing this at this implementation. 318c2ecf20Sopenharmony_ci * 328c2ecf20Sopenharmony_ci * Notes about dark watermark. The results of GC work depends on how big are 338c2ecf20Sopenharmony_ci * the UBIFS nodes GC deals with. Large nodes make GC waste more space. Indeed, 348c2ecf20Sopenharmony_ci * if GC move data from LEB A to LEB B and nodes in LEB A are large, GC would 358c2ecf20Sopenharmony_ci * have to waste large pieces of free space at the end of LEB B, because nodes 368c2ecf20Sopenharmony_ci * from LEB A would not fit. And the worst situation is when all nodes are of 378c2ecf20Sopenharmony_ci * maximum size. So dark watermark is the amount of free + dirty space in LEB 388c2ecf20Sopenharmony_ci * which are guaranteed to be reclaimable. If LEB has less space, the GC might 398c2ecf20Sopenharmony_ci * be unable to reclaim it. So, LEBs with free + dirty greater than dark 408c2ecf20Sopenharmony_ci * watermark are "good" LEBs from GC's point of view. The other LEBs are not so 418c2ecf20Sopenharmony_ci * good, and GC takes extra care when moving them. 428c2ecf20Sopenharmony_ci */ 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#include <linux/slab.h> 458c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 468c2ecf20Sopenharmony_ci#include <linux/list_sort.h> 478c2ecf20Sopenharmony_ci#include "ubifs.h" 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * GC may need to move more than one LEB to make progress. The below constants 518c2ecf20Sopenharmony_ci * define "soft" and "hard" limits on the number of LEBs the garbage collector 528c2ecf20Sopenharmony_ci * may move. 538c2ecf20Sopenharmony_ci */ 548c2ecf20Sopenharmony_ci#define SOFT_LEBS_LIMIT 4 558c2ecf20Sopenharmony_ci#define HARD_LEBS_LIMIT 32 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/** 588c2ecf20Sopenharmony_ci * switch_gc_head - switch the garbage collection journal head. 598c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * This function switch the GC head to the next LEB which is reserved in 628c2ecf20Sopenharmony_ci * @c->gc_lnum. Returns %0 in case of success, %-EAGAIN if commit is required, 638c2ecf20Sopenharmony_ci * and other negative error code in case of failures. 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistatic int switch_gc_head(struct ubifs_info *c) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci int err, gc_lnum = c->gc_lnum; 688c2ecf20Sopenharmony_ci struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci ubifs_assert(c, gc_lnum != -1); 718c2ecf20Sopenharmony_ci dbg_gc("switch GC head from LEB %d:%d to LEB %d (waste %d bytes)", 728c2ecf20Sopenharmony_ci wbuf->lnum, wbuf->offs + wbuf->used, gc_lnum, 738c2ecf20Sopenharmony_ci c->leb_size - wbuf->offs - wbuf->used); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci err = ubifs_wbuf_sync_nolock(wbuf); 768c2ecf20Sopenharmony_ci if (err) 778c2ecf20Sopenharmony_ci return err; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* 808c2ecf20Sopenharmony_ci * The GC write-buffer was synchronized, we may safely unmap 818c2ecf20Sopenharmony_ci * 'c->gc_lnum'. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, gc_lnum); 848c2ecf20Sopenharmony_ci if (err) 858c2ecf20Sopenharmony_ci return err; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci err = ubifs_add_bud_to_log(c, GCHD, gc_lnum, 0); 888c2ecf20Sopenharmony_ci if (err) 898c2ecf20Sopenharmony_ci return err; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci c->gc_lnum = -1; 928c2ecf20Sopenharmony_ci err = ubifs_wbuf_seek_nolock(wbuf, gc_lnum, 0); 938c2ecf20Sopenharmony_ci return err; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/** 978c2ecf20Sopenharmony_ci * data_nodes_cmp - compare 2 data nodes. 988c2ecf20Sopenharmony_ci * @priv: UBIFS file-system description object 998c2ecf20Sopenharmony_ci * @a: first data node 1008c2ecf20Sopenharmony_ci * @b: second data node 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * This function compares data nodes @a and @b. Returns %1 if @a has greater 1038c2ecf20Sopenharmony_ci * inode or block number, and %-1 otherwise. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic int data_nodes_cmp(void *priv, const struct list_head *a, 1068c2ecf20Sopenharmony_ci const struct list_head *b) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci ino_t inuma, inumb; 1098c2ecf20Sopenharmony_ci struct ubifs_info *c = priv; 1108c2ecf20Sopenharmony_ci struct ubifs_scan_node *sa, *sb; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci cond_resched(); 1138c2ecf20Sopenharmony_ci if (a == b) 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci sa = list_entry(a, struct ubifs_scan_node, list); 1178c2ecf20Sopenharmony_ci sb = list_entry(b, struct ubifs_scan_node, list); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci ubifs_assert(c, key_type(c, &sa->key) == UBIFS_DATA_KEY); 1208c2ecf20Sopenharmony_ci ubifs_assert(c, key_type(c, &sb->key) == UBIFS_DATA_KEY); 1218c2ecf20Sopenharmony_ci ubifs_assert(c, sa->type == UBIFS_DATA_NODE); 1228c2ecf20Sopenharmony_ci ubifs_assert(c, sb->type == UBIFS_DATA_NODE); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci inuma = key_inum(c, &sa->key); 1258c2ecf20Sopenharmony_ci inumb = key_inum(c, &sb->key); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (inuma == inumb) { 1288c2ecf20Sopenharmony_ci unsigned int blka = key_block(c, &sa->key); 1298c2ecf20Sopenharmony_ci unsigned int blkb = key_block(c, &sb->key); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (blka <= blkb) 1328c2ecf20Sopenharmony_ci return -1; 1338c2ecf20Sopenharmony_ci } else if (inuma <= inumb) 1348c2ecf20Sopenharmony_ci return -1; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 1; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* 1408c2ecf20Sopenharmony_ci * nondata_nodes_cmp - compare 2 non-data nodes. 1418c2ecf20Sopenharmony_ci * @priv: UBIFS file-system description object 1428c2ecf20Sopenharmony_ci * @a: first node 1438c2ecf20Sopenharmony_ci * @a: second node 1448c2ecf20Sopenharmony_ci * 1458c2ecf20Sopenharmony_ci * This function compares nodes @a and @b. It makes sure that inode nodes go 1468c2ecf20Sopenharmony_ci * first and sorted by length in descending order. Directory entry nodes go 1478c2ecf20Sopenharmony_ci * after inode nodes and are sorted in ascending hash valuer order. 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistatic int nondata_nodes_cmp(void *priv, const struct list_head *a, 1508c2ecf20Sopenharmony_ci const struct list_head *b) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci ino_t inuma, inumb; 1538c2ecf20Sopenharmony_ci struct ubifs_info *c = priv; 1548c2ecf20Sopenharmony_ci struct ubifs_scan_node *sa, *sb; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci cond_resched(); 1578c2ecf20Sopenharmony_ci if (a == b) 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci sa = list_entry(a, struct ubifs_scan_node, list); 1618c2ecf20Sopenharmony_ci sb = list_entry(b, struct ubifs_scan_node, list); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci ubifs_assert(c, key_type(c, &sa->key) != UBIFS_DATA_KEY && 1648c2ecf20Sopenharmony_ci key_type(c, &sb->key) != UBIFS_DATA_KEY); 1658c2ecf20Sopenharmony_ci ubifs_assert(c, sa->type != UBIFS_DATA_NODE && 1668c2ecf20Sopenharmony_ci sb->type != UBIFS_DATA_NODE); 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci /* Inodes go before directory entries */ 1698c2ecf20Sopenharmony_ci if (sa->type == UBIFS_INO_NODE) { 1708c2ecf20Sopenharmony_ci if (sb->type == UBIFS_INO_NODE) 1718c2ecf20Sopenharmony_ci return sb->len - sa->len; 1728c2ecf20Sopenharmony_ci return -1; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci if (sb->type == UBIFS_INO_NODE) 1758c2ecf20Sopenharmony_ci return 1; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci ubifs_assert(c, key_type(c, &sa->key) == UBIFS_DENT_KEY || 1788c2ecf20Sopenharmony_ci key_type(c, &sa->key) == UBIFS_XENT_KEY); 1798c2ecf20Sopenharmony_ci ubifs_assert(c, key_type(c, &sb->key) == UBIFS_DENT_KEY || 1808c2ecf20Sopenharmony_ci key_type(c, &sb->key) == UBIFS_XENT_KEY); 1818c2ecf20Sopenharmony_ci ubifs_assert(c, sa->type == UBIFS_DENT_NODE || 1828c2ecf20Sopenharmony_ci sa->type == UBIFS_XENT_NODE); 1838c2ecf20Sopenharmony_ci ubifs_assert(c, sb->type == UBIFS_DENT_NODE || 1848c2ecf20Sopenharmony_ci sb->type == UBIFS_XENT_NODE); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci inuma = key_inum(c, &sa->key); 1878c2ecf20Sopenharmony_ci inumb = key_inum(c, &sb->key); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (inuma == inumb) { 1908c2ecf20Sopenharmony_ci uint32_t hasha = key_hash(c, &sa->key); 1918c2ecf20Sopenharmony_ci uint32_t hashb = key_hash(c, &sb->key); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci if (hasha <= hashb) 1948c2ecf20Sopenharmony_ci return -1; 1958c2ecf20Sopenharmony_ci } else if (inuma <= inumb) 1968c2ecf20Sopenharmony_ci return -1; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci return 1; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci/** 2028c2ecf20Sopenharmony_ci * sort_nodes - sort nodes for GC. 2038c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 2048c2ecf20Sopenharmony_ci * @sleb: describes nodes to sort and contains the result on exit 2058c2ecf20Sopenharmony_ci * @nondata: contains non-data nodes on exit 2068c2ecf20Sopenharmony_ci * @min: minimum node size is returned here 2078c2ecf20Sopenharmony_ci * 2088c2ecf20Sopenharmony_ci * This function sorts the list of inodes to garbage collect. First of all, it 2098c2ecf20Sopenharmony_ci * kills obsolete nodes and separates data and non-data nodes to the 2108c2ecf20Sopenharmony_ci * @sleb->nodes and @nondata lists correspondingly. 2118c2ecf20Sopenharmony_ci * 2128c2ecf20Sopenharmony_ci * Data nodes are then sorted in block number order - this is important for 2138c2ecf20Sopenharmony_ci * bulk-read; data nodes with lower inode number go before data nodes with 2148c2ecf20Sopenharmony_ci * higher inode number, and data nodes with lower block number go before data 2158c2ecf20Sopenharmony_ci * nodes with higher block number; 2168c2ecf20Sopenharmony_ci * 2178c2ecf20Sopenharmony_ci * Non-data nodes are sorted as follows. 2188c2ecf20Sopenharmony_ci * o First go inode nodes - they are sorted in descending length order. 2198c2ecf20Sopenharmony_ci * o Then go directory entry nodes - they are sorted in hash order, which 2208c2ecf20Sopenharmony_ci * should supposedly optimize 'readdir()'. Direntry nodes with lower parent 2218c2ecf20Sopenharmony_ci * inode number go before direntry nodes with higher parent inode number, 2228c2ecf20Sopenharmony_ci * and direntry nodes with lower name hash values go before direntry nodes 2238c2ecf20Sopenharmony_ci * with higher name hash values. 2248c2ecf20Sopenharmony_ci * 2258c2ecf20Sopenharmony_ci * This function returns zero in case of success and a negative error code in 2268c2ecf20Sopenharmony_ci * case of failure. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb, 2298c2ecf20Sopenharmony_ci struct list_head *nondata, int *min) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int err; 2328c2ecf20Sopenharmony_ci struct ubifs_scan_node *snod, *tmp; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci *min = INT_MAX; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* Separate data nodes and non-data nodes */ 2378c2ecf20Sopenharmony_ci list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) { 2388c2ecf20Sopenharmony_ci ubifs_assert(c, snod->type == UBIFS_INO_NODE || 2398c2ecf20Sopenharmony_ci snod->type == UBIFS_DATA_NODE || 2408c2ecf20Sopenharmony_ci snod->type == UBIFS_DENT_NODE || 2418c2ecf20Sopenharmony_ci snod->type == UBIFS_XENT_NODE || 2428c2ecf20Sopenharmony_ci snod->type == UBIFS_TRUN_NODE || 2438c2ecf20Sopenharmony_ci snod->type == UBIFS_AUTH_NODE); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (snod->type != UBIFS_INO_NODE && 2468c2ecf20Sopenharmony_ci snod->type != UBIFS_DATA_NODE && 2478c2ecf20Sopenharmony_ci snod->type != UBIFS_DENT_NODE && 2488c2ecf20Sopenharmony_ci snod->type != UBIFS_XENT_NODE) { 2498c2ecf20Sopenharmony_ci /* Probably truncation node, zap it */ 2508c2ecf20Sopenharmony_ci list_del(&snod->list); 2518c2ecf20Sopenharmony_ci kfree(snod); 2528c2ecf20Sopenharmony_ci continue; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ubifs_assert(c, key_type(c, &snod->key) == UBIFS_DATA_KEY || 2568c2ecf20Sopenharmony_ci key_type(c, &snod->key) == UBIFS_INO_KEY || 2578c2ecf20Sopenharmony_ci key_type(c, &snod->key) == UBIFS_DENT_KEY || 2588c2ecf20Sopenharmony_ci key_type(c, &snod->key) == UBIFS_XENT_KEY); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci err = ubifs_tnc_has_node(c, &snod->key, 0, sleb->lnum, 2618c2ecf20Sopenharmony_ci snod->offs, 0); 2628c2ecf20Sopenharmony_ci if (err < 0) 2638c2ecf20Sopenharmony_ci return err; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (!err) { 2668c2ecf20Sopenharmony_ci /* The node is obsolete, remove it from the list */ 2678c2ecf20Sopenharmony_ci list_del(&snod->list); 2688c2ecf20Sopenharmony_ci kfree(snod); 2698c2ecf20Sopenharmony_ci continue; 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci if (snod->len < *min) 2738c2ecf20Sopenharmony_ci *min = snod->len; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (key_type(c, &snod->key) != UBIFS_DATA_KEY) 2768c2ecf20Sopenharmony_ci list_move_tail(&snod->list, nondata); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci /* Sort data and non-data nodes */ 2808c2ecf20Sopenharmony_ci list_sort(c, &sleb->nodes, &data_nodes_cmp); 2818c2ecf20Sopenharmony_ci list_sort(c, nondata, &nondata_nodes_cmp); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci err = dbg_check_data_nodes_order(c, &sleb->nodes); 2848c2ecf20Sopenharmony_ci if (err) 2858c2ecf20Sopenharmony_ci return err; 2868c2ecf20Sopenharmony_ci err = dbg_check_nondata_nodes_order(c, nondata); 2878c2ecf20Sopenharmony_ci if (err) 2888c2ecf20Sopenharmony_ci return err; 2898c2ecf20Sopenharmony_ci return 0; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci/** 2938c2ecf20Sopenharmony_ci * move_node - move a node. 2948c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 2958c2ecf20Sopenharmony_ci * @sleb: describes the LEB to move nodes from 2968c2ecf20Sopenharmony_ci * @snod: the mode to move 2978c2ecf20Sopenharmony_ci * @wbuf: write-buffer to move node to 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * This function moves node @snod to @wbuf, changes TNC correspondingly, and 3008c2ecf20Sopenharmony_ci * destroys @snod. Returns zero in case of success and a negative error code in 3018c2ecf20Sopenharmony_ci * case of failure. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_cistatic int move_node(struct ubifs_info *c, struct ubifs_scan_leb *sleb, 3048c2ecf20Sopenharmony_ci struct ubifs_scan_node *snod, struct ubifs_wbuf *wbuf) 3058c2ecf20Sopenharmony_ci{ 3068c2ecf20Sopenharmony_ci int err, new_lnum = wbuf->lnum, new_offs = wbuf->offs + wbuf->used; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci cond_resched(); 3098c2ecf20Sopenharmony_ci err = ubifs_wbuf_write_nolock(wbuf, snod->node, snod->len); 3108c2ecf20Sopenharmony_ci if (err) 3118c2ecf20Sopenharmony_ci return err; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci err = ubifs_tnc_replace(c, &snod->key, sleb->lnum, 3148c2ecf20Sopenharmony_ci snod->offs, new_lnum, new_offs, 3158c2ecf20Sopenharmony_ci snod->len); 3168c2ecf20Sopenharmony_ci list_del(&snod->list); 3178c2ecf20Sopenharmony_ci kfree(snod); 3188c2ecf20Sopenharmony_ci return err; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/** 3228c2ecf20Sopenharmony_ci * move_nodes - move nodes. 3238c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3248c2ecf20Sopenharmony_ci * @sleb: describes the LEB to move nodes from 3258c2ecf20Sopenharmony_ci * 3268c2ecf20Sopenharmony_ci * This function moves valid nodes from data LEB described by @sleb to the GC 3278c2ecf20Sopenharmony_ci * journal head. This function returns zero in case of success, %-EAGAIN if 3288c2ecf20Sopenharmony_ci * commit is required, and other negative error codes in case of other 3298c2ecf20Sopenharmony_ci * failures. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_cistatic int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci int err, min; 3348c2ecf20Sopenharmony_ci LIST_HEAD(nondata); 3358c2ecf20Sopenharmony_ci struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (wbuf->lnum == -1) { 3388c2ecf20Sopenharmony_ci /* 3398c2ecf20Sopenharmony_ci * The GC journal head is not set, because it is the first GC 3408c2ecf20Sopenharmony_ci * invocation since mount. 3418c2ecf20Sopenharmony_ci */ 3428c2ecf20Sopenharmony_ci err = switch_gc_head(c); 3438c2ecf20Sopenharmony_ci if (err) 3448c2ecf20Sopenharmony_ci return err; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci err = sort_nodes(c, sleb, &nondata, &min); 3488c2ecf20Sopenharmony_ci if (err) 3498c2ecf20Sopenharmony_ci goto out; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci /* Write nodes to their new location. Use the first-fit strategy */ 3528c2ecf20Sopenharmony_ci while (1) { 3538c2ecf20Sopenharmony_ci int avail, moved = 0; 3548c2ecf20Sopenharmony_ci struct ubifs_scan_node *snod, *tmp; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* Move data nodes */ 3578c2ecf20Sopenharmony_ci list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) { 3588c2ecf20Sopenharmony_ci avail = c->leb_size - wbuf->offs - wbuf->used - 3598c2ecf20Sopenharmony_ci ubifs_auth_node_sz(c); 3608c2ecf20Sopenharmony_ci if (snod->len > avail) 3618c2ecf20Sopenharmony_ci /* 3628c2ecf20Sopenharmony_ci * Do not skip data nodes in order to optimize 3638c2ecf20Sopenharmony_ci * bulk-read. 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci err = ubifs_shash_update(c, c->jheads[GCHD].log_hash, 3688c2ecf20Sopenharmony_ci snod->node, snod->len); 3698c2ecf20Sopenharmony_ci if (err) 3708c2ecf20Sopenharmony_ci goto out; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci err = move_node(c, sleb, snod, wbuf); 3738c2ecf20Sopenharmony_ci if (err) 3748c2ecf20Sopenharmony_ci goto out; 3758c2ecf20Sopenharmony_ci moved = 1; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci /* Move non-data nodes */ 3798c2ecf20Sopenharmony_ci list_for_each_entry_safe(snod, tmp, &nondata, list) { 3808c2ecf20Sopenharmony_ci avail = c->leb_size - wbuf->offs - wbuf->used - 3818c2ecf20Sopenharmony_ci ubifs_auth_node_sz(c); 3828c2ecf20Sopenharmony_ci if (avail < min) 3838c2ecf20Sopenharmony_ci break; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci if (snod->len > avail) { 3868c2ecf20Sopenharmony_ci /* 3878c2ecf20Sopenharmony_ci * Keep going only if this is an inode with 3888c2ecf20Sopenharmony_ci * some data. Otherwise stop and switch the GC 3898c2ecf20Sopenharmony_ci * head. IOW, we assume that data-less inode 3908c2ecf20Sopenharmony_ci * nodes and direntry nodes are roughly of the 3918c2ecf20Sopenharmony_ci * same size. 3928c2ecf20Sopenharmony_ci */ 3938c2ecf20Sopenharmony_ci if (key_type(c, &snod->key) == UBIFS_DENT_KEY || 3948c2ecf20Sopenharmony_ci snod->len == UBIFS_INO_NODE_SZ) 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci continue; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci err = ubifs_shash_update(c, c->jheads[GCHD].log_hash, 4008c2ecf20Sopenharmony_ci snod->node, snod->len); 4018c2ecf20Sopenharmony_ci if (err) 4028c2ecf20Sopenharmony_ci goto out; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci err = move_node(c, sleb, snod, wbuf); 4058c2ecf20Sopenharmony_ci if (err) 4068c2ecf20Sopenharmony_ci goto out; 4078c2ecf20Sopenharmony_ci moved = 1; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (ubifs_authenticated(c) && moved) { 4118c2ecf20Sopenharmony_ci struct ubifs_auth_node *auth; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci auth = kmalloc(ubifs_auth_node_sz(c), GFP_NOFS); 4148c2ecf20Sopenharmony_ci if (!auth) { 4158c2ecf20Sopenharmony_ci err = -ENOMEM; 4168c2ecf20Sopenharmony_ci goto out; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci err = ubifs_prepare_auth_node(c, auth, 4208c2ecf20Sopenharmony_ci c->jheads[GCHD].log_hash); 4218c2ecf20Sopenharmony_ci if (err) { 4228c2ecf20Sopenharmony_ci kfree(auth); 4238c2ecf20Sopenharmony_ci goto out; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci err = ubifs_wbuf_write_nolock(wbuf, auth, 4278c2ecf20Sopenharmony_ci ubifs_auth_node_sz(c)); 4288c2ecf20Sopenharmony_ci if (err) { 4298c2ecf20Sopenharmony_ci kfree(auth); 4308c2ecf20Sopenharmony_ci goto out; 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci ubifs_add_dirt(c, wbuf->lnum, ubifs_auth_node_sz(c)); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (list_empty(&sleb->nodes) && list_empty(&nondata)) 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* 4408c2ecf20Sopenharmony_ci * Waste the rest of the space in the LEB and switch to the 4418c2ecf20Sopenharmony_ci * next LEB. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci err = switch_gc_head(c); 4448c2ecf20Sopenharmony_ci if (err) 4458c2ecf20Sopenharmony_ci goto out; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return 0; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ciout: 4518c2ecf20Sopenharmony_ci list_splice_tail(&nondata, &sleb->nodes); 4528c2ecf20Sopenharmony_ci return err; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci/** 4568c2ecf20Sopenharmony_ci * gc_sync_wbufs - sync write-buffers for GC. 4578c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 4588c2ecf20Sopenharmony_ci * 4598c2ecf20Sopenharmony_ci * We must guarantee that obsoleting nodes are on flash. Unfortunately they may 4608c2ecf20Sopenharmony_ci * be in a write-buffer instead. That is, a node could be written to a 4618c2ecf20Sopenharmony_ci * write-buffer, obsoleting another node in a LEB that is GC'd. If that LEB is 4628c2ecf20Sopenharmony_ci * erased before the write-buffer is sync'd and then there is an unclean 4638c2ecf20Sopenharmony_ci * unmount, then an existing node is lost. To avoid this, we sync all 4648c2ecf20Sopenharmony_ci * write-buffers. 4658c2ecf20Sopenharmony_ci * 4668c2ecf20Sopenharmony_ci * This function returns %0 on success or a negative error code on failure. 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_cistatic int gc_sync_wbufs(struct ubifs_info *c) 4698c2ecf20Sopenharmony_ci{ 4708c2ecf20Sopenharmony_ci int err, i; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci for (i = 0; i < c->jhead_cnt; i++) { 4738c2ecf20Sopenharmony_ci if (i == GCHD) 4748c2ecf20Sopenharmony_ci continue; 4758c2ecf20Sopenharmony_ci err = ubifs_wbuf_sync(&c->jheads[i].wbuf); 4768c2ecf20Sopenharmony_ci if (err) 4778c2ecf20Sopenharmony_ci return err; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci return 0; 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci/** 4838c2ecf20Sopenharmony_ci * ubifs_garbage_collect_leb - garbage-collect a logical eraseblock. 4848c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 4858c2ecf20Sopenharmony_ci * @lp: describes the LEB to garbage collect 4868c2ecf20Sopenharmony_ci * 4878c2ecf20Sopenharmony_ci * This function garbage-collects an LEB and returns one of the @LEB_FREED, 4888c2ecf20Sopenharmony_ci * @LEB_RETAINED, etc positive codes in case of success, %-EAGAIN if commit is 4898c2ecf20Sopenharmony_ci * required, and other negative error codes in case of failures. 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ciint ubifs_garbage_collect_leb(struct ubifs_info *c, struct ubifs_lprops *lp) 4928c2ecf20Sopenharmony_ci{ 4938c2ecf20Sopenharmony_ci struct ubifs_scan_leb *sleb; 4948c2ecf20Sopenharmony_ci struct ubifs_scan_node *snod; 4958c2ecf20Sopenharmony_ci struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; 4968c2ecf20Sopenharmony_ci int err = 0, lnum = lp->lnum; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci ubifs_assert(c, c->gc_lnum != -1 || wbuf->offs + wbuf->used == 0 || 4998c2ecf20Sopenharmony_ci c->need_recovery); 5008c2ecf20Sopenharmony_ci ubifs_assert(c, c->gc_lnum != lnum); 5018c2ecf20Sopenharmony_ci ubifs_assert(c, wbuf->lnum != lnum); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (lp->free + lp->dirty == c->leb_size) { 5048c2ecf20Sopenharmony_ci /* Special case - a free LEB */ 5058c2ecf20Sopenharmony_ci dbg_gc("LEB %d is free, return it", lp->lnum); 5068c2ecf20Sopenharmony_ci ubifs_assert(c, !(lp->flags & LPROPS_INDEX)); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (lp->free != c->leb_size) { 5098c2ecf20Sopenharmony_ci /* 5108c2ecf20Sopenharmony_ci * Write buffers must be sync'd before unmapping 5118c2ecf20Sopenharmony_ci * freeable LEBs, because one of them may contain data 5128c2ecf20Sopenharmony_ci * which obsoletes something in 'lp->lnum'. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_ci err = gc_sync_wbufs(c); 5158c2ecf20Sopenharmony_ci if (err) 5168c2ecf20Sopenharmony_ci return err; 5178c2ecf20Sopenharmony_ci err = ubifs_change_one_lp(c, lp->lnum, c->leb_size, 5188c2ecf20Sopenharmony_ci 0, 0, 0, 0); 5198c2ecf20Sopenharmony_ci if (err) 5208c2ecf20Sopenharmony_ci return err; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, lp->lnum); 5238c2ecf20Sopenharmony_ci if (err) 5248c2ecf20Sopenharmony_ci return err; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci if (c->gc_lnum == -1) { 5278c2ecf20Sopenharmony_ci c->gc_lnum = lnum; 5288c2ecf20Sopenharmony_ci return LEB_RETAINED; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return LEB_FREED; 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci /* 5358c2ecf20Sopenharmony_ci * We scan the entire LEB even though we only really need to scan up to 5368c2ecf20Sopenharmony_ci * (c->leb_size - lp->free). 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci sleb = ubifs_scan(c, lnum, 0, c->sbuf, 0); 5398c2ecf20Sopenharmony_ci if (IS_ERR(sleb)) 5408c2ecf20Sopenharmony_ci return PTR_ERR(sleb); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci ubifs_assert(c, !list_empty(&sleb->nodes)); 5438c2ecf20Sopenharmony_ci snod = list_entry(sleb->nodes.next, struct ubifs_scan_node, list); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci if (snod->type == UBIFS_IDX_NODE) { 5468c2ecf20Sopenharmony_ci struct ubifs_gced_idx_leb *idx_gc; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci dbg_gc("indexing LEB %d (free %d, dirty %d)", 5498c2ecf20Sopenharmony_ci lnum, lp->free, lp->dirty); 5508c2ecf20Sopenharmony_ci list_for_each_entry(snod, &sleb->nodes, list) { 5518c2ecf20Sopenharmony_ci struct ubifs_idx_node *idx = snod->node; 5528c2ecf20Sopenharmony_ci int level = le16_to_cpu(idx->level); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci ubifs_assert(c, snod->type == UBIFS_IDX_NODE); 5558c2ecf20Sopenharmony_ci key_read(c, ubifs_idx_key(c, idx), &snod->key); 5568c2ecf20Sopenharmony_ci err = ubifs_dirty_idx_node(c, &snod->key, level, lnum, 5578c2ecf20Sopenharmony_ci snod->offs); 5588c2ecf20Sopenharmony_ci if (err) 5598c2ecf20Sopenharmony_ci goto out; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS); 5638c2ecf20Sopenharmony_ci if (!idx_gc) { 5648c2ecf20Sopenharmony_ci err = -ENOMEM; 5658c2ecf20Sopenharmony_ci goto out; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci idx_gc->lnum = lnum; 5698c2ecf20Sopenharmony_ci idx_gc->unmap = 0; 5708c2ecf20Sopenharmony_ci list_add(&idx_gc->list, &c->idx_gc); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci /* 5738c2ecf20Sopenharmony_ci * Don't release the LEB until after the next commit, because 5748c2ecf20Sopenharmony_ci * it may contain data which is needed for recovery. So 5758c2ecf20Sopenharmony_ci * although we freed this LEB, it will become usable only after 5768c2ecf20Sopenharmony_ci * the commit. 5778c2ecf20Sopenharmony_ci */ 5788c2ecf20Sopenharmony_ci err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0, 5798c2ecf20Sopenharmony_ci LPROPS_INDEX, 1); 5808c2ecf20Sopenharmony_ci if (err) 5818c2ecf20Sopenharmony_ci goto out; 5828c2ecf20Sopenharmony_ci err = LEB_FREED_IDX; 5838c2ecf20Sopenharmony_ci } else { 5848c2ecf20Sopenharmony_ci dbg_gc("data LEB %d (free %d, dirty %d)", 5858c2ecf20Sopenharmony_ci lnum, lp->free, lp->dirty); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci err = move_nodes(c, sleb); 5888c2ecf20Sopenharmony_ci if (err) 5898c2ecf20Sopenharmony_ci goto out_inc_seq; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci err = gc_sync_wbufs(c); 5928c2ecf20Sopenharmony_ci if (err) 5938c2ecf20Sopenharmony_ci goto out_inc_seq; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci err = ubifs_change_one_lp(c, lnum, c->leb_size, 0, 0, 0, 0); 5968c2ecf20Sopenharmony_ci if (err) 5978c2ecf20Sopenharmony_ci goto out_inc_seq; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* Allow for races with TNC */ 6008c2ecf20Sopenharmony_ci c->gced_lnum = lnum; 6018c2ecf20Sopenharmony_ci smp_wmb(); 6028c2ecf20Sopenharmony_ci c->gc_seq += 1; 6038c2ecf20Sopenharmony_ci smp_wmb(); 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (c->gc_lnum == -1) { 6068c2ecf20Sopenharmony_ci c->gc_lnum = lnum; 6078c2ecf20Sopenharmony_ci err = LEB_RETAINED; 6088c2ecf20Sopenharmony_ci } else { 6098c2ecf20Sopenharmony_ci err = ubifs_wbuf_sync_nolock(wbuf); 6108c2ecf20Sopenharmony_ci if (err) 6118c2ecf20Sopenharmony_ci goto out; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, lnum); 6148c2ecf20Sopenharmony_ci if (err) 6158c2ecf20Sopenharmony_ci goto out; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci err = LEB_FREED; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ciout: 6228c2ecf20Sopenharmony_ci ubifs_scan_destroy(sleb); 6238c2ecf20Sopenharmony_ci return err; 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ciout_inc_seq: 6268c2ecf20Sopenharmony_ci /* We may have moved at least some nodes so allow for races with TNC */ 6278c2ecf20Sopenharmony_ci c->gced_lnum = lnum; 6288c2ecf20Sopenharmony_ci smp_wmb(); 6298c2ecf20Sopenharmony_ci c->gc_seq += 1; 6308c2ecf20Sopenharmony_ci smp_wmb(); 6318c2ecf20Sopenharmony_ci goto out; 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci/** 6358c2ecf20Sopenharmony_ci * ubifs_garbage_collect - UBIFS garbage collector. 6368c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 6378c2ecf20Sopenharmony_ci * @anyway: do GC even if there are free LEBs 6388c2ecf20Sopenharmony_ci * 6398c2ecf20Sopenharmony_ci * This function does out-of-place garbage collection. The return codes are: 6408c2ecf20Sopenharmony_ci * o positive LEB number if the LEB has been freed and may be used; 6418c2ecf20Sopenharmony_ci * o %-EAGAIN if the caller has to run commit; 6428c2ecf20Sopenharmony_ci * o %-ENOSPC if GC failed to make any progress; 6438c2ecf20Sopenharmony_ci * o other negative error codes in case of other errors. 6448c2ecf20Sopenharmony_ci * 6458c2ecf20Sopenharmony_ci * Garbage collector writes data to the journal when GC'ing data LEBs, and just 6468c2ecf20Sopenharmony_ci * marking indexing nodes dirty when GC'ing indexing LEBs. Thus, at some point 6478c2ecf20Sopenharmony_ci * commit may be required. But commit cannot be run from inside GC, because the 6488c2ecf20Sopenharmony_ci * caller might be holding the commit lock, so %-EAGAIN is returned instead; 6498c2ecf20Sopenharmony_ci * And this error code means that the caller has to run commit, and re-run GC 6508c2ecf20Sopenharmony_ci * if there is still no free space. 6518c2ecf20Sopenharmony_ci * 6528c2ecf20Sopenharmony_ci * There are many reasons why this function may return %-EAGAIN: 6538c2ecf20Sopenharmony_ci * o the log is full and there is no space to write an LEB reference for 6548c2ecf20Sopenharmony_ci * @c->gc_lnum; 6558c2ecf20Sopenharmony_ci * o the journal is too large and exceeds size limitations; 6568c2ecf20Sopenharmony_ci * o GC moved indexing LEBs, but they can be used only after the commit; 6578c2ecf20Sopenharmony_ci * o the shrinker fails to find clean znodes to free and requests the commit; 6588c2ecf20Sopenharmony_ci * o etc. 6598c2ecf20Sopenharmony_ci * 6608c2ecf20Sopenharmony_ci * Note, if the file-system is close to be full, this function may return 6618c2ecf20Sopenharmony_ci * %-EAGAIN infinitely, so the caller has to limit amount of re-invocations of 6628c2ecf20Sopenharmony_ci * the function. E.g., this happens if the limits on the journal size are too 6638c2ecf20Sopenharmony_ci * tough and GC writes too much to the journal before an LEB is freed. This 6648c2ecf20Sopenharmony_ci * might also mean that the journal is too large, and the TNC becomes to big, 6658c2ecf20Sopenharmony_ci * so that the shrinker is constantly called, finds not clean znodes to free, 6668c2ecf20Sopenharmony_ci * and requests commit. Well, this may also happen if the journal is all right, 6678c2ecf20Sopenharmony_ci * but another kernel process consumes too much memory. Anyway, infinite 6688c2ecf20Sopenharmony_ci * %-EAGAIN may happen, but in some extreme/misconfiguration cases. 6698c2ecf20Sopenharmony_ci */ 6708c2ecf20Sopenharmony_ciint ubifs_garbage_collect(struct ubifs_info *c, int anyway) 6718c2ecf20Sopenharmony_ci{ 6728c2ecf20Sopenharmony_ci int i, err, ret, min_space = c->dead_wm; 6738c2ecf20Sopenharmony_ci struct ubifs_lprops lp; 6748c2ecf20Sopenharmony_ci struct ubifs_wbuf *wbuf = &c->jheads[GCHD].wbuf; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci ubifs_assert_cmt_locked(c); 6778c2ecf20Sopenharmony_ci ubifs_assert(c, !c->ro_media && !c->ro_mount); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci if (ubifs_gc_should_commit(c)) 6808c2ecf20Sopenharmony_ci return -EAGAIN; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (c->ro_error) { 6858c2ecf20Sopenharmony_ci ret = -EROFS; 6868c2ecf20Sopenharmony_ci goto out_unlock; 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* We expect the write-buffer to be empty on entry */ 6908c2ecf20Sopenharmony_ci ubifs_assert(c, !wbuf->used); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci for (i = 0; ; i++) { 6938c2ecf20Sopenharmony_ci int space_before, space_after; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci /* Maybe continue after find and break before find */ 6968c2ecf20Sopenharmony_ci lp.lnum = -1; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci cond_resched(); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci /* Give the commit an opportunity to run */ 7018c2ecf20Sopenharmony_ci if (ubifs_gc_should_commit(c)) { 7028c2ecf20Sopenharmony_ci ret = -EAGAIN; 7038c2ecf20Sopenharmony_ci break; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci if (i > SOFT_LEBS_LIMIT && !list_empty(&c->idx_gc)) { 7078c2ecf20Sopenharmony_ci /* 7088c2ecf20Sopenharmony_ci * We've done enough iterations. Indexing LEBs were 7098c2ecf20Sopenharmony_ci * moved and will be available after the commit. 7108c2ecf20Sopenharmony_ci */ 7118c2ecf20Sopenharmony_ci dbg_gc("soft limit, some index LEBs GC'ed, -EAGAIN"); 7128c2ecf20Sopenharmony_ci ubifs_commit_required(c); 7138c2ecf20Sopenharmony_ci ret = -EAGAIN; 7148c2ecf20Sopenharmony_ci break; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci if (i > HARD_LEBS_LIMIT) { 7188c2ecf20Sopenharmony_ci /* 7198c2ecf20Sopenharmony_ci * We've moved too many LEBs and have not made 7208c2ecf20Sopenharmony_ci * progress, give up. 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci dbg_gc("hard limit, -ENOSPC"); 7238c2ecf20Sopenharmony_ci ret = -ENOSPC; 7248c2ecf20Sopenharmony_ci break; 7258c2ecf20Sopenharmony_ci } 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* 7288c2ecf20Sopenharmony_ci * Empty and freeable LEBs can turn up while we waited for 7298c2ecf20Sopenharmony_ci * the wbuf lock, or while we have been running GC. In that 7308c2ecf20Sopenharmony_ci * case, we should just return one of those instead of 7318c2ecf20Sopenharmony_ci * continuing to GC dirty LEBs. Hence we request 7328c2ecf20Sopenharmony_ci * 'ubifs_find_dirty_leb()' to return an empty LEB if it can. 7338c2ecf20Sopenharmony_ci */ 7348c2ecf20Sopenharmony_ci ret = ubifs_find_dirty_leb(c, &lp, min_space, anyway ? 0 : 1); 7358c2ecf20Sopenharmony_ci if (ret) { 7368c2ecf20Sopenharmony_ci if (ret == -ENOSPC) 7378c2ecf20Sopenharmony_ci dbg_gc("no more dirty LEBs"); 7388c2ecf20Sopenharmony_ci break; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci dbg_gc("found LEB %d: free %d, dirty %d, sum %d (min. space %d)", 7428c2ecf20Sopenharmony_ci lp.lnum, lp.free, lp.dirty, lp.free + lp.dirty, 7438c2ecf20Sopenharmony_ci min_space); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci space_before = c->leb_size - wbuf->offs - wbuf->used; 7468c2ecf20Sopenharmony_ci if (wbuf->lnum == -1) 7478c2ecf20Sopenharmony_ci space_before = 0; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci ret = ubifs_garbage_collect_leb(c, &lp); 7508c2ecf20Sopenharmony_ci if (ret < 0) { 7518c2ecf20Sopenharmony_ci if (ret == -EAGAIN) { 7528c2ecf20Sopenharmony_ci /* 7538c2ecf20Sopenharmony_ci * This is not error, so we have to return the 7548c2ecf20Sopenharmony_ci * LEB to lprops. But if 'ubifs_return_leb()' 7558c2ecf20Sopenharmony_ci * fails, its failure code is propagated to the 7568c2ecf20Sopenharmony_ci * caller instead of the original '-EAGAIN'. 7578c2ecf20Sopenharmony_ci */ 7588c2ecf20Sopenharmony_ci err = ubifs_return_leb(c, lp.lnum); 7598c2ecf20Sopenharmony_ci if (err) { 7608c2ecf20Sopenharmony_ci ret = err; 7618c2ecf20Sopenharmony_ci /* LEB may always be "taken". So set 7628c2ecf20Sopenharmony_ci * the ubifs to read-only. Sync wbuf 7638c2ecf20Sopenharmony_ci * will return -EROFS, then go "out". 7648c2ecf20Sopenharmony_ci */ 7658c2ecf20Sopenharmony_ci ubifs_ro_mode(c, ret); 7668c2ecf20Sopenharmony_ci } 7678c2ecf20Sopenharmony_ci /* Maybe double return if go out */ 7688c2ecf20Sopenharmony_ci lp.lnum = -1; 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci } 7718c2ecf20Sopenharmony_ci goto out; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (ret == LEB_FREED) { 7758c2ecf20Sopenharmony_ci /* An LEB has been freed and is ready for use */ 7768c2ecf20Sopenharmony_ci dbg_gc("LEB %d freed, return", lp.lnum); 7778c2ecf20Sopenharmony_ci ret = lp.lnum; 7788c2ecf20Sopenharmony_ci break; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci if (ret == LEB_FREED_IDX) { 7828c2ecf20Sopenharmony_ci /* 7838c2ecf20Sopenharmony_ci * This was an indexing LEB and it cannot be 7848c2ecf20Sopenharmony_ci * immediately used. And instead of requesting the 7858c2ecf20Sopenharmony_ci * commit straight away, we try to garbage collect some 7868c2ecf20Sopenharmony_ci * more. 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_ci dbg_gc("indexing LEB %d freed, continue", lp.lnum); 7898c2ecf20Sopenharmony_ci continue; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci ubifs_assert(c, ret == LEB_RETAINED); 7938c2ecf20Sopenharmony_ci space_after = c->leb_size - wbuf->offs - wbuf->used; 7948c2ecf20Sopenharmony_ci dbg_gc("LEB %d retained, freed %d bytes", lp.lnum, 7958c2ecf20Sopenharmony_ci space_after - space_before); 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (space_after > space_before) { 7988c2ecf20Sopenharmony_ci /* GC makes progress, keep working */ 7998c2ecf20Sopenharmony_ci min_space >>= 1; 8008c2ecf20Sopenharmony_ci if (min_space < c->dead_wm) 8018c2ecf20Sopenharmony_ci min_space = c->dead_wm; 8028c2ecf20Sopenharmony_ci continue; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci dbg_gc("did not make progress"); 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci /* 8088c2ecf20Sopenharmony_ci * GC moved an LEB bud have not done any progress. This means 8098c2ecf20Sopenharmony_ci * that the previous GC head LEB contained too few free space 8108c2ecf20Sopenharmony_ci * and the LEB which was GC'ed contained only large nodes which 8118c2ecf20Sopenharmony_ci * did not fit that space. 8128c2ecf20Sopenharmony_ci * 8138c2ecf20Sopenharmony_ci * We can do 2 things: 8148c2ecf20Sopenharmony_ci * 1. pick another LEB in a hope it'll contain a small node 8158c2ecf20Sopenharmony_ci * which will fit the space we have at the end of current GC 8168c2ecf20Sopenharmony_ci * head LEB, but there is no guarantee, so we try this out 8178c2ecf20Sopenharmony_ci * unless we have already been working for too long; 8188c2ecf20Sopenharmony_ci * 2. request an LEB with more dirty space, which will force 8198c2ecf20Sopenharmony_ci * 'ubifs_find_dirty_leb()' to start scanning the lprops 8208c2ecf20Sopenharmony_ci * table, instead of just picking one from the heap 8218c2ecf20Sopenharmony_ci * (previously it already picked the dirtiest LEB). 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_ci if (i < SOFT_LEBS_LIMIT) { 8248c2ecf20Sopenharmony_ci dbg_gc("try again"); 8258c2ecf20Sopenharmony_ci continue; 8268c2ecf20Sopenharmony_ci } 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci min_space <<= 1; 8298c2ecf20Sopenharmony_ci if (min_space > c->dark_wm) 8308c2ecf20Sopenharmony_ci min_space = c->dark_wm; 8318c2ecf20Sopenharmony_ci dbg_gc("set min. space to %d", min_space); 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (ret == -ENOSPC && !list_empty(&c->idx_gc)) { 8358c2ecf20Sopenharmony_ci dbg_gc("no space, some index LEBs GC'ed, -EAGAIN"); 8368c2ecf20Sopenharmony_ci ubifs_commit_required(c); 8378c2ecf20Sopenharmony_ci ret = -EAGAIN; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci err = ubifs_wbuf_sync_nolock(wbuf); 8418c2ecf20Sopenharmony_ci if (!err) 8428c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, c->gc_lnum); 8438c2ecf20Sopenharmony_ci if (err) { 8448c2ecf20Sopenharmony_ci ret = err; 8458c2ecf20Sopenharmony_ci goto out; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ciout_unlock: 8488c2ecf20Sopenharmony_ci mutex_unlock(&wbuf->io_mutex); 8498c2ecf20Sopenharmony_ci return ret; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ciout: 8528c2ecf20Sopenharmony_ci ubifs_assert(c, ret < 0); 8538c2ecf20Sopenharmony_ci ubifs_assert(c, ret != -ENOSPC && ret != -EAGAIN); 8548c2ecf20Sopenharmony_ci ubifs_wbuf_sync_nolock(wbuf); 8558c2ecf20Sopenharmony_ci ubifs_ro_mode(c, ret); 8568c2ecf20Sopenharmony_ci mutex_unlock(&wbuf->io_mutex); 8578c2ecf20Sopenharmony_ci if (lp.lnum != -1) 8588c2ecf20Sopenharmony_ci ubifs_return_leb(c, lp.lnum); 8598c2ecf20Sopenharmony_ci return ret; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/** 8638c2ecf20Sopenharmony_ci * ubifs_gc_start_commit - garbage collection at start of commit. 8648c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 8658c2ecf20Sopenharmony_ci * 8668c2ecf20Sopenharmony_ci * If a LEB has only dirty and free space, then we may safely unmap it and make 8678c2ecf20Sopenharmony_ci * it free. Note, we cannot do this with indexing LEBs because dirty space may 8688c2ecf20Sopenharmony_ci * correspond index nodes that are required for recovery. In that case, the 8698c2ecf20Sopenharmony_ci * LEB cannot be unmapped until after the next commit. 8708c2ecf20Sopenharmony_ci * 8718c2ecf20Sopenharmony_ci * This function returns %0 upon success and a negative error code upon failure. 8728c2ecf20Sopenharmony_ci */ 8738c2ecf20Sopenharmony_ciint ubifs_gc_start_commit(struct ubifs_info *c) 8748c2ecf20Sopenharmony_ci{ 8758c2ecf20Sopenharmony_ci struct ubifs_gced_idx_leb *idx_gc; 8768c2ecf20Sopenharmony_ci const struct ubifs_lprops *lp; 8778c2ecf20Sopenharmony_ci int err = 0, flags; 8788c2ecf20Sopenharmony_ci 8798c2ecf20Sopenharmony_ci ubifs_get_lprops(c); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci /* 8828c2ecf20Sopenharmony_ci * Unmap (non-index) freeable LEBs. Note that recovery requires that all 8838c2ecf20Sopenharmony_ci * wbufs are sync'd before this, which is done in 'do_commit()'. 8848c2ecf20Sopenharmony_ci */ 8858c2ecf20Sopenharmony_ci while (1) { 8868c2ecf20Sopenharmony_ci lp = ubifs_fast_find_freeable(c); 8878c2ecf20Sopenharmony_ci if (!lp) 8888c2ecf20Sopenharmony_ci break; 8898c2ecf20Sopenharmony_ci ubifs_assert(c, !(lp->flags & LPROPS_TAKEN)); 8908c2ecf20Sopenharmony_ci ubifs_assert(c, !(lp->flags & LPROPS_INDEX)); 8918c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, lp->lnum); 8928c2ecf20Sopenharmony_ci if (err) 8938c2ecf20Sopenharmony_ci goto out; 8948c2ecf20Sopenharmony_ci lp = ubifs_change_lp(c, lp, c->leb_size, 0, lp->flags, 0); 8958c2ecf20Sopenharmony_ci if (IS_ERR(lp)) { 8968c2ecf20Sopenharmony_ci err = PTR_ERR(lp); 8978c2ecf20Sopenharmony_ci goto out; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci ubifs_assert(c, !(lp->flags & LPROPS_TAKEN)); 9008c2ecf20Sopenharmony_ci ubifs_assert(c, !(lp->flags & LPROPS_INDEX)); 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci /* Mark GC'd index LEBs OK to unmap after this commit finishes */ 9048c2ecf20Sopenharmony_ci list_for_each_entry(idx_gc, &c->idx_gc, list) 9058c2ecf20Sopenharmony_ci idx_gc->unmap = 1; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci /* Record index freeable LEBs for unmapping after commit */ 9088c2ecf20Sopenharmony_ci while (1) { 9098c2ecf20Sopenharmony_ci lp = ubifs_fast_find_frdi_idx(c); 9108c2ecf20Sopenharmony_ci if (IS_ERR(lp)) { 9118c2ecf20Sopenharmony_ci err = PTR_ERR(lp); 9128c2ecf20Sopenharmony_ci goto out; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci if (!lp) 9158c2ecf20Sopenharmony_ci break; 9168c2ecf20Sopenharmony_ci idx_gc = kmalloc(sizeof(struct ubifs_gced_idx_leb), GFP_NOFS); 9178c2ecf20Sopenharmony_ci if (!idx_gc) { 9188c2ecf20Sopenharmony_ci err = -ENOMEM; 9198c2ecf20Sopenharmony_ci goto out; 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci ubifs_assert(c, !(lp->flags & LPROPS_TAKEN)); 9228c2ecf20Sopenharmony_ci ubifs_assert(c, lp->flags & LPROPS_INDEX); 9238c2ecf20Sopenharmony_ci /* Don't release the LEB until after the next commit */ 9248c2ecf20Sopenharmony_ci flags = (lp->flags | LPROPS_TAKEN) ^ LPROPS_INDEX; 9258c2ecf20Sopenharmony_ci lp = ubifs_change_lp(c, lp, c->leb_size, 0, flags, 1); 9268c2ecf20Sopenharmony_ci if (IS_ERR(lp)) { 9278c2ecf20Sopenharmony_ci err = PTR_ERR(lp); 9288c2ecf20Sopenharmony_ci kfree(idx_gc); 9298c2ecf20Sopenharmony_ci goto out; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci ubifs_assert(c, lp->flags & LPROPS_TAKEN); 9328c2ecf20Sopenharmony_ci ubifs_assert(c, !(lp->flags & LPROPS_INDEX)); 9338c2ecf20Sopenharmony_ci idx_gc->lnum = lp->lnum; 9348c2ecf20Sopenharmony_ci idx_gc->unmap = 1; 9358c2ecf20Sopenharmony_ci list_add(&idx_gc->list, &c->idx_gc); 9368c2ecf20Sopenharmony_ci } 9378c2ecf20Sopenharmony_ciout: 9388c2ecf20Sopenharmony_ci ubifs_release_lprops(c); 9398c2ecf20Sopenharmony_ci return err; 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci/** 9438c2ecf20Sopenharmony_ci * ubifs_gc_end_commit - garbage collection at end of commit. 9448c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 9458c2ecf20Sopenharmony_ci * 9468c2ecf20Sopenharmony_ci * This function completes out-of-place garbage collection of index LEBs. 9478c2ecf20Sopenharmony_ci */ 9488c2ecf20Sopenharmony_ciint ubifs_gc_end_commit(struct ubifs_info *c) 9498c2ecf20Sopenharmony_ci{ 9508c2ecf20Sopenharmony_ci struct ubifs_gced_idx_leb *idx_gc, *tmp; 9518c2ecf20Sopenharmony_ci struct ubifs_wbuf *wbuf; 9528c2ecf20Sopenharmony_ci int err = 0; 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci wbuf = &c->jheads[GCHD].wbuf; 9558c2ecf20Sopenharmony_ci mutex_lock_nested(&wbuf->io_mutex, wbuf->jhead); 9568c2ecf20Sopenharmony_ci list_for_each_entry_safe(idx_gc, tmp, &c->idx_gc, list) 9578c2ecf20Sopenharmony_ci if (idx_gc->unmap) { 9588c2ecf20Sopenharmony_ci dbg_gc("LEB %d", idx_gc->lnum); 9598c2ecf20Sopenharmony_ci err = ubifs_leb_unmap(c, idx_gc->lnum); 9608c2ecf20Sopenharmony_ci if (err) 9618c2ecf20Sopenharmony_ci goto out; 9628c2ecf20Sopenharmony_ci err = ubifs_change_one_lp(c, idx_gc->lnum, LPROPS_NC, 9638c2ecf20Sopenharmony_ci LPROPS_NC, 0, LPROPS_TAKEN, -1); 9648c2ecf20Sopenharmony_ci if (err) 9658c2ecf20Sopenharmony_ci goto out; 9668c2ecf20Sopenharmony_ci list_del(&idx_gc->list); 9678c2ecf20Sopenharmony_ci kfree(idx_gc); 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ciout: 9708c2ecf20Sopenharmony_ci mutex_unlock(&wbuf->io_mutex); 9718c2ecf20Sopenharmony_ci return err; 9728c2ecf20Sopenharmony_ci} 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci/** 9758c2ecf20Sopenharmony_ci * ubifs_destroy_idx_gc - destroy idx_gc list. 9768c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 9778c2ecf20Sopenharmony_ci * 9788c2ecf20Sopenharmony_ci * This function destroys the @c->idx_gc list. It is called when unmounting 9798c2ecf20Sopenharmony_ci * so locks are not needed. Returns zero in case of success and a negative 9808c2ecf20Sopenharmony_ci * error code in case of failure. 9818c2ecf20Sopenharmony_ci */ 9828c2ecf20Sopenharmony_civoid ubifs_destroy_idx_gc(struct ubifs_info *c) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci while (!list_empty(&c->idx_gc)) { 9858c2ecf20Sopenharmony_ci struct ubifs_gced_idx_leb *idx_gc; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, 9888c2ecf20Sopenharmony_ci list); 9898c2ecf20Sopenharmony_ci c->idx_gc_cnt -= 1; 9908c2ecf20Sopenharmony_ci list_del(&idx_gc->list); 9918c2ecf20Sopenharmony_ci kfree(idx_gc); 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci/** 9968c2ecf20Sopenharmony_ci * ubifs_get_idx_gc_leb - get a LEB from GC'd index LEB list. 9978c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 9988c2ecf20Sopenharmony_ci * 9998c2ecf20Sopenharmony_ci * Called during start commit so locks are not needed. 10008c2ecf20Sopenharmony_ci */ 10018c2ecf20Sopenharmony_ciint ubifs_get_idx_gc_leb(struct ubifs_info *c) 10028c2ecf20Sopenharmony_ci{ 10038c2ecf20Sopenharmony_ci struct ubifs_gced_idx_leb *idx_gc; 10048c2ecf20Sopenharmony_ci int lnum; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (list_empty(&c->idx_gc)) 10078c2ecf20Sopenharmony_ci return -ENOSPC; 10088c2ecf20Sopenharmony_ci idx_gc = list_entry(c->idx_gc.next, struct ubifs_gced_idx_leb, list); 10098c2ecf20Sopenharmony_ci lnum = idx_gc->lnum; 10108c2ecf20Sopenharmony_ci /* c->idx_gc_cnt is updated by the caller when lprops are updated */ 10118c2ecf20Sopenharmony_ci list_del(&idx_gc->list); 10128c2ecf20Sopenharmony_ci kfree(idx_gc); 10138c2ecf20Sopenharmony_ci return lnum; 10148c2ecf20Sopenharmony_ci} 1015