18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * lcnalloc.c - Cluster (de)allocation code. Part of the Linux-NTFS project. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2004-2005 Anton Altaparmakov 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifdef NTFS_RW 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include "lcnalloc.h" 138c2ecf20Sopenharmony_ci#include "debug.h" 148c2ecf20Sopenharmony_ci#include "bitmap.h" 158c2ecf20Sopenharmony_ci#include "inode.h" 168c2ecf20Sopenharmony_ci#include "volume.h" 178c2ecf20Sopenharmony_ci#include "attrib.h" 188c2ecf20Sopenharmony_ci#include "malloc.h" 198c2ecf20Sopenharmony_ci#include "aops.h" 208c2ecf20Sopenharmony_ci#include "ntfs.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/** 238c2ecf20Sopenharmony_ci * ntfs_cluster_free_from_rl_nolock - free clusters from runlist 248c2ecf20Sopenharmony_ci * @vol: mounted ntfs volume on which to free the clusters 258c2ecf20Sopenharmony_ci * @rl: runlist describing the clusters to free 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Free all the clusters described by the runlist @rl on the volume @vol. In 288c2ecf20Sopenharmony_ci * the case of an error being returned, at least some of the clusters were not 298c2ecf20Sopenharmony_ci * freed. 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Return 0 on success and -errno on error. 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * Locking: - The volume lcn bitmap must be locked for writing on entry and is 348c2ecf20Sopenharmony_ci * left locked on return. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_ciint ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, 378c2ecf20Sopenharmony_ci const runlist_element *rl) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct inode *lcnbmp_vi = vol->lcnbmp_ino; 408c2ecf20Sopenharmony_ci int ret = 0; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci ntfs_debug("Entering."); 438c2ecf20Sopenharmony_ci if (!rl) 448c2ecf20Sopenharmony_ci return 0; 458c2ecf20Sopenharmony_ci for (; rl->length; rl++) { 468c2ecf20Sopenharmony_ci int err; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci if (rl->lcn < 0) 498c2ecf20Sopenharmony_ci continue; 508c2ecf20Sopenharmony_ci err = ntfs_bitmap_clear_run(lcnbmp_vi, rl->lcn, rl->length); 518c2ecf20Sopenharmony_ci if (unlikely(err && (!ret || ret == -ENOMEM) && ret != err)) 528c2ecf20Sopenharmony_ci ret = err; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci ntfs_debug("Done."); 558c2ecf20Sopenharmony_ci return ret; 568c2ecf20Sopenharmony_ci} 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/** 598c2ecf20Sopenharmony_ci * ntfs_cluster_alloc - allocate clusters on an ntfs volume 608c2ecf20Sopenharmony_ci * @vol: mounted ntfs volume on which to allocate the clusters 618c2ecf20Sopenharmony_ci * @start_vcn: vcn to use for the first allocated cluster 628c2ecf20Sopenharmony_ci * @count: number of clusters to allocate 638c2ecf20Sopenharmony_ci * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none) 648c2ecf20Sopenharmony_ci * @zone: zone from which to allocate the clusters 658c2ecf20Sopenharmony_ci * @is_extension: if 'true', this is an attribute extension 668c2ecf20Sopenharmony_ci * 678c2ecf20Sopenharmony_ci * Allocate @count clusters preferably starting at cluster @start_lcn or at the 688c2ecf20Sopenharmony_ci * current allocator position if @start_lcn is -1, on the mounted ntfs volume 698c2ecf20Sopenharmony_ci * @vol. @zone is either DATA_ZONE for allocation of normal clusters or 708c2ecf20Sopenharmony_ci * MFT_ZONE for allocation of clusters for the master file table, i.e. the 718c2ecf20Sopenharmony_ci * $MFT/$DATA attribute. 728c2ecf20Sopenharmony_ci * 738c2ecf20Sopenharmony_ci * @start_vcn specifies the vcn of the first allocated cluster. This makes 748c2ecf20Sopenharmony_ci * merging the resulting runlist with the old runlist easier. 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * If @is_extension is 'true', the caller is allocating clusters to extend an 778c2ecf20Sopenharmony_ci * attribute and if it is 'false', the caller is allocating clusters to fill a 788c2ecf20Sopenharmony_ci * hole in an attribute. Practically the difference is that if @is_extension 798c2ecf20Sopenharmony_ci * is 'true' the returned runlist will be terminated with LCN_ENOENT and if 808c2ecf20Sopenharmony_ci * @is_extension is 'false' the runlist will be terminated with 818c2ecf20Sopenharmony_ci * LCN_RL_NOT_MAPPED. 828c2ecf20Sopenharmony_ci * 838c2ecf20Sopenharmony_ci * You need to check the return value with IS_ERR(). If this is false, the 848c2ecf20Sopenharmony_ci * function was successful and the return value is a runlist describing the 858c2ecf20Sopenharmony_ci * allocated cluster(s). If IS_ERR() is true, the function failed and 868c2ecf20Sopenharmony_ci * PTR_ERR() gives you the error code. 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * Notes on the allocation algorithm 898c2ecf20Sopenharmony_ci * ================================= 908c2ecf20Sopenharmony_ci * 918c2ecf20Sopenharmony_ci * There are two data zones. First is the area between the end of the mft zone 928c2ecf20Sopenharmony_ci * and the end of the volume, and second is the area between the start of the 938c2ecf20Sopenharmony_ci * volume and the start of the mft zone. On unmodified/standard NTFS 1.x 948c2ecf20Sopenharmony_ci * volumes, the second data zone does not exist due to the mft zone being 958c2ecf20Sopenharmony_ci * expanded to cover the start of the volume in order to reserve space for the 968c2ecf20Sopenharmony_ci * mft bitmap attribute. 978c2ecf20Sopenharmony_ci * 988c2ecf20Sopenharmony_ci * This is not the prettiest function but the complexity stems from the need of 998c2ecf20Sopenharmony_ci * implementing the mft vs data zoned approach and from the fact that we have 1008c2ecf20Sopenharmony_ci * access to the lcn bitmap in portions of up to 8192 bytes at a time, so we 1018c2ecf20Sopenharmony_ci * need to cope with crossing over boundaries of two buffers. Further, the 1028c2ecf20Sopenharmony_ci * fact that the allocator allows for caller supplied hints as to the location 1038c2ecf20Sopenharmony_ci * of where allocation should begin and the fact that the allocator keeps track 1048c2ecf20Sopenharmony_ci * of where in the data zones the next natural allocation should occur, 1058c2ecf20Sopenharmony_ci * contribute to the complexity of the function. But it should all be 1068c2ecf20Sopenharmony_ci * worthwhile, because this allocator should: 1) be a full implementation of 1078c2ecf20Sopenharmony_ci * the MFT zone approach used by Windows NT, 2) cause reduction in 1088c2ecf20Sopenharmony_ci * fragmentation, and 3) be speedy in allocations (the code is not optimized 1098c2ecf20Sopenharmony_ci * for speed, but the algorithm is, so further speed improvements are probably 1108c2ecf20Sopenharmony_ci * possible). 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * FIXME: We should be monitoring cluster allocation and increment the MFT zone 1138c2ecf20Sopenharmony_ci * size dynamically but this is something for the future. We will just cause 1148c2ecf20Sopenharmony_ci * heavier fragmentation by not doing it and I am not even sure Windows would 1158c2ecf20Sopenharmony_ci * grow the MFT zone dynamically, so it might even be correct not to do this. 1168c2ecf20Sopenharmony_ci * The overhead in doing dynamic MFT zone expansion would be very large and 1178c2ecf20Sopenharmony_ci * unlikely worth the effort. (AIA) 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * TODO: I have added in double the required zone position pointer wrap around 1208c2ecf20Sopenharmony_ci * logic which can be optimized to having only one of the two logic sets. 1218c2ecf20Sopenharmony_ci * However, having the double logic will work fine, but if we have only one of 1228c2ecf20Sopenharmony_ci * the sets and we get it wrong somewhere, then we get into trouble, so 1238c2ecf20Sopenharmony_ci * removing the duplicate logic requires _very_ careful consideration of _all_ 1248c2ecf20Sopenharmony_ci * possible code paths. So at least for now, I am leaving the double logic - 1258c2ecf20Sopenharmony_ci * better safe than sorry... (AIA) 1268c2ecf20Sopenharmony_ci * 1278c2ecf20Sopenharmony_ci * Locking: - The volume lcn bitmap must be unlocked on entry and is unlocked 1288c2ecf20Sopenharmony_ci * on return. 1298c2ecf20Sopenharmony_ci * - This function takes the volume lcn bitmap lock for writing and 1308c2ecf20Sopenharmony_ci * modifies the bitmap contents. 1318c2ecf20Sopenharmony_ci */ 1328c2ecf20Sopenharmony_cirunlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn, 1338c2ecf20Sopenharmony_ci const s64 count, const LCN start_lcn, 1348c2ecf20Sopenharmony_ci const NTFS_CLUSTER_ALLOCATION_ZONES zone, 1358c2ecf20Sopenharmony_ci const bool is_extension) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn; 1388c2ecf20Sopenharmony_ci LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size; 1398c2ecf20Sopenharmony_ci s64 clusters; 1408c2ecf20Sopenharmony_ci loff_t i_size; 1418c2ecf20Sopenharmony_ci struct inode *lcnbmp_vi; 1428c2ecf20Sopenharmony_ci runlist_element *rl = NULL; 1438c2ecf20Sopenharmony_ci struct address_space *mapping; 1448c2ecf20Sopenharmony_ci struct page *page = NULL; 1458c2ecf20Sopenharmony_ci u8 *buf, *byte; 1468c2ecf20Sopenharmony_ci int err = 0, rlpos, rlsize, buf_size; 1478c2ecf20Sopenharmony_ci u8 pass, done_zones, search_zone, need_writeback = 0, bit; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci ntfs_debug("Entering for start_vcn 0x%llx, count 0x%llx, start_lcn " 1508c2ecf20Sopenharmony_ci "0x%llx, zone %s_ZONE.", (unsigned long long)start_vcn, 1518c2ecf20Sopenharmony_ci (unsigned long long)count, 1528c2ecf20Sopenharmony_ci (unsigned long long)start_lcn, 1538c2ecf20Sopenharmony_ci zone == MFT_ZONE ? "MFT" : "DATA"); 1548c2ecf20Sopenharmony_ci BUG_ON(!vol); 1558c2ecf20Sopenharmony_ci lcnbmp_vi = vol->lcnbmp_ino; 1568c2ecf20Sopenharmony_ci BUG_ON(!lcnbmp_vi); 1578c2ecf20Sopenharmony_ci BUG_ON(start_vcn < 0); 1588c2ecf20Sopenharmony_ci BUG_ON(count < 0); 1598c2ecf20Sopenharmony_ci BUG_ON(start_lcn < -1); 1608c2ecf20Sopenharmony_ci BUG_ON(zone < FIRST_ZONE); 1618c2ecf20Sopenharmony_ci BUG_ON(zone > LAST_ZONE); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* Return NULL if @count is zero. */ 1648c2ecf20Sopenharmony_ci if (!count) 1658c2ecf20Sopenharmony_ci return NULL; 1668c2ecf20Sopenharmony_ci /* Take the lcnbmp lock for writing. */ 1678c2ecf20Sopenharmony_ci down_write(&vol->lcnbmp_lock); 1688c2ecf20Sopenharmony_ci /* 1698c2ecf20Sopenharmony_ci * If no specific @start_lcn was requested, use the current data zone 1708c2ecf20Sopenharmony_ci * position, otherwise use the requested @start_lcn but make sure it 1718c2ecf20Sopenharmony_ci * lies outside the mft zone. Also set done_zones to 0 (no zones done) 1728c2ecf20Sopenharmony_ci * and pass depending on whether we are starting inside a zone (1) or 1738c2ecf20Sopenharmony_ci * at the beginning of a zone (2). If requesting from the MFT_ZONE, 1748c2ecf20Sopenharmony_ci * we either start at the current position within the mft zone or at 1758c2ecf20Sopenharmony_ci * the specified position. If the latter is out of bounds then we start 1768c2ecf20Sopenharmony_ci * at the beginning of the MFT_ZONE. 1778c2ecf20Sopenharmony_ci */ 1788c2ecf20Sopenharmony_ci done_zones = 0; 1798c2ecf20Sopenharmony_ci pass = 1; 1808c2ecf20Sopenharmony_ci /* 1818c2ecf20Sopenharmony_ci * zone_start and zone_end are the current search range. search_zone 1828c2ecf20Sopenharmony_ci * is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of 1838c2ecf20Sopenharmony_ci * volume) and 4 for data zone 2 (start of volume till start of mft 1848c2ecf20Sopenharmony_ci * zone). 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci zone_start = start_lcn; 1878c2ecf20Sopenharmony_ci if (zone_start < 0) { 1888c2ecf20Sopenharmony_ci if (zone == DATA_ZONE) 1898c2ecf20Sopenharmony_ci zone_start = vol->data1_zone_pos; 1908c2ecf20Sopenharmony_ci else 1918c2ecf20Sopenharmony_ci zone_start = vol->mft_zone_pos; 1928c2ecf20Sopenharmony_ci if (!zone_start) { 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * Zone starts at beginning of volume which means a 1958c2ecf20Sopenharmony_ci * single pass is sufficient. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci pass = 2; 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci } else if (zone == DATA_ZONE && zone_start >= vol->mft_zone_start && 2008c2ecf20Sopenharmony_ci zone_start < vol->mft_zone_end) { 2018c2ecf20Sopenharmony_ci zone_start = vol->mft_zone_end; 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * Starting at beginning of data1_zone which means a single 2048c2ecf20Sopenharmony_ci * pass in this zone is sufficient. 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci pass = 2; 2078c2ecf20Sopenharmony_ci } else if (zone == MFT_ZONE && (zone_start < vol->mft_zone_start || 2088c2ecf20Sopenharmony_ci zone_start >= vol->mft_zone_end)) { 2098c2ecf20Sopenharmony_ci zone_start = vol->mft_lcn; 2108c2ecf20Sopenharmony_ci if (!vol->mft_zone_end) 2118c2ecf20Sopenharmony_ci zone_start = 0; 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * Starting at beginning of volume which means a single pass 2148c2ecf20Sopenharmony_ci * is sufficient. 2158c2ecf20Sopenharmony_ci */ 2168c2ecf20Sopenharmony_ci pass = 2; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci if (zone == MFT_ZONE) { 2198c2ecf20Sopenharmony_ci zone_end = vol->mft_zone_end; 2208c2ecf20Sopenharmony_ci search_zone = 1; 2218c2ecf20Sopenharmony_ci } else /* if (zone == DATA_ZONE) */ { 2228c2ecf20Sopenharmony_ci /* Skip searching the mft zone. */ 2238c2ecf20Sopenharmony_ci done_zones |= 1; 2248c2ecf20Sopenharmony_ci if (zone_start >= vol->mft_zone_end) { 2258c2ecf20Sopenharmony_ci zone_end = vol->nr_clusters; 2268c2ecf20Sopenharmony_ci search_zone = 2; 2278c2ecf20Sopenharmony_ci } else { 2288c2ecf20Sopenharmony_ci zone_end = vol->mft_zone_start; 2298c2ecf20Sopenharmony_ci search_zone = 4; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci /* 2338c2ecf20Sopenharmony_ci * bmp_pos is the current bit position inside the bitmap. We use 2348c2ecf20Sopenharmony_ci * bmp_initial_pos to determine whether or not to do a zone switch. 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci bmp_pos = bmp_initial_pos = zone_start; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci /* Loop until all clusters are allocated, i.e. clusters == 0. */ 2398c2ecf20Sopenharmony_ci clusters = count; 2408c2ecf20Sopenharmony_ci rlpos = rlsize = 0; 2418c2ecf20Sopenharmony_ci mapping = lcnbmp_vi->i_mapping; 2428c2ecf20Sopenharmony_ci i_size = i_size_read(lcnbmp_vi); 2438c2ecf20Sopenharmony_ci while (1) { 2448c2ecf20Sopenharmony_ci ntfs_debug("Start of outer while loop: done_zones 0x%x, " 2458c2ecf20Sopenharmony_ci "search_zone %i, pass %i, zone_start 0x%llx, " 2468c2ecf20Sopenharmony_ci "zone_end 0x%llx, bmp_initial_pos 0x%llx, " 2478c2ecf20Sopenharmony_ci "bmp_pos 0x%llx, rlpos %i, rlsize %i.", 2488c2ecf20Sopenharmony_ci done_zones, search_zone, pass, 2498c2ecf20Sopenharmony_ci (unsigned long long)zone_start, 2508c2ecf20Sopenharmony_ci (unsigned long long)zone_end, 2518c2ecf20Sopenharmony_ci (unsigned long long)bmp_initial_pos, 2528c2ecf20Sopenharmony_ci (unsigned long long)bmp_pos, rlpos, rlsize); 2538c2ecf20Sopenharmony_ci /* Loop until we run out of free clusters. */ 2548c2ecf20Sopenharmony_ci last_read_pos = bmp_pos >> 3; 2558c2ecf20Sopenharmony_ci ntfs_debug("last_read_pos 0x%llx.", 2568c2ecf20Sopenharmony_ci (unsigned long long)last_read_pos); 2578c2ecf20Sopenharmony_ci if (last_read_pos > i_size) { 2588c2ecf20Sopenharmony_ci ntfs_debug("End of attribute reached. " 2598c2ecf20Sopenharmony_ci "Skipping to zone_pass_done."); 2608c2ecf20Sopenharmony_ci goto zone_pass_done; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci if (likely(page)) { 2638c2ecf20Sopenharmony_ci if (need_writeback) { 2648c2ecf20Sopenharmony_ci ntfs_debug("Marking page dirty."); 2658c2ecf20Sopenharmony_ci flush_dcache_page(page); 2668c2ecf20Sopenharmony_ci set_page_dirty(page); 2678c2ecf20Sopenharmony_ci need_writeback = 0; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci ntfs_unmap_page(page); 2708c2ecf20Sopenharmony_ci } 2718c2ecf20Sopenharmony_ci page = ntfs_map_page(mapping, last_read_pos >> 2728c2ecf20Sopenharmony_ci PAGE_SHIFT); 2738c2ecf20Sopenharmony_ci if (IS_ERR(page)) { 2748c2ecf20Sopenharmony_ci err = PTR_ERR(page); 2758c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to map page."); 2768c2ecf20Sopenharmony_ci goto out; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci buf_size = last_read_pos & ~PAGE_MASK; 2798c2ecf20Sopenharmony_ci buf = page_address(page) + buf_size; 2808c2ecf20Sopenharmony_ci buf_size = PAGE_SIZE - buf_size; 2818c2ecf20Sopenharmony_ci if (unlikely(last_read_pos + buf_size > i_size)) 2828c2ecf20Sopenharmony_ci buf_size = i_size - last_read_pos; 2838c2ecf20Sopenharmony_ci buf_size <<= 3; 2848c2ecf20Sopenharmony_ci lcn = bmp_pos & 7; 2858c2ecf20Sopenharmony_ci bmp_pos &= ~(LCN)7; 2868c2ecf20Sopenharmony_ci ntfs_debug("Before inner while loop: buf_size %i, lcn 0x%llx, " 2878c2ecf20Sopenharmony_ci "bmp_pos 0x%llx, need_writeback %i.", buf_size, 2888c2ecf20Sopenharmony_ci (unsigned long long)lcn, 2898c2ecf20Sopenharmony_ci (unsigned long long)bmp_pos, need_writeback); 2908c2ecf20Sopenharmony_ci while (lcn < buf_size && lcn + bmp_pos < zone_end) { 2918c2ecf20Sopenharmony_ci byte = buf + (lcn >> 3); 2928c2ecf20Sopenharmony_ci ntfs_debug("In inner while loop: buf_size %i, " 2938c2ecf20Sopenharmony_ci "lcn 0x%llx, bmp_pos 0x%llx, " 2948c2ecf20Sopenharmony_ci "need_writeback %i, byte ofs 0x%x, " 2958c2ecf20Sopenharmony_ci "*byte 0x%x.", buf_size, 2968c2ecf20Sopenharmony_ci (unsigned long long)lcn, 2978c2ecf20Sopenharmony_ci (unsigned long long)bmp_pos, 2988c2ecf20Sopenharmony_ci need_writeback, 2998c2ecf20Sopenharmony_ci (unsigned int)(lcn >> 3), 3008c2ecf20Sopenharmony_ci (unsigned int)*byte); 3018c2ecf20Sopenharmony_ci /* Skip full bytes. */ 3028c2ecf20Sopenharmony_ci if (*byte == 0xff) { 3038c2ecf20Sopenharmony_ci lcn = (lcn + 8) & ~(LCN)7; 3048c2ecf20Sopenharmony_ci ntfs_debug("Continuing while loop 1."); 3058c2ecf20Sopenharmony_ci continue; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci bit = 1 << (lcn & 7); 3088c2ecf20Sopenharmony_ci ntfs_debug("bit 0x%x.", bit); 3098c2ecf20Sopenharmony_ci /* If the bit is already set, go onto the next one. */ 3108c2ecf20Sopenharmony_ci if (*byte & bit) { 3118c2ecf20Sopenharmony_ci lcn++; 3128c2ecf20Sopenharmony_ci ntfs_debug("Continuing while loop 2."); 3138c2ecf20Sopenharmony_ci continue; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci /* 3168c2ecf20Sopenharmony_ci * Allocate more memory if needed, including space for 3178c2ecf20Sopenharmony_ci * the terminator element. 3188c2ecf20Sopenharmony_ci * ntfs_malloc_nofs() operates on whole pages only. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ci if ((rlpos + 2) * sizeof(*rl) > rlsize) { 3218c2ecf20Sopenharmony_ci runlist_element *rl2; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci ntfs_debug("Reallocating memory."); 3248c2ecf20Sopenharmony_ci if (!rl) 3258c2ecf20Sopenharmony_ci ntfs_debug("First free bit is at LCN " 3268c2ecf20Sopenharmony_ci "0x%llx.", 3278c2ecf20Sopenharmony_ci (unsigned long long) 3288c2ecf20Sopenharmony_ci (lcn + bmp_pos)); 3298c2ecf20Sopenharmony_ci rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE); 3308c2ecf20Sopenharmony_ci if (unlikely(!rl2)) { 3318c2ecf20Sopenharmony_ci err = -ENOMEM; 3328c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to " 3338c2ecf20Sopenharmony_ci "allocate memory."); 3348c2ecf20Sopenharmony_ci goto out; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci memcpy(rl2, rl, rlsize); 3378c2ecf20Sopenharmony_ci ntfs_free(rl); 3388c2ecf20Sopenharmony_ci rl = rl2; 3398c2ecf20Sopenharmony_ci rlsize += PAGE_SIZE; 3408c2ecf20Sopenharmony_ci ntfs_debug("Reallocated memory, rlsize 0x%x.", 3418c2ecf20Sopenharmony_ci rlsize); 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci /* Allocate the bitmap bit. */ 3448c2ecf20Sopenharmony_ci *byte |= bit; 3458c2ecf20Sopenharmony_ci /* We need to write this bitmap page to disk. */ 3468c2ecf20Sopenharmony_ci need_writeback = 1; 3478c2ecf20Sopenharmony_ci ntfs_debug("*byte 0x%x, need_writeback is set.", 3488c2ecf20Sopenharmony_ci (unsigned int)*byte); 3498c2ecf20Sopenharmony_ci /* 3508c2ecf20Sopenharmony_ci * Coalesce with previous run if adjacent LCNs. 3518c2ecf20Sopenharmony_ci * Otherwise, append a new run. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci ntfs_debug("Adding run (lcn 0x%llx, len 0x%llx), " 3548c2ecf20Sopenharmony_ci "prev_lcn 0x%llx, lcn 0x%llx, " 3558c2ecf20Sopenharmony_ci "bmp_pos 0x%llx, prev_run_len 0x%llx, " 3568c2ecf20Sopenharmony_ci "rlpos %i.", 3578c2ecf20Sopenharmony_ci (unsigned long long)(lcn + bmp_pos), 3588c2ecf20Sopenharmony_ci 1ULL, (unsigned long long)prev_lcn, 3598c2ecf20Sopenharmony_ci (unsigned long long)lcn, 3608c2ecf20Sopenharmony_ci (unsigned long long)bmp_pos, 3618c2ecf20Sopenharmony_ci (unsigned long long)prev_run_len, 3628c2ecf20Sopenharmony_ci rlpos); 3638c2ecf20Sopenharmony_ci if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) { 3648c2ecf20Sopenharmony_ci ntfs_debug("Coalescing to run (lcn 0x%llx, " 3658c2ecf20Sopenharmony_ci "len 0x%llx).", 3668c2ecf20Sopenharmony_ci (unsigned long long) 3678c2ecf20Sopenharmony_ci rl[rlpos - 1].lcn, 3688c2ecf20Sopenharmony_ci (unsigned long long) 3698c2ecf20Sopenharmony_ci rl[rlpos - 1].length); 3708c2ecf20Sopenharmony_ci rl[rlpos - 1].length = ++prev_run_len; 3718c2ecf20Sopenharmony_ci ntfs_debug("Run now (lcn 0x%llx, len 0x%llx), " 3728c2ecf20Sopenharmony_ci "prev_run_len 0x%llx.", 3738c2ecf20Sopenharmony_ci (unsigned long long) 3748c2ecf20Sopenharmony_ci rl[rlpos - 1].lcn, 3758c2ecf20Sopenharmony_ci (unsigned long long) 3768c2ecf20Sopenharmony_ci rl[rlpos - 1].length, 3778c2ecf20Sopenharmony_ci (unsigned long long) 3788c2ecf20Sopenharmony_ci prev_run_len); 3798c2ecf20Sopenharmony_ci } else { 3808c2ecf20Sopenharmony_ci if (likely(rlpos)) { 3818c2ecf20Sopenharmony_ci ntfs_debug("Adding new run, (previous " 3828c2ecf20Sopenharmony_ci "run lcn 0x%llx, " 3838c2ecf20Sopenharmony_ci "len 0x%llx).", 3848c2ecf20Sopenharmony_ci (unsigned long long) 3858c2ecf20Sopenharmony_ci rl[rlpos - 1].lcn, 3868c2ecf20Sopenharmony_ci (unsigned long long) 3878c2ecf20Sopenharmony_ci rl[rlpos - 1].length); 3888c2ecf20Sopenharmony_ci rl[rlpos].vcn = rl[rlpos - 1].vcn + 3898c2ecf20Sopenharmony_ci prev_run_len; 3908c2ecf20Sopenharmony_ci } else { 3918c2ecf20Sopenharmony_ci ntfs_debug("Adding new run, is first " 3928c2ecf20Sopenharmony_ci "run."); 3938c2ecf20Sopenharmony_ci rl[rlpos].vcn = start_vcn; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci rl[rlpos].lcn = prev_lcn = lcn + bmp_pos; 3968c2ecf20Sopenharmony_ci rl[rlpos].length = prev_run_len = 1; 3978c2ecf20Sopenharmony_ci rlpos++; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci /* Done? */ 4008c2ecf20Sopenharmony_ci if (!--clusters) { 4018c2ecf20Sopenharmony_ci LCN tc; 4028c2ecf20Sopenharmony_ci /* 4038c2ecf20Sopenharmony_ci * Update the current zone position. Positions 4048c2ecf20Sopenharmony_ci * of already scanned zones have been updated 4058c2ecf20Sopenharmony_ci * during the respective zone switches. 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_ci tc = lcn + bmp_pos + 1; 4088c2ecf20Sopenharmony_ci ntfs_debug("Done. Updating current zone " 4098c2ecf20Sopenharmony_ci "position, tc 0x%llx, " 4108c2ecf20Sopenharmony_ci "search_zone %i.", 4118c2ecf20Sopenharmony_ci (unsigned long long)tc, 4128c2ecf20Sopenharmony_ci search_zone); 4138c2ecf20Sopenharmony_ci switch (search_zone) { 4148c2ecf20Sopenharmony_ci case 1: 4158c2ecf20Sopenharmony_ci ntfs_debug("Before checks, " 4168c2ecf20Sopenharmony_ci "vol->mft_zone_pos " 4178c2ecf20Sopenharmony_ci "0x%llx.", 4188c2ecf20Sopenharmony_ci (unsigned long long) 4198c2ecf20Sopenharmony_ci vol->mft_zone_pos); 4208c2ecf20Sopenharmony_ci if (tc >= vol->mft_zone_end) { 4218c2ecf20Sopenharmony_ci vol->mft_zone_pos = 4228c2ecf20Sopenharmony_ci vol->mft_lcn; 4238c2ecf20Sopenharmony_ci if (!vol->mft_zone_end) 4248c2ecf20Sopenharmony_ci vol->mft_zone_pos = 0; 4258c2ecf20Sopenharmony_ci } else if ((bmp_initial_pos >= 4268c2ecf20Sopenharmony_ci vol->mft_zone_pos || 4278c2ecf20Sopenharmony_ci tc > vol->mft_zone_pos) 4288c2ecf20Sopenharmony_ci && tc >= vol->mft_lcn) 4298c2ecf20Sopenharmony_ci vol->mft_zone_pos = tc; 4308c2ecf20Sopenharmony_ci ntfs_debug("After checks, " 4318c2ecf20Sopenharmony_ci "vol->mft_zone_pos " 4328c2ecf20Sopenharmony_ci "0x%llx.", 4338c2ecf20Sopenharmony_ci (unsigned long long) 4348c2ecf20Sopenharmony_ci vol->mft_zone_pos); 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci case 2: 4378c2ecf20Sopenharmony_ci ntfs_debug("Before checks, " 4388c2ecf20Sopenharmony_ci "vol->data1_zone_pos " 4398c2ecf20Sopenharmony_ci "0x%llx.", 4408c2ecf20Sopenharmony_ci (unsigned long long) 4418c2ecf20Sopenharmony_ci vol->data1_zone_pos); 4428c2ecf20Sopenharmony_ci if (tc >= vol->nr_clusters) 4438c2ecf20Sopenharmony_ci vol->data1_zone_pos = 4448c2ecf20Sopenharmony_ci vol->mft_zone_end; 4458c2ecf20Sopenharmony_ci else if ((bmp_initial_pos >= 4468c2ecf20Sopenharmony_ci vol->data1_zone_pos || 4478c2ecf20Sopenharmony_ci tc > vol->data1_zone_pos) 4488c2ecf20Sopenharmony_ci && tc >= vol->mft_zone_end) 4498c2ecf20Sopenharmony_ci vol->data1_zone_pos = tc; 4508c2ecf20Sopenharmony_ci ntfs_debug("After checks, " 4518c2ecf20Sopenharmony_ci "vol->data1_zone_pos " 4528c2ecf20Sopenharmony_ci "0x%llx.", 4538c2ecf20Sopenharmony_ci (unsigned long long) 4548c2ecf20Sopenharmony_ci vol->data1_zone_pos); 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci case 4: 4578c2ecf20Sopenharmony_ci ntfs_debug("Before checks, " 4588c2ecf20Sopenharmony_ci "vol->data2_zone_pos " 4598c2ecf20Sopenharmony_ci "0x%llx.", 4608c2ecf20Sopenharmony_ci (unsigned long long) 4618c2ecf20Sopenharmony_ci vol->data2_zone_pos); 4628c2ecf20Sopenharmony_ci if (tc >= vol->mft_zone_start) 4638c2ecf20Sopenharmony_ci vol->data2_zone_pos = 0; 4648c2ecf20Sopenharmony_ci else if (bmp_initial_pos >= 4658c2ecf20Sopenharmony_ci vol->data2_zone_pos || 4668c2ecf20Sopenharmony_ci tc > vol->data2_zone_pos) 4678c2ecf20Sopenharmony_ci vol->data2_zone_pos = tc; 4688c2ecf20Sopenharmony_ci ntfs_debug("After checks, " 4698c2ecf20Sopenharmony_ci "vol->data2_zone_pos " 4708c2ecf20Sopenharmony_ci "0x%llx.", 4718c2ecf20Sopenharmony_ci (unsigned long long) 4728c2ecf20Sopenharmony_ci vol->data2_zone_pos); 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci default: 4758c2ecf20Sopenharmony_ci BUG(); 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci ntfs_debug("Finished. Going to out."); 4788c2ecf20Sopenharmony_ci goto out; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci lcn++; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci bmp_pos += buf_size; 4838c2ecf20Sopenharmony_ci ntfs_debug("After inner while loop: buf_size 0x%x, lcn " 4848c2ecf20Sopenharmony_ci "0x%llx, bmp_pos 0x%llx, need_writeback %i.", 4858c2ecf20Sopenharmony_ci buf_size, (unsigned long long)lcn, 4868c2ecf20Sopenharmony_ci (unsigned long long)bmp_pos, need_writeback); 4878c2ecf20Sopenharmony_ci if (bmp_pos < zone_end) { 4888c2ecf20Sopenharmony_ci ntfs_debug("Continuing outer while loop, " 4898c2ecf20Sopenharmony_ci "bmp_pos 0x%llx, zone_end 0x%llx.", 4908c2ecf20Sopenharmony_ci (unsigned long long)bmp_pos, 4918c2ecf20Sopenharmony_ci (unsigned long long)zone_end); 4928c2ecf20Sopenharmony_ci continue; 4938c2ecf20Sopenharmony_ci } 4948c2ecf20Sopenharmony_cizone_pass_done: /* Finished with the current zone pass. */ 4958c2ecf20Sopenharmony_ci ntfs_debug("At zone_pass_done, pass %i.", pass); 4968c2ecf20Sopenharmony_ci if (pass == 1) { 4978c2ecf20Sopenharmony_ci /* 4988c2ecf20Sopenharmony_ci * Now do pass 2, scanning the first part of the zone 4998c2ecf20Sopenharmony_ci * we omitted in pass 1. 5008c2ecf20Sopenharmony_ci */ 5018c2ecf20Sopenharmony_ci pass = 2; 5028c2ecf20Sopenharmony_ci zone_end = zone_start; 5038c2ecf20Sopenharmony_ci switch (search_zone) { 5048c2ecf20Sopenharmony_ci case 1: /* mft_zone */ 5058c2ecf20Sopenharmony_ci zone_start = vol->mft_zone_start; 5068c2ecf20Sopenharmony_ci break; 5078c2ecf20Sopenharmony_ci case 2: /* data1_zone */ 5088c2ecf20Sopenharmony_ci zone_start = vol->mft_zone_end; 5098c2ecf20Sopenharmony_ci break; 5108c2ecf20Sopenharmony_ci case 4: /* data2_zone */ 5118c2ecf20Sopenharmony_ci zone_start = 0; 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci default: 5148c2ecf20Sopenharmony_ci BUG(); 5158c2ecf20Sopenharmony_ci } 5168c2ecf20Sopenharmony_ci /* Sanity check. */ 5178c2ecf20Sopenharmony_ci if (zone_end < zone_start) 5188c2ecf20Sopenharmony_ci zone_end = zone_start; 5198c2ecf20Sopenharmony_ci bmp_pos = zone_start; 5208c2ecf20Sopenharmony_ci ntfs_debug("Continuing outer while loop, pass 2, " 5218c2ecf20Sopenharmony_ci "zone_start 0x%llx, zone_end 0x%llx, " 5228c2ecf20Sopenharmony_ci "bmp_pos 0x%llx.", 5238c2ecf20Sopenharmony_ci (unsigned long long)zone_start, 5248c2ecf20Sopenharmony_ci (unsigned long long)zone_end, 5258c2ecf20Sopenharmony_ci (unsigned long long)bmp_pos); 5268c2ecf20Sopenharmony_ci continue; 5278c2ecf20Sopenharmony_ci } /* pass == 2 */ 5288c2ecf20Sopenharmony_cidone_zones_check: 5298c2ecf20Sopenharmony_ci ntfs_debug("At done_zones_check, search_zone %i, done_zones " 5308c2ecf20Sopenharmony_ci "before 0x%x, done_zones after 0x%x.", 5318c2ecf20Sopenharmony_ci search_zone, done_zones, 5328c2ecf20Sopenharmony_ci done_zones | search_zone); 5338c2ecf20Sopenharmony_ci done_zones |= search_zone; 5348c2ecf20Sopenharmony_ci if (done_zones < 7) { 5358c2ecf20Sopenharmony_ci ntfs_debug("Switching zone."); 5368c2ecf20Sopenharmony_ci /* Now switch to the next zone we haven't done yet. */ 5378c2ecf20Sopenharmony_ci pass = 1; 5388c2ecf20Sopenharmony_ci switch (search_zone) { 5398c2ecf20Sopenharmony_ci case 1: 5408c2ecf20Sopenharmony_ci ntfs_debug("Switching from mft zone to data1 " 5418c2ecf20Sopenharmony_ci "zone."); 5428c2ecf20Sopenharmony_ci /* Update mft zone position. */ 5438c2ecf20Sopenharmony_ci if (rlpos) { 5448c2ecf20Sopenharmony_ci LCN tc; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci ntfs_debug("Before checks, " 5478c2ecf20Sopenharmony_ci "vol->mft_zone_pos " 5488c2ecf20Sopenharmony_ci "0x%llx.", 5498c2ecf20Sopenharmony_ci (unsigned long long) 5508c2ecf20Sopenharmony_ci vol->mft_zone_pos); 5518c2ecf20Sopenharmony_ci tc = rl[rlpos - 1].lcn + 5528c2ecf20Sopenharmony_ci rl[rlpos - 1].length; 5538c2ecf20Sopenharmony_ci if (tc >= vol->mft_zone_end) { 5548c2ecf20Sopenharmony_ci vol->mft_zone_pos = 5558c2ecf20Sopenharmony_ci vol->mft_lcn; 5568c2ecf20Sopenharmony_ci if (!vol->mft_zone_end) 5578c2ecf20Sopenharmony_ci vol->mft_zone_pos = 0; 5588c2ecf20Sopenharmony_ci } else if ((bmp_initial_pos >= 5598c2ecf20Sopenharmony_ci vol->mft_zone_pos || 5608c2ecf20Sopenharmony_ci tc > vol->mft_zone_pos) 5618c2ecf20Sopenharmony_ci && tc >= vol->mft_lcn) 5628c2ecf20Sopenharmony_ci vol->mft_zone_pos = tc; 5638c2ecf20Sopenharmony_ci ntfs_debug("After checks, " 5648c2ecf20Sopenharmony_ci "vol->mft_zone_pos " 5658c2ecf20Sopenharmony_ci "0x%llx.", 5668c2ecf20Sopenharmony_ci (unsigned long long) 5678c2ecf20Sopenharmony_ci vol->mft_zone_pos); 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci /* Switch from mft zone to data1 zone. */ 5708c2ecf20Sopenharmony_ciswitch_to_data1_zone: search_zone = 2; 5718c2ecf20Sopenharmony_ci zone_start = bmp_initial_pos = 5728c2ecf20Sopenharmony_ci vol->data1_zone_pos; 5738c2ecf20Sopenharmony_ci zone_end = vol->nr_clusters; 5748c2ecf20Sopenharmony_ci if (zone_start == vol->mft_zone_end) 5758c2ecf20Sopenharmony_ci pass = 2; 5768c2ecf20Sopenharmony_ci if (zone_start >= zone_end) { 5778c2ecf20Sopenharmony_ci vol->data1_zone_pos = zone_start = 5788c2ecf20Sopenharmony_ci vol->mft_zone_end; 5798c2ecf20Sopenharmony_ci pass = 2; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci break; 5828c2ecf20Sopenharmony_ci case 2: 5838c2ecf20Sopenharmony_ci ntfs_debug("Switching from data1 zone to " 5848c2ecf20Sopenharmony_ci "data2 zone."); 5858c2ecf20Sopenharmony_ci /* Update data1 zone position. */ 5868c2ecf20Sopenharmony_ci if (rlpos) { 5878c2ecf20Sopenharmony_ci LCN tc; 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci ntfs_debug("Before checks, " 5908c2ecf20Sopenharmony_ci "vol->data1_zone_pos " 5918c2ecf20Sopenharmony_ci "0x%llx.", 5928c2ecf20Sopenharmony_ci (unsigned long long) 5938c2ecf20Sopenharmony_ci vol->data1_zone_pos); 5948c2ecf20Sopenharmony_ci tc = rl[rlpos - 1].lcn + 5958c2ecf20Sopenharmony_ci rl[rlpos - 1].length; 5968c2ecf20Sopenharmony_ci if (tc >= vol->nr_clusters) 5978c2ecf20Sopenharmony_ci vol->data1_zone_pos = 5988c2ecf20Sopenharmony_ci vol->mft_zone_end; 5998c2ecf20Sopenharmony_ci else if ((bmp_initial_pos >= 6008c2ecf20Sopenharmony_ci vol->data1_zone_pos || 6018c2ecf20Sopenharmony_ci tc > vol->data1_zone_pos) 6028c2ecf20Sopenharmony_ci && tc >= vol->mft_zone_end) 6038c2ecf20Sopenharmony_ci vol->data1_zone_pos = tc; 6048c2ecf20Sopenharmony_ci ntfs_debug("After checks, " 6058c2ecf20Sopenharmony_ci "vol->data1_zone_pos " 6068c2ecf20Sopenharmony_ci "0x%llx.", 6078c2ecf20Sopenharmony_ci (unsigned long long) 6088c2ecf20Sopenharmony_ci vol->data1_zone_pos); 6098c2ecf20Sopenharmony_ci } 6108c2ecf20Sopenharmony_ci /* Switch from data1 zone to data2 zone. */ 6118c2ecf20Sopenharmony_ci search_zone = 4; 6128c2ecf20Sopenharmony_ci zone_start = bmp_initial_pos = 6138c2ecf20Sopenharmony_ci vol->data2_zone_pos; 6148c2ecf20Sopenharmony_ci zone_end = vol->mft_zone_start; 6158c2ecf20Sopenharmony_ci if (!zone_start) 6168c2ecf20Sopenharmony_ci pass = 2; 6178c2ecf20Sopenharmony_ci if (zone_start >= zone_end) { 6188c2ecf20Sopenharmony_ci vol->data2_zone_pos = zone_start = 6198c2ecf20Sopenharmony_ci bmp_initial_pos = 0; 6208c2ecf20Sopenharmony_ci pass = 2; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci break; 6238c2ecf20Sopenharmony_ci case 4: 6248c2ecf20Sopenharmony_ci ntfs_debug("Switching from data2 zone to " 6258c2ecf20Sopenharmony_ci "data1 zone."); 6268c2ecf20Sopenharmony_ci /* Update data2 zone position. */ 6278c2ecf20Sopenharmony_ci if (rlpos) { 6288c2ecf20Sopenharmony_ci LCN tc; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci ntfs_debug("Before checks, " 6318c2ecf20Sopenharmony_ci "vol->data2_zone_pos " 6328c2ecf20Sopenharmony_ci "0x%llx.", 6338c2ecf20Sopenharmony_ci (unsigned long long) 6348c2ecf20Sopenharmony_ci vol->data2_zone_pos); 6358c2ecf20Sopenharmony_ci tc = rl[rlpos - 1].lcn + 6368c2ecf20Sopenharmony_ci rl[rlpos - 1].length; 6378c2ecf20Sopenharmony_ci if (tc >= vol->mft_zone_start) 6388c2ecf20Sopenharmony_ci vol->data2_zone_pos = 0; 6398c2ecf20Sopenharmony_ci else if (bmp_initial_pos >= 6408c2ecf20Sopenharmony_ci vol->data2_zone_pos || 6418c2ecf20Sopenharmony_ci tc > vol->data2_zone_pos) 6428c2ecf20Sopenharmony_ci vol->data2_zone_pos = tc; 6438c2ecf20Sopenharmony_ci ntfs_debug("After checks, " 6448c2ecf20Sopenharmony_ci "vol->data2_zone_pos " 6458c2ecf20Sopenharmony_ci "0x%llx.", 6468c2ecf20Sopenharmony_ci (unsigned long long) 6478c2ecf20Sopenharmony_ci vol->data2_zone_pos); 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci /* Switch from data2 zone to data1 zone. */ 6508c2ecf20Sopenharmony_ci goto switch_to_data1_zone; 6518c2ecf20Sopenharmony_ci default: 6528c2ecf20Sopenharmony_ci BUG(); 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci ntfs_debug("After zone switch, search_zone %i, " 6558c2ecf20Sopenharmony_ci "pass %i, bmp_initial_pos 0x%llx, " 6568c2ecf20Sopenharmony_ci "zone_start 0x%llx, zone_end 0x%llx.", 6578c2ecf20Sopenharmony_ci search_zone, pass, 6588c2ecf20Sopenharmony_ci (unsigned long long)bmp_initial_pos, 6598c2ecf20Sopenharmony_ci (unsigned long long)zone_start, 6608c2ecf20Sopenharmony_ci (unsigned long long)zone_end); 6618c2ecf20Sopenharmony_ci bmp_pos = zone_start; 6628c2ecf20Sopenharmony_ci if (zone_start == zone_end) { 6638c2ecf20Sopenharmony_ci ntfs_debug("Empty zone, going to " 6648c2ecf20Sopenharmony_ci "done_zones_check."); 6658c2ecf20Sopenharmony_ci /* Empty zone. Don't bother searching it. */ 6668c2ecf20Sopenharmony_ci goto done_zones_check; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci ntfs_debug("Continuing outer while loop."); 6698c2ecf20Sopenharmony_ci continue; 6708c2ecf20Sopenharmony_ci } /* done_zones == 7 */ 6718c2ecf20Sopenharmony_ci ntfs_debug("All zones are finished."); 6728c2ecf20Sopenharmony_ci /* 6738c2ecf20Sopenharmony_ci * All zones are finished! If DATA_ZONE, shrink mft zone. If 6748c2ecf20Sopenharmony_ci * MFT_ZONE, we have really run out of space. 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_ci mft_zone_size = vol->mft_zone_end - vol->mft_zone_start; 6778c2ecf20Sopenharmony_ci ntfs_debug("vol->mft_zone_start 0x%llx, vol->mft_zone_end " 6788c2ecf20Sopenharmony_ci "0x%llx, mft_zone_size 0x%llx.", 6798c2ecf20Sopenharmony_ci (unsigned long long)vol->mft_zone_start, 6808c2ecf20Sopenharmony_ci (unsigned long long)vol->mft_zone_end, 6818c2ecf20Sopenharmony_ci (unsigned long long)mft_zone_size); 6828c2ecf20Sopenharmony_ci if (zone == MFT_ZONE || mft_zone_size <= 0) { 6838c2ecf20Sopenharmony_ci ntfs_debug("No free clusters left, going to out."); 6848c2ecf20Sopenharmony_ci /* Really no more space left on device. */ 6858c2ecf20Sopenharmony_ci err = -ENOSPC; 6868c2ecf20Sopenharmony_ci goto out; 6878c2ecf20Sopenharmony_ci } /* zone == DATA_ZONE && mft_zone_size > 0 */ 6888c2ecf20Sopenharmony_ci ntfs_debug("Shrinking mft zone."); 6898c2ecf20Sopenharmony_ci zone_end = vol->mft_zone_end; 6908c2ecf20Sopenharmony_ci mft_zone_size >>= 1; 6918c2ecf20Sopenharmony_ci if (mft_zone_size > 0) 6928c2ecf20Sopenharmony_ci vol->mft_zone_end = vol->mft_zone_start + mft_zone_size; 6938c2ecf20Sopenharmony_ci else /* mft zone and data2 zone no longer exist. */ 6948c2ecf20Sopenharmony_ci vol->data2_zone_pos = vol->mft_zone_start = 6958c2ecf20Sopenharmony_ci vol->mft_zone_end = 0; 6968c2ecf20Sopenharmony_ci if (vol->mft_zone_pos >= vol->mft_zone_end) { 6978c2ecf20Sopenharmony_ci vol->mft_zone_pos = vol->mft_lcn; 6988c2ecf20Sopenharmony_ci if (!vol->mft_zone_end) 6998c2ecf20Sopenharmony_ci vol->mft_zone_pos = 0; 7008c2ecf20Sopenharmony_ci } 7018c2ecf20Sopenharmony_ci bmp_pos = zone_start = bmp_initial_pos = 7028c2ecf20Sopenharmony_ci vol->data1_zone_pos = vol->mft_zone_end; 7038c2ecf20Sopenharmony_ci search_zone = 2; 7048c2ecf20Sopenharmony_ci pass = 2; 7058c2ecf20Sopenharmony_ci done_zones &= ~2; 7068c2ecf20Sopenharmony_ci ntfs_debug("After shrinking mft zone, mft_zone_size 0x%llx, " 7078c2ecf20Sopenharmony_ci "vol->mft_zone_start 0x%llx, " 7088c2ecf20Sopenharmony_ci "vol->mft_zone_end 0x%llx, " 7098c2ecf20Sopenharmony_ci "vol->mft_zone_pos 0x%llx, search_zone 2, " 7108c2ecf20Sopenharmony_ci "pass 2, dones_zones 0x%x, zone_start 0x%llx, " 7118c2ecf20Sopenharmony_ci "zone_end 0x%llx, vol->data1_zone_pos 0x%llx, " 7128c2ecf20Sopenharmony_ci "continuing outer while loop.", 7138c2ecf20Sopenharmony_ci (unsigned long long)mft_zone_size, 7148c2ecf20Sopenharmony_ci (unsigned long long)vol->mft_zone_start, 7158c2ecf20Sopenharmony_ci (unsigned long long)vol->mft_zone_end, 7168c2ecf20Sopenharmony_ci (unsigned long long)vol->mft_zone_pos, 7178c2ecf20Sopenharmony_ci done_zones, (unsigned long long)zone_start, 7188c2ecf20Sopenharmony_ci (unsigned long long)zone_end, 7198c2ecf20Sopenharmony_ci (unsigned long long)vol->data1_zone_pos); 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci ntfs_debug("After outer while loop."); 7228c2ecf20Sopenharmony_ciout: 7238c2ecf20Sopenharmony_ci ntfs_debug("At out."); 7248c2ecf20Sopenharmony_ci /* Add runlist terminator element. */ 7258c2ecf20Sopenharmony_ci if (likely(rl)) { 7268c2ecf20Sopenharmony_ci rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; 7278c2ecf20Sopenharmony_ci rl[rlpos].lcn = is_extension ? LCN_ENOENT : LCN_RL_NOT_MAPPED; 7288c2ecf20Sopenharmony_ci rl[rlpos].length = 0; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci if (likely(page && !IS_ERR(page))) { 7318c2ecf20Sopenharmony_ci if (need_writeback) { 7328c2ecf20Sopenharmony_ci ntfs_debug("Marking page dirty."); 7338c2ecf20Sopenharmony_ci flush_dcache_page(page); 7348c2ecf20Sopenharmony_ci set_page_dirty(page); 7358c2ecf20Sopenharmony_ci need_writeback = 0; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci ntfs_unmap_page(page); 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci if (likely(!err)) { 7408c2ecf20Sopenharmony_ci up_write(&vol->lcnbmp_lock); 7418c2ecf20Sopenharmony_ci ntfs_debug("Done."); 7428c2ecf20Sopenharmony_ci return rl; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to allocate clusters, aborting " 7458c2ecf20Sopenharmony_ci "(error %i).", err); 7468c2ecf20Sopenharmony_ci if (rl) { 7478c2ecf20Sopenharmony_ci int err2; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci if (err == -ENOSPC) 7508c2ecf20Sopenharmony_ci ntfs_debug("Not enough space to complete allocation, " 7518c2ecf20Sopenharmony_ci "err -ENOSPC, first free lcn 0x%llx, " 7528c2ecf20Sopenharmony_ci "could allocate up to 0x%llx " 7538c2ecf20Sopenharmony_ci "clusters.", 7548c2ecf20Sopenharmony_ci (unsigned long long)rl[0].lcn, 7558c2ecf20Sopenharmony_ci (unsigned long long)(count - clusters)); 7568c2ecf20Sopenharmony_ci /* Deallocate all allocated clusters. */ 7578c2ecf20Sopenharmony_ci ntfs_debug("Attempting rollback..."); 7588c2ecf20Sopenharmony_ci err2 = ntfs_cluster_free_from_rl_nolock(vol, rl); 7598c2ecf20Sopenharmony_ci if (err2) { 7608c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to rollback (error %i). " 7618c2ecf20Sopenharmony_ci "Leaving inconsistent metadata! " 7628c2ecf20Sopenharmony_ci "Unmount and run chkdsk.", err2); 7638c2ecf20Sopenharmony_ci NVolSetErrors(vol); 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci /* Free the runlist. */ 7668c2ecf20Sopenharmony_ci ntfs_free(rl); 7678c2ecf20Sopenharmony_ci } else if (err == -ENOSPC) 7688c2ecf20Sopenharmony_ci ntfs_debug("No space left at all, err = -ENOSPC, first free " 7698c2ecf20Sopenharmony_ci "lcn = 0x%llx.", 7708c2ecf20Sopenharmony_ci (long long)vol->data1_zone_pos); 7718c2ecf20Sopenharmony_ci up_write(&vol->lcnbmp_lock); 7728c2ecf20Sopenharmony_ci return ERR_PTR(err); 7738c2ecf20Sopenharmony_ci} 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci/** 7768c2ecf20Sopenharmony_ci * __ntfs_cluster_free - free clusters on an ntfs volume 7778c2ecf20Sopenharmony_ci * @ni: ntfs inode whose runlist describes the clusters to free 7788c2ecf20Sopenharmony_ci * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters 7798c2ecf20Sopenharmony_ci * @count: number of clusters to free or -1 for all clusters 7808c2ecf20Sopenharmony_ci * @ctx: active attribute search context if present or NULL if not 7818c2ecf20Sopenharmony_ci * @is_rollback: true if this is a rollback operation 7828c2ecf20Sopenharmony_ci * 7838c2ecf20Sopenharmony_ci * Free @count clusters starting at the cluster @start_vcn in the runlist 7848c2ecf20Sopenharmony_ci * described by the vfs inode @ni. 7858c2ecf20Sopenharmony_ci * 7868c2ecf20Sopenharmony_ci * If @count is -1, all clusters from @start_vcn to the end of the runlist are 7878c2ecf20Sopenharmony_ci * deallocated. Thus, to completely free all clusters in a runlist, use 7888c2ecf20Sopenharmony_ci * @start_vcn = 0 and @count = -1. 7898c2ecf20Sopenharmony_ci * 7908c2ecf20Sopenharmony_ci * If @ctx is specified, it is an active search context of @ni and its base mft 7918c2ecf20Sopenharmony_ci * record. This is needed when __ntfs_cluster_free() encounters unmapped 7928c2ecf20Sopenharmony_ci * runlist fragments and allows their mapping. If you do not have the mft 7938c2ecf20Sopenharmony_ci * record mapped, you can specify @ctx as NULL and __ntfs_cluster_free() will 7948c2ecf20Sopenharmony_ci * perform the necessary mapping and unmapping. 7958c2ecf20Sopenharmony_ci * 7968c2ecf20Sopenharmony_ci * Note, __ntfs_cluster_free() saves the state of @ctx on entry and restores it 7978c2ecf20Sopenharmony_ci * before returning. Thus, @ctx will be left pointing to the same attribute on 7988c2ecf20Sopenharmony_ci * return as on entry. However, the actual pointers in @ctx may point to 7998c2ecf20Sopenharmony_ci * different memory locations on return, so you must remember to reset any 8008c2ecf20Sopenharmony_ci * cached pointers from the @ctx, i.e. after the call to __ntfs_cluster_free(), 8018c2ecf20Sopenharmony_ci * you will probably want to do: 8028c2ecf20Sopenharmony_ci * m = ctx->mrec; 8038c2ecf20Sopenharmony_ci * a = ctx->attr; 8048c2ecf20Sopenharmony_ci * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that 8058c2ecf20Sopenharmony_ci * you cache ctx->mrec in a variable @m of type MFT_RECORD *. 8068c2ecf20Sopenharmony_ci * 8078c2ecf20Sopenharmony_ci * @is_rollback should always be 'false', it is for internal use to rollback 8088c2ecf20Sopenharmony_ci * errors. You probably want to use ntfs_cluster_free() instead. 8098c2ecf20Sopenharmony_ci * 8108c2ecf20Sopenharmony_ci * Note, __ntfs_cluster_free() does not modify the runlist, so you have to 8118c2ecf20Sopenharmony_ci * remove from the runlist or mark sparse the freed runs later. 8128c2ecf20Sopenharmony_ci * 8138c2ecf20Sopenharmony_ci * Return the number of deallocated clusters (not counting sparse ones) on 8148c2ecf20Sopenharmony_ci * success and -errno on error. 8158c2ecf20Sopenharmony_ci * 8168c2ecf20Sopenharmony_ci * WARNING: If @ctx is supplied, regardless of whether success or failure is 8178c2ecf20Sopenharmony_ci * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx 8188c2ecf20Sopenharmony_ci * is no longer valid, i.e. you need to either call 8198c2ecf20Sopenharmony_ci * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. 8208c2ecf20Sopenharmony_ci * In that case PTR_ERR(@ctx->mrec) will give you the error code for 8218c2ecf20Sopenharmony_ci * why the mapping of the old inode failed. 8228c2ecf20Sopenharmony_ci * 8238c2ecf20Sopenharmony_ci * Locking: - The runlist described by @ni must be locked for writing on entry 8248c2ecf20Sopenharmony_ci * and is locked on return. Note the runlist may be modified when 8258c2ecf20Sopenharmony_ci * needed runlist fragments need to be mapped. 8268c2ecf20Sopenharmony_ci * - The volume lcn bitmap must be unlocked on entry and is unlocked 8278c2ecf20Sopenharmony_ci * on return. 8288c2ecf20Sopenharmony_ci * - This function takes the volume lcn bitmap lock for writing and 8298c2ecf20Sopenharmony_ci * modifies the bitmap contents. 8308c2ecf20Sopenharmony_ci * - If @ctx is NULL, the base mft record of @ni must not be mapped on 8318c2ecf20Sopenharmony_ci * entry and it will be left unmapped on return. 8328c2ecf20Sopenharmony_ci * - If @ctx is not NULL, the base mft record must be mapped on entry 8338c2ecf20Sopenharmony_ci * and it will be left mapped on return. 8348c2ecf20Sopenharmony_ci */ 8358c2ecf20Sopenharmony_cis64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, 8368c2ecf20Sopenharmony_ci ntfs_attr_search_ctx *ctx, const bool is_rollback) 8378c2ecf20Sopenharmony_ci{ 8388c2ecf20Sopenharmony_ci s64 delta, to_free, total_freed, real_freed; 8398c2ecf20Sopenharmony_ci ntfs_volume *vol; 8408c2ecf20Sopenharmony_ci struct inode *lcnbmp_vi; 8418c2ecf20Sopenharmony_ci runlist_element *rl; 8428c2ecf20Sopenharmony_ci int err; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci BUG_ON(!ni); 8458c2ecf20Sopenharmony_ci ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count " 8468c2ecf20Sopenharmony_ci "0x%llx.%s", ni->mft_no, (unsigned long long)start_vcn, 8478c2ecf20Sopenharmony_ci (unsigned long long)count, 8488c2ecf20Sopenharmony_ci is_rollback ? " (rollback)" : ""); 8498c2ecf20Sopenharmony_ci vol = ni->vol; 8508c2ecf20Sopenharmony_ci lcnbmp_vi = vol->lcnbmp_ino; 8518c2ecf20Sopenharmony_ci BUG_ON(!lcnbmp_vi); 8528c2ecf20Sopenharmony_ci BUG_ON(start_vcn < 0); 8538c2ecf20Sopenharmony_ci BUG_ON(count < -1); 8548c2ecf20Sopenharmony_ci /* 8558c2ecf20Sopenharmony_ci * Lock the lcn bitmap for writing but only if not rolling back. We 8568c2ecf20Sopenharmony_ci * must hold the lock all the way including through rollback otherwise 8578c2ecf20Sopenharmony_ci * rollback is not possible because once we have cleared a bit and 8588c2ecf20Sopenharmony_ci * dropped the lock, anyone could have set the bit again, thus 8598c2ecf20Sopenharmony_ci * allocating the cluster for another use. 8608c2ecf20Sopenharmony_ci */ 8618c2ecf20Sopenharmony_ci if (likely(!is_rollback)) 8628c2ecf20Sopenharmony_ci down_write(&vol->lcnbmp_lock); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci total_freed = real_freed = 0; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, ctx); 8678c2ecf20Sopenharmony_ci if (IS_ERR(rl)) { 8688c2ecf20Sopenharmony_ci if (!is_rollback) 8698c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to find first runlist " 8708c2ecf20Sopenharmony_ci "element (error %li), aborting.", 8718c2ecf20Sopenharmony_ci PTR_ERR(rl)); 8728c2ecf20Sopenharmony_ci err = PTR_ERR(rl); 8738c2ecf20Sopenharmony_ci goto err_out; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci if (unlikely(rl->lcn < LCN_HOLE)) { 8768c2ecf20Sopenharmony_ci if (!is_rollback) 8778c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "First runlist element has " 8788c2ecf20Sopenharmony_ci "invalid lcn, aborting."); 8798c2ecf20Sopenharmony_ci err = -EIO; 8808c2ecf20Sopenharmony_ci goto err_out; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci /* Find the starting cluster inside the run that needs freeing. */ 8838c2ecf20Sopenharmony_ci delta = start_vcn - rl->vcn; 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* The number of clusters in this run that need freeing. */ 8868c2ecf20Sopenharmony_ci to_free = rl->length - delta; 8878c2ecf20Sopenharmony_ci if (count >= 0 && to_free > count) 8888c2ecf20Sopenharmony_ci to_free = count; 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (likely(rl->lcn >= 0)) { 8918c2ecf20Sopenharmony_ci /* Do the actual freeing of the clusters in this run. */ 8928c2ecf20Sopenharmony_ci err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn + delta, 8938c2ecf20Sopenharmony_ci to_free, likely(!is_rollback) ? 0 : 1); 8948c2ecf20Sopenharmony_ci if (unlikely(err)) { 8958c2ecf20Sopenharmony_ci if (!is_rollback) 8968c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to clear first run " 8978c2ecf20Sopenharmony_ci "(error %i), aborting.", err); 8988c2ecf20Sopenharmony_ci goto err_out; 8998c2ecf20Sopenharmony_ci } 9008c2ecf20Sopenharmony_ci /* We have freed @to_free real clusters. */ 9018c2ecf20Sopenharmony_ci real_freed = to_free; 9028c2ecf20Sopenharmony_ci }; 9038c2ecf20Sopenharmony_ci /* Go to the next run and adjust the number of clusters left to free. */ 9048c2ecf20Sopenharmony_ci ++rl; 9058c2ecf20Sopenharmony_ci if (count >= 0) 9068c2ecf20Sopenharmony_ci count -= to_free; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci /* Keep track of the total "freed" clusters, including sparse ones. */ 9098c2ecf20Sopenharmony_ci total_freed = to_free; 9108c2ecf20Sopenharmony_ci /* 9118c2ecf20Sopenharmony_ci * Loop over the remaining runs, using @count as a capping value, and 9128c2ecf20Sopenharmony_ci * free them. 9138c2ecf20Sopenharmony_ci */ 9148c2ecf20Sopenharmony_ci for (; rl->length && count != 0; ++rl) { 9158c2ecf20Sopenharmony_ci if (unlikely(rl->lcn < LCN_HOLE)) { 9168c2ecf20Sopenharmony_ci VCN vcn; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* Attempt to map runlist. */ 9198c2ecf20Sopenharmony_ci vcn = rl->vcn; 9208c2ecf20Sopenharmony_ci rl = ntfs_attr_find_vcn_nolock(ni, vcn, ctx); 9218c2ecf20Sopenharmony_ci if (IS_ERR(rl)) { 9228c2ecf20Sopenharmony_ci err = PTR_ERR(rl); 9238c2ecf20Sopenharmony_ci if (!is_rollback) 9248c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to map " 9258c2ecf20Sopenharmony_ci "runlist fragment or " 9268c2ecf20Sopenharmony_ci "failed to find " 9278c2ecf20Sopenharmony_ci "subsequent runlist " 9288c2ecf20Sopenharmony_ci "element."); 9298c2ecf20Sopenharmony_ci goto err_out; 9308c2ecf20Sopenharmony_ci } 9318c2ecf20Sopenharmony_ci if (unlikely(rl->lcn < LCN_HOLE)) { 9328c2ecf20Sopenharmony_ci if (!is_rollback) 9338c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Runlist element " 9348c2ecf20Sopenharmony_ci "has invalid lcn " 9358c2ecf20Sopenharmony_ci "(0x%llx).", 9368c2ecf20Sopenharmony_ci (unsigned long long) 9378c2ecf20Sopenharmony_ci rl->lcn); 9388c2ecf20Sopenharmony_ci err = -EIO; 9398c2ecf20Sopenharmony_ci goto err_out; 9408c2ecf20Sopenharmony_ci } 9418c2ecf20Sopenharmony_ci } 9428c2ecf20Sopenharmony_ci /* The number of clusters in this run that need freeing. */ 9438c2ecf20Sopenharmony_ci to_free = rl->length; 9448c2ecf20Sopenharmony_ci if (count >= 0 && to_free > count) 9458c2ecf20Sopenharmony_ci to_free = count; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci if (likely(rl->lcn >= 0)) { 9488c2ecf20Sopenharmony_ci /* Do the actual freeing of the clusters in the run. */ 9498c2ecf20Sopenharmony_ci err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn, 9508c2ecf20Sopenharmony_ci to_free, likely(!is_rollback) ? 0 : 1); 9518c2ecf20Sopenharmony_ci if (unlikely(err)) { 9528c2ecf20Sopenharmony_ci if (!is_rollback) 9538c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to clear " 9548c2ecf20Sopenharmony_ci "subsequent run."); 9558c2ecf20Sopenharmony_ci goto err_out; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci /* We have freed @to_free real clusters. */ 9588c2ecf20Sopenharmony_ci real_freed += to_free; 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci /* Adjust the number of clusters left to free. */ 9618c2ecf20Sopenharmony_ci if (count >= 0) 9628c2ecf20Sopenharmony_ci count -= to_free; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci /* Update the total done clusters. */ 9658c2ecf20Sopenharmony_ci total_freed += to_free; 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci if (likely(!is_rollback)) 9688c2ecf20Sopenharmony_ci up_write(&vol->lcnbmp_lock); 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci BUG_ON(count > 0); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* We are done. Return the number of actually freed clusters. */ 9738c2ecf20Sopenharmony_ci ntfs_debug("Done."); 9748c2ecf20Sopenharmony_ci return real_freed; 9758c2ecf20Sopenharmony_cierr_out: 9768c2ecf20Sopenharmony_ci if (is_rollback) 9778c2ecf20Sopenharmony_ci return err; 9788c2ecf20Sopenharmony_ci /* If no real clusters were freed, no need to rollback. */ 9798c2ecf20Sopenharmony_ci if (!real_freed) { 9808c2ecf20Sopenharmony_ci up_write(&vol->lcnbmp_lock); 9818c2ecf20Sopenharmony_ci return err; 9828c2ecf20Sopenharmony_ci } 9838c2ecf20Sopenharmony_ci /* 9848c2ecf20Sopenharmony_ci * Attempt to rollback and if that succeeds just return the error code. 9858c2ecf20Sopenharmony_ci * If rollback fails, set the volume errors flag, emit an error 9868c2ecf20Sopenharmony_ci * message, and return the error code. 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_ci delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, true); 9898c2ecf20Sopenharmony_ci if (delta < 0) { 9908c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " 9918c2ecf20Sopenharmony_ci "inconsistent metadata! Unmount and run " 9928c2ecf20Sopenharmony_ci "chkdsk.", (int)delta); 9938c2ecf20Sopenharmony_ci NVolSetErrors(vol); 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci up_write(&vol->lcnbmp_lock); 9968c2ecf20Sopenharmony_ci ntfs_error(vol->sb, "Aborting (error %i).", err); 9978c2ecf20Sopenharmony_ci return err; 9988c2ecf20Sopenharmony_ci} 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci#endif /* NTFS_RW */ 1001