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 the budgeting sub-system which is responsible for UBIFS 138c2ecf20Sopenharmony_ci * space management. 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Factors such as compression, wasted space at the ends of LEBs, space in other 168c2ecf20Sopenharmony_ci * journal heads, the effect of updates on the index, and so on, make it 178c2ecf20Sopenharmony_ci * impossible to accurately predict the amount of space needed. Consequently 188c2ecf20Sopenharmony_ci * approximations are used. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "ubifs.h" 228c2ecf20Sopenharmony_ci#include <linux/writeback.h> 238c2ecf20Sopenharmony_ci#include <linux/math64.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * When pessimistic budget calculations say that there is no enough space, 278c2ecf20Sopenharmony_ci * UBIFS starts writing back dirty inodes and pages, doing garbage collection, 288c2ecf20Sopenharmony_ci * or committing. The below constant defines maximum number of times UBIFS 298c2ecf20Sopenharmony_ci * repeats the operations. 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_ci#define MAX_MKSPC_RETRIES 3 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * The below constant defines amount of dirty pages which should be written 358c2ecf20Sopenharmony_ci * back at when trying to shrink the liability. 368c2ecf20Sopenharmony_ci */ 378c2ecf20Sopenharmony_ci#define NR_TO_WRITE 16 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/** 408c2ecf20Sopenharmony_ci * shrink_liability - write-back some dirty pages/inodes. 418c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 428c2ecf20Sopenharmony_ci * @nr_to_write: how many dirty pages to write-back 438c2ecf20Sopenharmony_ci * 448c2ecf20Sopenharmony_ci * This function shrinks UBIFS liability by means of writing back some amount 458c2ecf20Sopenharmony_ci * of dirty inodes and their pages. 468c2ecf20Sopenharmony_ci * 478c2ecf20Sopenharmony_ci * Note, this function synchronizes even VFS inodes which are locked 488c2ecf20Sopenharmony_ci * (@i_mutex) by the caller of the budgeting function, because write-back does 498c2ecf20Sopenharmony_ci * not touch @i_mutex. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistatic void shrink_liability(struct ubifs_info *c, int nr_to_write) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci down_read(&c->vfs_sb->s_umount); 548c2ecf20Sopenharmony_ci writeback_inodes_sb_nr(c->vfs_sb, nr_to_write, WB_REASON_FS_FREE_SPACE); 558c2ecf20Sopenharmony_ci up_read(&c->vfs_sb->s_umount); 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/** 598c2ecf20Sopenharmony_ci * run_gc - run garbage collector. 608c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * This function runs garbage collector to make some more free space. Returns 638c2ecf20Sopenharmony_ci * zero if a free LEB has been produced, %-EAGAIN if commit is required, and a 648c2ecf20Sopenharmony_ci * negative error code in case of failure. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_cistatic int run_gc(struct ubifs_info *c) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci int err, lnum; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Make some free space by garbage-collecting dirty space */ 718c2ecf20Sopenharmony_ci down_read(&c->commit_sem); 728c2ecf20Sopenharmony_ci lnum = ubifs_garbage_collect(c, 1); 738c2ecf20Sopenharmony_ci up_read(&c->commit_sem); 748c2ecf20Sopenharmony_ci if (lnum < 0) 758c2ecf20Sopenharmony_ci return lnum; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci /* GC freed one LEB, return it to lprops */ 788c2ecf20Sopenharmony_ci dbg_budg("GC freed LEB %d", lnum); 798c2ecf20Sopenharmony_ci err = ubifs_return_leb(c, lnum); 808c2ecf20Sopenharmony_ci if (err) 818c2ecf20Sopenharmony_ci return err; 828c2ecf20Sopenharmony_ci return 0; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci/** 868c2ecf20Sopenharmony_ci * get_liability - calculate current liability. 878c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 888c2ecf20Sopenharmony_ci * 898c2ecf20Sopenharmony_ci * This function calculates and returns current UBIFS liability, i.e. the 908c2ecf20Sopenharmony_ci * amount of bytes UBIFS has "promised" to write to the media. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_cistatic long long get_liability(struct ubifs_info *c) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci long long liab; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci spin_lock(&c->space_lock); 978c2ecf20Sopenharmony_ci liab = c->bi.idx_growth + c->bi.data_growth + c->bi.dd_growth; 988c2ecf20Sopenharmony_ci spin_unlock(&c->space_lock); 998c2ecf20Sopenharmony_ci return liab; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/** 1038c2ecf20Sopenharmony_ci * make_free_space - make more free space on the file-system. 1048c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * This function is called when an operation cannot be budgeted because there 1078c2ecf20Sopenharmony_ci * is supposedly no free space. But in most cases there is some free space: 1088c2ecf20Sopenharmony_ci * o budgeting is pessimistic, so it always budgets more than it is actually 1098c2ecf20Sopenharmony_ci * needed, so shrinking the liability is one way to make free space - the 1108c2ecf20Sopenharmony_ci * cached data will take less space then it was budgeted for; 1118c2ecf20Sopenharmony_ci * o GC may turn some dark space into free space (budgeting treats dark space 1128c2ecf20Sopenharmony_ci * as not available); 1138c2ecf20Sopenharmony_ci * o commit may free some LEB, i.e., turn freeable LEBs into free LEBs. 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * So this function tries to do the above. Returns %-EAGAIN if some free space 1168c2ecf20Sopenharmony_ci * was presumably made and the caller has to re-try budgeting the operation. 1178c2ecf20Sopenharmony_ci * Returns %-ENOSPC if it couldn't do more free space, and other negative error 1188c2ecf20Sopenharmony_ci * codes on failures. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_cistatic int make_free_space(struct ubifs_info *c) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci int err, retries = 0; 1238c2ecf20Sopenharmony_ci long long liab1, liab2; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci do { 1268c2ecf20Sopenharmony_ci liab1 = get_liability(c); 1278c2ecf20Sopenharmony_ci /* 1288c2ecf20Sopenharmony_ci * We probably have some dirty pages or inodes (liability), try 1298c2ecf20Sopenharmony_ci * to write them back. 1308c2ecf20Sopenharmony_ci */ 1318c2ecf20Sopenharmony_ci dbg_budg("liability %lld, run write-back", liab1); 1328c2ecf20Sopenharmony_ci shrink_liability(c, NR_TO_WRITE); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci liab2 = get_liability(c); 1358c2ecf20Sopenharmony_ci if (liab2 < liab1) 1368c2ecf20Sopenharmony_ci return -EAGAIN; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci dbg_budg("new liability %lld (not shrunk)", liab2); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* Liability did not shrink again, try GC */ 1418c2ecf20Sopenharmony_ci dbg_budg("Run GC"); 1428c2ecf20Sopenharmony_ci err = run_gc(c); 1438c2ecf20Sopenharmony_ci if (!err) 1448c2ecf20Sopenharmony_ci return -EAGAIN; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (err != -EAGAIN && err != -ENOSPC) 1478c2ecf20Sopenharmony_ci /* Some real error happened */ 1488c2ecf20Sopenharmony_ci return err; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci dbg_budg("Run commit (retries %d)", retries); 1518c2ecf20Sopenharmony_ci err = ubifs_run_commit(c); 1528c2ecf20Sopenharmony_ci if (err) 1538c2ecf20Sopenharmony_ci return err; 1548c2ecf20Sopenharmony_ci } while (retries++ < MAX_MKSPC_RETRIES); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci return -ENOSPC; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/** 1608c2ecf20Sopenharmony_ci * ubifs_calc_min_idx_lebs - calculate amount of LEBs for the index. 1618c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 1628c2ecf20Sopenharmony_ci * 1638c2ecf20Sopenharmony_ci * This function calculates and returns the number of LEBs which should be kept 1648c2ecf20Sopenharmony_ci * for index usage. 1658c2ecf20Sopenharmony_ci */ 1668c2ecf20Sopenharmony_ciint ubifs_calc_min_idx_lebs(struct ubifs_info *c) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci int idx_lebs; 1698c2ecf20Sopenharmony_ci long long idx_size; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci idx_size = c->bi.old_idx_sz + c->bi.idx_growth + c->bi.uncommitted_idx; 1728c2ecf20Sopenharmony_ci /* And make sure we have thrice the index size of space reserved */ 1738c2ecf20Sopenharmony_ci idx_size += idx_size << 1; 1748c2ecf20Sopenharmony_ci /* 1758c2ecf20Sopenharmony_ci * We do not maintain 'old_idx_size' as 'old_idx_lebs'/'old_idx_bytes' 1768c2ecf20Sopenharmony_ci * pair, nor similarly the two variables for the new index size, so we 1778c2ecf20Sopenharmony_ci * have to do this costly 64-bit division on fast-path. 1788c2ecf20Sopenharmony_ci */ 1798c2ecf20Sopenharmony_ci idx_lebs = div_u64(idx_size + c->idx_leb_size - 1, c->idx_leb_size); 1808c2ecf20Sopenharmony_ci /* 1818c2ecf20Sopenharmony_ci * The index head is not available for the in-the-gaps method, so add an 1828c2ecf20Sopenharmony_ci * extra LEB to compensate. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci idx_lebs += 1; 1858c2ecf20Sopenharmony_ci if (idx_lebs < MIN_INDEX_LEBS) 1868c2ecf20Sopenharmony_ci idx_lebs = MIN_INDEX_LEBS; 1878c2ecf20Sopenharmony_ci return idx_lebs; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/** 1918c2ecf20Sopenharmony_ci * ubifs_calc_available - calculate available FS space. 1928c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 1938c2ecf20Sopenharmony_ci * @min_idx_lebs: minimum number of LEBs reserved for the index 1948c2ecf20Sopenharmony_ci * 1958c2ecf20Sopenharmony_ci * This function calculates and returns amount of FS space available for use. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cilong long ubifs_calc_available(const struct ubifs_info *c, int min_idx_lebs) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int subtract_lebs; 2008c2ecf20Sopenharmony_ci long long available; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci available = c->main_bytes - c->lst.total_used; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * Now 'available' contains theoretically available flash space 2068c2ecf20Sopenharmony_ci * assuming there is no index, so we have to subtract the space which 2078c2ecf20Sopenharmony_ci * is reserved for the index. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci subtract_lebs = min_idx_lebs; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* Take into account that GC reserves one LEB for its own needs */ 2128c2ecf20Sopenharmony_ci subtract_lebs += 1; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * Since different write types go to different heads, we should 2168c2ecf20Sopenharmony_ci * reserve one leb for each head. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci subtract_lebs += c->jhead_cnt; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* We also reserve one LEB for deletions, which bypass budgeting */ 2218c2ecf20Sopenharmony_ci subtract_lebs += 1; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci available -= (long long)subtract_lebs * c->leb_size; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* Subtract the dead space which is not available for use */ 2268c2ecf20Sopenharmony_ci available -= c->lst.total_dead; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* 2298c2ecf20Sopenharmony_ci * Subtract dark space, which might or might not be usable - it depends 2308c2ecf20Sopenharmony_ci * on the data which we have on the media and which will be written. If 2318c2ecf20Sopenharmony_ci * this is a lot of uncompressed or not-compressible data, the dark 2328c2ecf20Sopenharmony_ci * space cannot be used. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci available -= c->lst.total_dark; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* 2378c2ecf20Sopenharmony_ci * However, there is more dark space. The index may be bigger than 2388c2ecf20Sopenharmony_ci * @min_idx_lebs. Those extra LEBs are assumed to be available, but 2398c2ecf20Sopenharmony_ci * their dark space is not included in total_dark, so it is subtracted 2408c2ecf20Sopenharmony_ci * here. 2418c2ecf20Sopenharmony_ci */ 2428c2ecf20Sopenharmony_ci if (c->lst.idx_lebs > min_idx_lebs) { 2438c2ecf20Sopenharmony_ci subtract_lebs = c->lst.idx_lebs - min_idx_lebs; 2448c2ecf20Sopenharmony_ci available -= subtract_lebs * c->dark_wm; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* The calculations are rough and may end up with a negative number */ 2488c2ecf20Sopenharmony_ci return available > 0 ? available : 0; 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci/** 2528c2ecf20Sopenharmony_ci * can_use_rp - check whether the user is allowed to use reserved pool. 2538c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 2548c2ecf20Sopenharmony_ci * 2558c2ecf20Sopenharmony_ci * UBIFS has so-called "reserved pool" which is flash space reserved 2568c2ecf20Sopenharmony_ci * for the superuser and for uses whose UID/GID is recorded in UBIFS superblock. 2578c2ecf20Sopenharmony_ci * This function checks whether current user is allowed to use reserved pool. 2588c2ecf20Sopenharmony_ci * Returns %1 current user is allowed to use reserved pool and %0 otherwise. 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_cistatic int can_use_rp(struct ubifs_info *c) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci if (uid_eq(current_fsuid(), c->rp_uid) || capable(CAP_SYS_RESOURCE) || 2638c2ecf20Sopenharmony_ci (!gid_eq(c->rp_gid, GLOBAL_ROOT_GID) && in_group_p(c->rp_gid))) 2648c2ecf20Sopenharmony_ci return 1; 2658c2ecf20Sopenharmony_ci return 0; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/** 2698c2ecf20Sopenharmony_ci * do_budget_space - reserve flash space for index and data growth. 2708c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 2718c2ecf20Sopenharmony_ci * 2728c2ecf20Sopenharmony_ci * This function makes sure UBIFS has enough free LEBs for index growth and 2738c2ecf20Sopenharmony_ci * data. 2748c2ecf20Sopenharmony_ci * 2758c2ecf20Sopenharmony_ci * When budgeting index space, UBIFS reserves thrice as many LEBs as the index 2768c2ecf20Sopenharmony_ci * would take if it was consolidated and written to the flash. This guarantees 2778c2ecf20Sopenharmony_ci * that the "in-the-gaps" commit method always succeeds and UBIFS will always 2788c2ecf20Sopenharmony_ci * be able to commit dirty index. So this function basically adds amount of 2798c2ecf20Sopenharmony_ci * budgeted index space to the size of the current index, multiplies this by 3, 2808c2ecf20Sopenharmony_ci * and makes sure this does not exceed the amount of free LEBs. 2818c2ecf20Sopenharmony_ci * 2828c2ecf20Sopenharmony_ci * Notes about @c->bi.min_idx_lebs and @c->lst.idx_lebs variables: 2838c2ecf20Sopenharmony_ci * o @c->lst.idx_lebs is the number of LEBs the index currently uses. It might 2848c2ecf20Sopenharmony_ci * be large, because UBIFS does not do any index consolidation as long as 2858c2ecf20Sopenharmony_ci * there is free space. IOW, the index may take a lot of LEBs, but the LEBs 2868c2ecf20Sopenharmony_ci * will contain a lot of dirt. 2878c2ecf20Sopenharmony_ci * o @c->bi.min_idx_lebs is the number of LEBS the index presumably takes. IOW, 2888c2ecf20Sopenharmony_ci * the index may be consolidated to take up to @c->bi.min_idx_lebs LEBs. 2898c2ecf20Sopenharmony_ci * 2908c2ecf20Sopenharmony_ci * This function returns zero in case of success, and %-ENOSPC in case of 2918c2ecf20Sopenharmony_ci * failure. 2928c2ecf20Sopenharmony_ci */ 2938c2ecf20Sopenharmony_cistatic int do_budget_space(struct ubifs_info *c) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci long long outstanding, available; 2968c2ecf20Sopenharmony_ci int lebs, rsvd_idx_lebs, min_idx_lebs; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* First budget index space */ 2998c2ecf20Sopenharmony_ci min_idx_lebs = ubifs_calc_min_idx_lebs(c); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Now 'min_idx_lebs' contains number of LEBs to reserve */ 3028c2ecf20Sopenharmony_ci if (min_idx_lebs > c->lst.idx_lebs) 3038c2ecf20Sopenharmony_ci rsvd_idx_lebs = min_idx_lebs - c->lst.idx_lebs; 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci rsvd_idx_lebs = 0; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* 3088c2ecf20Sopenharmony_ci * The number of LEBs that are available to be used by the index is: 3098c2ecf20Sopenharmony_ci * 3108c2ecf20Sopenharmony_ci * @c->lst.empty_lebs + @c->freeable_cnt + @c->idx_gc_cnt - 3118c2ecf20Sopenharmony_ci * @c->lst.taken_empty_lebs 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * @c->lst.empty_lebs are available because they are empty. 3148c2ecf20Sopenharmony_ci * @c->freeable_cnt are available because they contain only free and 3158c2ecf20Sopenharmony_ci * dirty space, @c->idx_gc_cnt are available because they are index 3168c2ecf20Sopenharmony_ci * LEBs that have been garbage collected and are awaiting the commit 3178c2ecf20Sopenharmony_ci * before they can be used. And the in-the-gaps method will grab these 3188c2ecf20Sopenharmony_ci * if it needs them. @c->lst.taken_empty_lebs are empty LEBs that have 3198c2ecf20Sopenharmony_ci * already been allocated for some purpose. 3208c2ecf20Sopenharmony_ci * 3218c2ecf20Sopenharmony_ci * Note, @c->idx_gc_cnt is included to both @c->lst.empty_lebs (because 3228c2ecf20Sopenharmony_ci * these LEBs are empty) and to @c->lst.taken_empty_lebs (because they 3238c2ecf20Sopenharmony_ci * are taken until after the commit). 3248c2ecf20Sopenharmony_ci * 3258c2ecf20Sopenharmony_ci * Note, @c->lst.taken_empty_lebs may temporarily be higher by one 3268c2ecf20Sopenharmony_ci * because of the way we serialize LEB allocations and budgeting. See a 3278c2ecf20Sopenharmony_ci * comment in 'ubifs_find_free_space()'. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_ci lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt - 3308c2ecf20Sopenharmony_ci c->lst.taken_empty_lebs; 3318c2ecf20Sopenharmony_ci if (unlikely(rsvd_idx_lebs > lebs)) { 3328c2ecf20Sopenharmony_ci dbg_budg("out of indexing space: min_idx_lebs %d (old %d), rsvd_idx_lebs %d", 3338c2ecf20Sopenharmony_ci min_idx_lebs, c->bi.min_idx_lebs, rsvd_idx_lebs); 3348c2ecf20Sopenharmony_ci return -ENOSPC; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci available = ubifs_calc_available(c, min_idx_lebs); 3388c2ecf20Sopenharmony_ci outstanding = c->bi.data_growth + c->bi.dd_growth; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci if (unlikely(available < outstanding)) { 3418c2ecf20Sopenharmony_ci dbg_budg("out of data space: available %lld, outstanding %lld", 3428c2ecf20Sopenharmony_ci available, outstanding); 3438c2ecf20Sopenharmony_ci return -ENOSPC; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (available - outstanding <= c->rp_size && !can_use_rp(c)) 3478c2ecf20Sopenharmony_ci return -ENOSPC; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci c->bi.min_idx_lebs = min_idx_lebs; 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci/** 3548c2ecf20Sopenharmony_ci * calc_idx_growth - calculate approximate index growth from budgeting request. 3558c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3568c2ecf20Sopenharmony_ci * @req: budgeting request 3578c2ecf20Sopenharmony_ci * 3588c2ecf20Sopenharmony_ci * For now we assume each new node adds one znode. But this is rather poor 3598c2ecf20Sopenharmony_ci * approximation, though. 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_cistatic int calc_idx_growth(const struct ubifs_info *c, 3628c2ecf20Sopenharmony_ci const struct ubifs_budget_req *req) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci int znodes; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci znodes = req->new_ino + (req->new_page << UBIFS_BLOCKS_PER_PAGE_SHIFT) + 3678c2ecf20Sopenharmony_ci req->new_dent; 3688c2ecf20Sopenharmony_ci return znodes * c->max_idx_node_sz; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/** 3728c2ecf20Sopenharmony_ci * calc_data_growth - calculate approximate amount of new data from budgeting 3738c2ecf20Sopenharmony_ci * request. 3748c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3758c2ecf20Sopenharmony_ci * @req: budgeting request 3768c2ecf20Sopenharmony_ci */ 3778c2ecf20Sopenharmony_cistatic int calc_data_growth(const struct ubifs_info *c, 3788c2ecf20Sopenharmony_ci const struct ubifs_budget_req *req) 3798c2ecf20Sopenharmony_ci{ 3808c2ecf20Sopenharmony_ci int data_growth; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci data_growth = req->new_ino ? c->bi.inode_budget : 0; 3838c2ecf20Sopenharmony_ci if (req->new_page) 3848c2ecf20Sopenharmony_ci data_growth += c->bi.page_budget; 3858c2ecf20Sopenharmony_ci if (req->new_dent) 3868c2ecf20Sopenharmony_ci data_growth += c->bi.dent_budget; 3878c2ecf20Sopenharmony_ci data_growth += req->new_ino_d; 3888c2ecf20Sopenharmony_ci return data_growth; 3898c2ecf20Sopenharmony_ci} 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci/** 3928c2ecf20Sopenharmony_ci * calc_dd_growth - calculate approximate amount of data which makes other data 3938c2ecf20Sopenharmony_ci * dirty from budgeting request. 3948c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 3958c2ecf20Sopenharmony_ci * @req: budgeting request 3968c2ecf20Sopenharmony_ci */ 3978c2ecf20Sopenharmony_cistatic int calc_dd_growth(const struct ubifs_info *c, 3988c2ecf20Sopenharmony_ci const struct ubifs_budget_req *req) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci int dd_growth; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci dd_growth = req->dirtied_page ? c->bi.page_budget : 0; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (req->dirtied_ino) 4058c2ecf20Sopenharmony_ci dd_growth += c->bi.inode_budget * req->dirtied_ino; 4068c2ecf20Sopenharmony_ci if (req->mod_dent) 4078c2ecf20Sopenharmony_ci dd_growth += c->bi.dent_budget; 4088c2ecf20Sopenharmony_ci dd_growth += req->dirtied_ino_d; 4098c2ecf20Sopenharmony_ci return dd_growth; 4108c2ecf20Sopenharmony_ci} 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci/** 4138c2ecf20Sopenharmony_ci * ubifs_budget_space - ensure there is enough space to complete an operation. 4148c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 4158c2ecf20Sopenharmony_ci * @req: budget request 4168c2ecf20Sopenharmony_ci * 4178c2ecf20Sopenharmony_ci * This function allocates budget for an operation. It uses pessimistic 4188c2ecf20Sopenharmony_ci * approximation of how much flash space the operation needs. The goal of this 4198c2ecf20Sopenharmony_ci * function is to make sure UBIFS always has flash space to flush all dirty 4208c2ecf20Sopenharmony_ci * pages, dirty inodes, and dirty znodes (liability). This function may force 4218c2ecf20Sopenharmony_ci * commit, garbage-collection or write-back. Returns zero in case of success, 4228c2ecf20Sopenharmony_ci * %-ENOSPC if there is no free space and other negative error codes in case of 4238c2ecf20Sopenharmony_ci * failures. 4248c2ecf20Sopenharmony_ci */ 4258c2ecf20Sopenharmony_ciint ubifs_budget_space(struct ubifs_info *c, struct ubifs_budget_req *req) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci int err, idx_growth, data_growth, dd_growth, retried = 0; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ubifs_assert(c, req->new_page <= 1); 4308c2ecf20Sopenharmony_ci ubifs_assert(c, req->dirtied_page <= 1); 4318c2ecf20Sopenharmony_ci ubifs_assert(c, req->new_dent <= 1); 4328c2ecf20Sopenharmony_ci ubifs_assert(c, req->mod_dent <= 1); 4338c2ecf20Sopenharmony_ci ubifs_assert(c, req->new_ino <= 1); 4348c2ecf20Sopenharmony_ci ubifs_assert(c, req->new_ino_d <= UBIFS_MAX_INO_DATA); 4358c2ecf20Sopenharmony_ci ubifs_assert(c, req->dirtied_ino <= 4); 4368c2ecf20Sopenharmony_ci ubifs_assert(c, req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); 4378c2ecf20Sopenharmony_ci ubifs_assert(c, !(req->new_ino_d & 7)); 4388c2ecf20Sopenharmony_ci ubifs_assert(c, !(req->dirtied_ino_d & 7)); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci data_growth = calc_data_growth(c, req); 4418c2ecf20Sopenharmony_ci dd_growth = calc_dd_growth(c, req); 4428c2ecf20Sopenharmony_ci if (!data_growth && !dd_growth) 4438c2ecf20Sopenharmony_ci return 0; 4448c2ecf20Sopenharmony_ci idx_growth = calc_idx_growth(c, req); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ciagain: 4478c2ecf20Sopenharmony_ci spin_lock(&c->space_lock); 4488c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.idx_growth >= 0); 4498c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.data_growth >= 0); 4508c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.dd_growth >= 0); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (unlikely(c->bi.nospace) && (c->bi.nospace_rp || !can_use_rp(c))) { 4538c2ecf20Sopenharmony_ci dbg_budg("no space"); 4548c2ecf20Sopenharmony_ci spin_unlock(&c->space_lock); 4558c2ecf20Sopenharmony_ci return -ENOSPC; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci c->bi.idx_growth += idx_growth; 4598c2ecf20Sopenharmony_ci c->bi.data_growth += data_growth; 4608c2ecf20Sopenharmony_ci c->bi.dd_growth += dd_growth; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci err = do_budget_space(c); 4638c2ecf20Sopenharmony_ci if (likely(!err)) { 4648c2ecf20Sopenharmony_ci req->idx_growth = idx_growth; 4658c2ecf20Sopenharmony_ci req->data_growth = data_growth; 4668c2ecf20Sopenharmony_ci req->dd_growth = dd_growth; 4678c2ecf20Sopenharmony_ci spin_unlock(&c->space_lock); 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Restore the old values */ 4728c2ecf20Sopenharmony_ci c->bi.idx_growth -= idx_growth; 4738c2ecf20Sopenharmony_ci c->bi.data_growth -= data_growth; 4748c2ecf20Sopenharmony_ci c->bi.dd_growth -= dd_growth; 4758c2ecf20Sopenharmony_ci spin_unlock(&c->space_lock); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if (req->fast) { 4788c2ecf20Sopenharmony_ci dbg_budg("no space for fast budgeting"); 4798c2ecf20Sopenharmony_ci return err; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci err = make_free_space(c); 4838c2ecf20Sopenharmony_ci cond_resched(); 4848c2ecf20Sopenharmony_ci if (err == -EAGAIN) { 4858c2ecf20Sopenharmony_ci dbg_budg("try again"); 4868c2ecf20Sopenharmony_ci goto again; 4878c2ecf20Sopenharmony_ci } else if (err == -ENOSPC) { 4888c2ecf20Sopenharmony_ci if (!retried) { 4898c2ecf20Sopenharmony_ci retried = 1; 4908c2ecf20Sopenharmony_ci dbg_budg("-ENOSPC, but anyway try once again"); 4918c2ecf20Sopenharmony_ci goto again; 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci dbg_budg("FS is full, -ENOSPC"); 4948c2ecf20Sopenharmony_ci c->bi.nospace = 1; 4958c2ecf20Sopenharmony_ci if (can_use_rp(c) || c->rp_size == 0) 4968c2ecf20Sopenharmony_ci c->bi.nospace_rp = 1; 4978c2ecf20Sopenharmony_ci smp_wmb(); 4988c2ecf20Sopenharmony_ci } else 4998c2ecf20Sopenharmony_ci ubifs_err(c, "cannot budget space, error %d", err); 5008c2ecf20Sopenharmony_ci return err; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci/** 5048c2ecf20Sopenharmony_ci * ubifs_release_budget - release budgeted free space. 5058c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5068c2ecf20Sopenharmony_ci * @req: budget request 5078c2ecf20Sopenharmony_ci * 5088c2ecf20Sopenharmony_ci * This function releases the space budgeted by 'ubifs_budget_space()'. Note, 5098c2ecf20Sopenharmony_ci * since the index changes (which were budgeted for in @req->idx_growth) will 5108c2ecf20Sopenharmony_ci * only be written to the media on commit, this function moves the index budget 5118c2ecf20Sopenharmony_ci * from @c->bi.idx_growth to @c->bi.uncommitted_idx. The latter will be zeroed 5128c2ecf20Sopenharmony_ci * by the commit operation. 5138c2ecf20Sopenharmony_ci */ 5148c2ecf20Sopenharmony_civoid ubifs_release_budget(struct ubifs_info *c, struct ubifs_budget_req *req) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci ubifs_assert(c, req->new_page <= 1); 5178c2ecf20Sopenharmony_ci ubifs_assert(c, req->dirtied_page <= 1); 5188c2ecf20Sopenharmony_ci ubifs_assert(c, req->new_dent <= 1); 5198c2ecf20Sopenharmony_ci ubifs_assert(c, req->mod_dent <= 1); 5208c2ecf20Sopenharmony_ci ubifs_assert(c, req->new_ino <= 1); 5218c2ecf20Sopenharmony_ci ubifs_assert(c, req->new_ino_d <= UBIFS_MAX_INO_DATA); 5228c2ecf20Sopenharmony_ci ubifs_assert(c, req->dirtied_ino <= 4); 5238c2ecf20Sopenharmony_ci ubifs_assert(c, req->dirtied_ino_d <= UBIFS_MAX_INO_DATA * 4); 5248c2ecf20Sopenharmony_ci ubifs_assert(c, !(req->new_ino_d & 7)); 5258c2ecf20Sopenharmony_ci ubifs_assert(c, !(req->dirtied_ino_d & 7)); 5268c2ecf20Sopenharmony_ci if (!req->recalculate) { 5278c2ecf20Sopenharmony_ci ubifs_assert(c, req->idx_growth >= 0); 5288c2ecf20Sopenharmony_ci ubifs_assert(c, req->data_growth >= 0); 5298c2ecf20Sopenharmony_ci ubifs_assert(c, req->dd_growth >= 0); 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (req->recalculate) { 5338c2ecf20Sopenharmony_ci req->data_growth = calc_data_growth(c, req); 5348c2ecf20Sopenharmony_ci req->dd_growth = calc_dd_growth(c, req); 5358c2ecf20Sopenharmony_ci req->idx_growth = calc_idx_growth(c, req); 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci if (!req->data_growth && !req->dd_growth) 5398c2ecf20Sopenharmony_ci return; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci c->bi.nospace = c->bi.nospace_rp = 0; 5428c2ecf20Sopenharmony_ci smp_wmb(); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci spin_lock(&c->space_lock); 5458c2ecf20Sopenharmony_ci c->bi.idx_growth -= req->idx_growth; 5468c2ecf20Sopenharmony_ci c->bi.uncommitted_idx += req->idx_growth; 5478c2ecf20Sopenharmony_ci c->bi.data_growth -= req->data_growth; 5488c2ecf20Sopenharmony_ci c->bi.dd_growth -= req->dd_growth; 5498c2ecf20Sopenharmony_ci c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.idx_growth >= 0); 5528c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.data_growth >= 0); 5538c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.dd_growth >= 0); 5548c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.min_idx_lebs < c->main_lebs); 5558c2ecf20Sopenharmony_ci ubifs_assert(c, !(c->bi.idx_growth & 7)); 5568c2ecf20Sopenharmony_ci ubifs_assert(c, !(c->bi.data_growth & 7)); 5578c2ecf20Sopenharmony_ci ubifs_assert(c, !(c->bi.dd_growth & 7)); 5588c2ecf20Sopenharmony_ci spin_unlock(&c->space_lock); 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci/** 5628c2ecf20Sopenharmony_ci * ubifs_convert_page_budget - convert budget of a new page. 5638c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5648c2ecf20Sopenharmony_ci * 5658c2ecf20Sopenharmony_ci * This function converts budget which was allocated for a new page of data to 5668c2ecf20Sopenharmony_ci * the budget of changing an existing page of data. The latter is smaller than 5678c2ecf20Sopenharmony_ci * the former, so this function only does simple re-calculation and does not 5688c2ecf20Sopenharmony_ci * involve any write-back. 5698c2ecf20Sopenharmony_ci */ 5708c2ecf20Sopenharmony_civoid ubifs_convert_page_budget(struct ubifs_info *c) 5718c2ecf20Sopenharmony_ci{ 5728c2ecf20Sopenharmony_ci spin_lock(&c->space_lock); 5738c2ecf20Sopenharmony_ci /* Release the index growth reservation */ 5748c2ecf20Sopenharmony_ci c->bi.idx_growth -= c->max_idx_node_sz << UBIFS_BLOCKS_PER_PAGE_SHIFT; 5758c2ecf20Sopenharmony_ci /* Release the data growth reservation */ 5768c2ecf20Sopenharmony_ci c->bi.data_growth -= c->bi.page_budget; 5778c2ecf20Sopenharmony_ci /* Increase the dirty data growth reservation instead */ 5788c2ecf20Sopenharmony_ci c->bi.dd_growth += c->bi.page_budget; 5798c2ecf20Sopenharmony_ci /* And re-calculate the indexing space reservation */ 5808c2ecf20Sopenharmony_ci c->bi.min_idx_lebs = ubifs_calc_min_idx_lebs(c); 5818c2ecf20Sopenharmony_ci spin_unlock(&c->space_lock); 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci/** 5858c2ecf20Sopenharmony_ci * ubifs_release_dirty_inode_budget - release dirty inode budget. 5868c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 5878c2ecf20Sopenharmony_ci * @ui: UBIFS inode to release the budget for 5888c2ecf20Sopenharmony_ci * 5898c2ecf20Sopenharmony_ci * This function releases budget corresponding to a dirty inode. It is usually 5908c2ecf20Sopenharmony_ci * called when after the inode has been written to the media and marked as 5918c2ecf20Sopenharmony_ci * clean. It also causes the "no space" flags to be cleared. 5928c2ecf20Sopenharmony_ci */ 5938c2ecf20Sopenharmony_civoid ubifs_release_dirty_inode_budget(struct ubifs_info *c, 5948c2ecf20Sopenharmony_ci struct ubifs_inode *ui) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct ubifs_budget_req req; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci memset(&req, 0, sizeof(struct ubifs_budget_req)); 5998c2ecf20Sopenharmony_ci /* The "no space" flags will be cleared because dd_growth is > 0 */ 6008c2ecf20Sopenharmony_ci req.dd_growth = c->bi.inode_budget + ALIGN(ui->data_len, 8); 6018c2ecf20Sopenharmony_ci ubifs_release_budget(c, &req); 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci/** 6058c2ecf20Sopenharmony_ci * ubifs_reported_space - calculate reported free space. 6068c2ecf20Sopenharmony_ci * @c: the UBIFS file-system description object 6078c2ecf20Sopenharmony_ci * @free: amount of free space 6088c2ecf20Sopenharmony_ci * 6098c2ecf20Sopenharmony_ci * This function calculates amount of free space which will be reported to 6108c2ecf20Sopenharmony_ci * user-space. User-space application tend to expect that if the file-system 6118c2ecf20Sopenharmony_ci * (e.g., via the 'statfs()' call) reports that it has N bytes available, they 6128c2ecf20Sopenharmony_ci * are able to write a file of size N. UBIFS attaches node headers to each data 6138c2ecf20Sopenharmony_ci * node and it has to write indexing nodes as well. This introduces additional 6148c2ecf20Sopenharmony_ci * overhead, and UBIFS has to report slightly less free space to meet the above 6158c2ecf20Sopenharmony_ci * expectations. 6168c2ecf20Sopenharmony_ci * 6178c2ecf20Sopenharmony_ci * This function assumes free space is made up of uncompressed data nodes and 6188c2ecf20Sopenharmony_ci * full index nodes (one per data node, tripled because we always allow enough 6198c2ecf20Sopenharmony_ci * space to write the index thrice). 6208c2ecf20Sopenharmony_ci * 6218c2ecf20Sopenharmony_ci * Note, the calculation is pessimistic, which means that most of the time 6228c2ecf20Sopenharmony_ci * UBIFS reports less space than it actually has. 6238c2ecf20Sopenharmony_ci */ 6248c2ecf20Sopenharmony_cilong long ubifs_reported_space(const struct ubifs_info *c, long long free) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci int divisor, factor, f; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* 6298c2ecf20Sopenharmony_ci * Reported space size is @free * X, where X is UBIFS block size 6308c2ecf20Sopenharmony_ci * divided by UBIFS block size + all overhead one data block 6318c2ecf20Sopenharmony_ci * introduces. The overhead is the node header + indexing overhead. 6328c2ecf20Sopenharmony_ci * 6338c2ecf20Sopenharmony_ci * Indexing overhead calculations are based on the following formula: 6348c2ecf20Sopenharmony_ci * I = N/(f - 1) + 1, where I - number of indexing nodes, N - number 6358c2ecf20Sopenharmony_ci * of data nodes, f - fanout. Because effective UBIFS fanout is twice 6368c2ecf20Sopenharmony_ci * as less than maximum fanout, we assume that each data node 6378c2ecf20Sopenharmony_ci * introduces 3 * @c->max_idx_node_sz / (@c->fanout/2 - 1) bytes. 6388c2ecf20Sopenharmony_ci * Note, the multiplier 3 is because UBIFS reserves thrice as more space 6398c2ecf20Sopenharmony_ci * for the index. 6408c2ecf20Sopenharmony_ci */ 6418c2ecf20Sopenharmony_ci f = c->fanout > 3 ? c->fanout >> 1 : 2; 6428c2ecf20Sopenharmony_ci factor = UBIFS_BLOCK_SIZE; 6438c2ecf20Sopenharmony_ci divisor = UBIFS_MAX_DATA_NODE_SZ; 6448c2ecf20Sopenharmony_ci divisor += (c->max_idx_node_sz * 3) / (f - 1); 6458c2ecf20Sopenharmony_ci free *= factor; 6468c2ecf20Sopenharmony_ci return div_u64(free, divisor); 6478c2ecf20Sopenharmony_ci} 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci/** 6508c2ecf20Sopenharmony_ci * ubifs_get_free_space_nolock - return amount of free space. 6518c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 6528c2ecf20Sopenharmony_ci * 6538c2ecf20Sopenharmony_ci * This function calculates amount of free space to report to user-space. 6548c2ecf20Sopenharmony_ci * 6558c2ecf20Sopenharmony_ci * Because UBIFS may introduce substantial overhead (the index, node headers, 6568c2ecf20Sopenharmony_ci * alignment, wastage at the end of LEBs, etc), it cannot report real amount of 6578c2ecf20Sopenharmony_ci * free flash space it has (well, because not all dirty space is reclaimable, 6588c2ecf20Sopenharmony_ci * UBIFS does not actually know the real amount). If UBIFS did so, it would 6598c2ecf20Sopenharmony_ci * bread user expectations about what free space is. Users seem to accustomed 6608c2ecf20Sopenharmony_ci * to assume that if the file-system reports N bytes of free space, they would 6618c2ecf20Sopenharmony_ci * be able to fit a file of N bytes to the FS. This almost works for 6628c2ecf20Sopenharmony_ci * traditional file-systems, because they have way less overhead than UBIFS. 6638c2ecf20Sopenharmony_ci * So, to keep users happy, UBIFS tries to take the overhead into account. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_cilong long ubifs_get_free_space_nolock(struct ubifs_info *c) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci int rsvd_idx_lebs, lebs; 6688c2ecf20Sopenharmony_ci long long available, outstanding, free; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci ubifs_assert(c, c->bi.min_idx_lebs == ubifs_calc_min_idx_lebs(c)); 6718c2ecf20Sopenharmony_ci outstanding = c->bi.data_growth + c->bi.dd_growth; 6728c2ecf20Sopenharmony_ci available = ubifs_calc_available(c, c->bi.min_idx_lebs); 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* 6758c2ecf20Sopenharmony_ci * When reporting free space to user-space, UBIFS guarantees that it is 6768c2ecf20Sopenharmony_ci * possible to write a file of free space size. This means that for 6778c2ecf20Sopenharmony_ci * empty LEBs we may use more precise calculations than 6788c2ecf20Sopenharmony_ci * 'ubifs_calc_available()' is using. Namely, we know that in empty 6798c2ecf20Sopenharmony_ci * LEBs we would waste only @c->leb_overhead bytes, not @c->dark_wm. 6808c2ecf20Sopenharmony_ci * Thus, amend the available space. 6818c2ecf20Sopenharmony_ci * 6828c2ecf20Sopenharmony_ci * Note, the calculations below are similar to what we have in 6838c2ecf20Sopenharmony_ci * 'do_budget_space()', so refer there for comments. 6848c2ecf20Sopenharmony_ci */ 6858c2ecf20Sopenharmony_ci if (c->bi.min_idx_lebs > c->lst.idx_lebs) 6868c2ecf20Sopenharmony_ci rsvd_idx_lebs = c->bi.min_idx_lebs - c->lst.idx_lebs; 6878c2ecf20Sopenharmony_ci else 6888c2ecf20Sopenharmony_ci rsvd_idx_lebs = 0; 6898c2ecf20Sopenharmony_ci lebs = c->lst.empty_lebs + c->freeable_cnt + c->idx_gc_cnt - 6908c2ecf20Sopenharmony_ci c->lst.taken_empty_lebs; 6918c2ecf20Sopenharmony_ci lebs -= rsvd_idx_lebs; 6928c2ecf20Sopenharmony_ci available += lebs * (c->dark_wm - c->leb_overhead); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (available > outstanding) 6958c2ecf20Sopenharmony_ci free = ubifs_reported_space(c, available - outstanding); 6968c2ecf20Sopenharmony_ci else 6978c2ecf20Sopenharmony_ci free = 0; 6988c2ecf20Sopenharmony_ci return free; 6998c2ecf20Sopenharmony_ci} 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci/** 7028c2ecf20Sopenharmony_ci * ubifs_get_free_space - return amount of free space. 7038c2ecf20Sopenharmony_ci * @c: UBIFS file-system description object 7048c2ecf20Sopenharmony_ci * 7058c2ecf20Sopenharmony_ci * This function calculates and returns amount of free space to report to 7068c2ecf20Sopenharmony_ci * user-space. 7078c2ecf20Sopenharmony_ci */ 7088c2ecf20Sopenharmony_cilong long ubifs_get_free_space(struct ubifs_info *c) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci long long free; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci spin_lock(&c->space_lock); 7138c2ecf20Sopenharmony_ci free = ubifs_get_free_space_nolock(c); 7148c2ecf20Sopenharmony_ci spin_unlock(&c->space_lock); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci return free; 7178c2ecf20Sopenharmony_ci} 718