162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * lcnalloc.c - Cluster (de)allocation code. Part of the Linux-NTFS project. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2004-2005 Anton Altaparmakov 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#ifdef NTFS_RW 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/pagemap.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "lcnalloc.h" 1362306a36Sopenharmony_ci#include "debug.h" 1462306a36Sopenharmony_ci#include "bitmap.h" 1562306a36Sopenharmony_ci#include "inode.h" 1662306a36Sopenharmony_ci#include "volume.h" 1762306a36Sopenharmony_ci#include "attrib.h" 1862306a36Sopenharmony_ci#include "malloc.h" 1962306a36Sopenharmony_ci#include "aops.h" 2062306a36Sopenharmony_ci#include "ntfs.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/** 2362306a36Sopenharmony_ci * ntfs_cluster_free_from_rl_nolock - free clusters from runlist 2462306a36Sopenharmony_ci * @vol: mounted ntfs volume on which to free the clusters 2562306a36Sopenharmony_ci * @rl: runlist describing the clusters to free 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Free all the clusters described by the runlist @rl on the volume @vol. In 2862306a36Sopenharmony_ci * the case of an error being returned, at least some of the clusters were not 2962306a36Sopenharmony_ci * freed. 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * Return 0 on success and -errno on error. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * Locking: - The volume lcn bitmap must be locked for writing on entry and is 3462306a36Sopenharmony_ci * left locked on return. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ciint ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol, 3762306a36Sopenharmony_ci const runlist_element *rl) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct inode *lcnbmp_vi = vol->lcnbmp_ino; 4062306a36Sopenharmony_ci int ret = 0; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci ntfs_debug("Entering."); 4362306a36Sopenharmony_ci if (!rl) 4462306a36Sopenharmony_ci return 0; 4562306a36Sopenharmony_ci for (; rl->length; rl++) { 4662306a36Sopenharmony_ci int err; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (rl->lcn < 0) 4962306a36Sopenharmony_ci continue; 5062306a36Sopenharmony_ci err = ntfs_bitmap_clear_run(lcnbmp_vi, rl->lcn, rl->length); 5162306a36Sopenharmony_ci if (unlikely(err && (!ret || ret == -ENOMEM) && ret != err)) 5262306a36Sopenharmony_ci ret = err; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci ntfs_debug("Done."); 5562306a36Sopenharmony_ci return ret; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * ntfs_cluster_alloc - allocate clusters on an ntfs volume 6062306a36Sopenharmony_ci * @vol: mounted ntfs volume on which to allocate the clusters 6162306a36Sopenharmony_ci * @start_vcn: vcn to use for the first allocated cluster 6262306a36Sopenharmony_ci * @count: number of clusters to allocate 6362306a36Sopenharmony_ci * @start_lcn: starting lcn at which to allocate the clusters (or -1 if none) 6462306a36Sopenharmony_ci * @zone: zone from which to allocate the clusters 6562306a36Sopenharmony_ci * @is_extension: if 'true', this is an attribute extension 6662306a36Sopenharmony_ci * 6762306a36Sopenharmony_ci * Allocate @count clusters preferably starting at cluster @start_lcn or at the 6862306a36Sopenharmony_ci * current allocator position if @start_lcn is -1, on the mounted ntfs volume 6962306a36Sopenharmony_ci * @vol. @zone is either DATA_ZONE for allocation of normal clusters or 7062306a36Sopenharmony_ci * MFT_ZONE for allocation of clusters for the master file table, i.e. the 7162306a36Sopenharmony_ci * $MFT/$DATA attribute. 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * @start_vcn specifies the vcn of the first allocated cluster. This makes 7462306a36Sopenharmony_ci * merging the resulting runlist with the old runlist easier. 7562306a36Sopenharmony_ci * 7662306a36Sopenharmony_ci * If @is_extension is 'true', the caller is allocating clusters to extend an 7762306a36Sopenharmony_ci * attribute and if it is 'false', the caller is allocating clusters to fill a 7862306a36Sopenharmony_ci * hole in an attribute. Practically the difference is that if @is_extension 7962306a36Sopenharmony_ci * is 'true' the returned runlist will be terminated with LCN_ENOENT and if 8062306a36Sopenharmony_ci * @is_extension is 'false' the runlist will be terminated with 8162306a36Sopenharmony_ci * LCN_RL_NOT_MAPPED. 8262306a36Sopenharmony_ci * 8362306a36Sopenharmony_ci * You need to check the return value with IS_ERR(). If this is false, the 8462306a36Sopenharmony_ci * function was successful and the return value is a runlist describing the 8562306a36Sopenharmony_ci * allocated cluster(s). If IS_ERR() is true, the function failed and 8662306a36Sopenharmony_ci * PTR_ERR() gives you the error code. 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * Notes on the allocation algorithm 8962306a36Sopenharmony_ci * ================================= 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * There are two data zones. First is the area between the end of the mft zone 9262306a36Sopenharmony_ci * and the end of the volume, and second is the area between the start of the 9362306a36Sopenharmony_ci * volume and the start of the mft zone. On unmodified/standard NTFS 1.x 9462306a36Sopenharmony_ci * volumes, the second data zone does not exist due to the mft zone being 9562306a36Sopenharmony_ci * expanded to cover the start of the volume in order to reserve space for the 9662306a36Sopenharmony_ci * mft bitmap attribute. 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * This is not the prettiest function but the complexity stems from the need of 9962306a36Sopenharmony_ci * implementing the mft vs data zoned approach and from the fact that we have 10062306a36Sopenharmony_ci * access to the lcn bitmap in portions of up to 8192 bytes at a time, so we 10162306a36Sopenharmony_ci * need to cope with crossing over boundaries of two buffers. Further, the 10262306a36Sopenharmony_ci * fact that the allocator allows for caller supplied hints as to the location 10362306a36Sopenharmony_ci * of where allocation should begin and the fact that the allocator keeps track 10462306a36Sopenharmony_ci * of where in the data zones the next natural allocation should occur, 10562306a36Sopenharmony_ci * contribute to the complexity of the function. But it should all be 10662306a36Sopenharmony_ci * worthwhile, because this allocator should: 1) be a full implementation of 10762306a36Sopenharmony_ci * the MFT zone approach used by Windows NT, 2) cause reduction in 10862306a36Sopenharmony_ci * fragmentation, and 3) be speedy in allocations (the code is not optimized 10962306a36Sopenharmony_ci * for speed, but the algorithm is, so further speed improvements are probably 11062306a36Sopenharmony_ci * possible). 11162306a36Sopenharmony_ci * 11262306a36Sopenharmony_ci * FIXME: We should be monitoring cluster allocation and increment the MFT zone 11362306a36Sopenharmony_ci * size dynamically but this is something for the future. We will just cause 11462306a36Sopenharmony_ci * heavier fragmentation by not doing it and I am not even sure Windows would 11562306a36Sopenharmony_ci * grow the MFT zone dynamically, so it might even be correct not to do this. 11662306a36Sopenharmony_ci * The overhead in doing dynamic MFT zone expansion would be very large and 11762306a36Sopenharmony_ci * unlikely worth the effort. (AIA) 11862306a36Sopenharmony_ci * 11962306a36Sopenharmony_ci * TODO: I have added in double the required zone position pointer wrap around 12062306a36Sopenharmony_ci * logic which can be optimized to having only one of the two logic sets. 12162306a36Sopenharmony_ci * However, having the double logic will work fine, but if we have only one of 12262306a36Sopenharmony_ci * the sets and we get it wrong somewhere, then we get into trouble, so 12362306a36Sopenharmony_ci * removing the duplicate logic requires _very_ careful consideration of _all_ 12462306a36Sopenharmony_ci * possible code paths. So at least for now, I am leaving the double logic - 12562306a36Sopenharmony_ci * better safe than sorry... (AIA) 12662306a36Sopenharmony_ci * 12762306a36Sopenharmony_ci * Locking: - The volume lcn bitmap must be unlocked on entry and is unlocked 12862306a36Sopenharmony_ci * on return. 12962306a36Sopenharmony_ci * - This function takes the volume lcn bitmap lock for writing and 13062306a36Sopenharmony_ci * modifies the bitmap contents. 13162306a36Sopenharmony_ci */ 13262306a36Sopenharmony_cirunlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn, 13362306a36Sopenharmony_ci const s64 count, const LCN start_lcn, 13462306a36Sopenharmony_ci const NTFS_CLUSTER_ALLOCATION_ZONES zone, 13562306a36Sopenharmony_ci const bool is_extension) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn; 13862306a36Sopenharmony_ci LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size; 13962306a36Sopenharmony_ci s64 clusters; 14062306a36Sopenharmony_ci loff_t i_size; 14162306a36Sopenharmony_ci struct inode *lcnbmp_vi; 14262306a36Sopenharmony_ci runlist_element *rl = NULL; 14362306a36Sopenharmony_ci struct address_space *mapping; 14462306a36Sopenharmony_ci struct page *page = NULL; 14562306a36Sopenharmony_ci u8 *buf, *byte; 14662306a36Sopenharmony_ci int err = 0, rlpos, rlsize, buf_size; 14762306a36Sopenharmony_ci u8 pass, done_zones, search_zone, need_writeback = 0, bit; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci ntfs_debug("Entering for start_vcn 0x%llx, count 0x%llx, start_lcn " 15062306a36Sopenharmony_ci "0x%llx, zone %s_ZONE.", (unsigned long long)start_vcn, 15162306a36Sopenharmony_ci (unsigned long long)count, 15262306a36Sopenharmony_ci (unsigned long long)start_lcn, 15362306a36Sopenharmony_ci zone == MFT_ZONE ? "MFT" : "DATA"); 15462306a36Sopenharmony_ci BUG_ON(!vol); 15562306a36Sopenharmony_ci lcnbmp_vi = vol->lcnbmp_ino; 15662306a36Sopenharmony_ci BUG_ON(!lcnbmp_vi); 15762306a36Sopenharmony_ci BUG_ON(start_vcn < 0); 15862306a36Sopenharmony_ci BUG_ON(count < 0); 15962306a36Sopenharmony_ci BUG_ON(start_lcn < -1); 16062306a36Sopenharmony_ci BUG_ON(zone < FIRST_ZONE); 16162306a36Sopenharmony_ci BUG_ON(zone > LAST_ZONE); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci /* Return NULL if @count is zero. */ 16462306a36Sopenharmony_ci if (!count) 16562306a36Sopenharmony_ci return NULL; 16662306a36Sopenharmony_ci /* Take the lcnbmp lock for writing. */ 16762306a36Sopenharmony_ci down_write(&vol->lcnbmp_lock); 16862306a36Sopenharmony_ci /* 16962306a36Sopenharmony_ci * If no specific @start_lcn was requested, use the current data zone 17062306a36Sopenharmony_ci * position, otherwise use the requested @start_lcn but make sure it 17162306a36Sopenharmony_ci * lies outside the mft zone. Also set done_zones to 0 (no zones done) 17262306a36Sopenharmony_ci * and pass depending on whether we are starting inside a zone (1) or 17362306a36Sopenharmony_ci * at the beginning of a zone (2). If requesting from the MFT_ZONE, 17462306a36Sopenharmony_ci * we either start at the current position within the mft zone or at 17562306a36Sopenharmony_ci * the specified position. If the latter is out of bounds then we start 17662306a36Sopenharmony_ci * at the beginning of the MFT_ZONE. 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci done_zones = 0; 17962306a36Sopenharmony_ci pass = 1; 18062306a36Sopenharmony_ci /* 18162306a36Sopenharmony_ci * zone_start and zone_end are the current search range. search_zone 18262306a36Sopenharmony_ci * is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of 18362306a36Sopenharmony_ci * volume) and 4 for data zone 2 (start of volume till start of mft 18462306a36Sopenharmony_ci * zone). 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci zone_start = start_lcn; 18762306a36Sopenharmony_ci if (zone_start < 0) { 18862306a36Sopenharmony_ci if (zone == DATA_ZONE) 18962306a36Sopenharmony_ci zone_start = vol->data1_zone_pos; 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci zone_start = vol->mft_zone_pos; 19262306a36Sopenharmony_ci if (!zone_start) { 19362306a36Sopenharmony_ci /* 19462306a36Sopenharmony_ci * Zone starts at beginning of volume which means a 19562306a36Sopenharmony_ci * single pass is sufficient. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci pass = 2; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci } else if (zone == DATA_ZONE && zone_start >= vol->mft_zone_start && 20062306a36Sopenharmony_ci zone_start < vol->mft_zone_end) { 20162306a36Sopenharmony_ci zone_start = vol->mft_zone_end; 20262306a36Sopenharmony_ci /* 20362306a36Sopenharmony_ci * Starting at beginning of data1_zone which means a single 20462306a36Sopenharmony_ci * pass in this zone is sufficient. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci pass = 2; 20762306a36Sopenharmony_ci } else if (zone == MFT_ZONE && (zone_start < vol->mft_zone_start || 20862306a36Sopenharmony_ci zone_start >= vol->mft_zone_end)) { 20962306a36Sopenharmony_ci zone_start = vol->mft_lcn; 21062306a36Sopenharmony_ci if (!vol->mft_zone_end) 21162306a36Sopenharmony_ci zone_start = 0; 21262306a36Sopenharmony_ci /* 21362306a36Sopenharmony_ci * Starting at beginning of volume which means a single pass 21462306a36Sopenharmony_ci * is sufficient. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci pass = 2; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci if (zone == MFT_ZONE) { 21962306a36Sopenharmony_ci zone_end = vol->mft_zone_end; 22062306a36Sopenharmony_ci search_zone = 1; 22162306a36Sopenharmony_ci } else /* if (zone == DATA_ZONE) */ { 22262306a36Sopenharmony_ci /* Skip searching the mft zone. */ 22362306a36Sopenharmony_ci done_zones |= 1; 22462306a36Sopenharmony_ci if (zone_start >= vol->mft_zone_end) { 22562306a36Sopenharmony_ci zone_end = vol->nr_clusters; 22662306a36Sopenharmony_ci search_zone = 2; 22762306a36Sopenharmony_ci } else { 22862306a36Sopenharmony_ci zone_end = vol->mft_zone_start; 22962306a36Sopenharmony_ci search_zone = 4; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci /* 23362306a36Sopenharmony_ci * bmp_pos is the current bit position inside the bitmap. We use 23462306a36Sopenharmony_ci * bmp_initial_pos to determine whether or not to do a zone switch. 23562306a36Sopenharmony_ci */ 23662306a36Sopenharmony_ci bmp_pos = bmp_initial_pos = zone_start; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Loop until all clusters are allocated, i.e. clusters == 0. */ 23962306a36Sopenharmony_ci clusters = count; 24062306a36Sopenharmony_ci rlpos = rlsize = 0; 24162306a36Sopenharmony_ci mapping = lcnbmp_vi->i_mapping; 24262306a36Sopenharmony_ci i_size = i_size_read(lcnbmp_vi); 24362306a36Sopenharmony_ci while (1) { 24462306a36Sopenharmony_ci ntfs_debug("Start of outer while loop: done_zones 0x%x, " 24562306a36Sopenharmony_ci "search_zone %i, pass %i, zone_start 0x%llx, " 24662306a36Sopenharmony_ci "zone_end 0x%llx, bmp_initial_pos 0x%llx, " 24762306a36Sopenharmony_ci "bmp_pos 0x%llx, rlpos %i, rlsize %i.", 24862306a36Sopenharmony_ci done_zones, search_zone, pass, 24962306a36Sopenharmony_ci (unsigned long long)zone_start, 25062306a36Sopenharmony_ci (unsigned long long)zone_end, 25162306a36Sopenharmony_ci (unsigned long long)bmp_initial_pos, 25262306a36Sopenharmony_ci (unsigned long long)bmp_pos, rlpos, rlsize); 25362306a36Sopenharmony_ci /* Loop until we run out of free clusters. */ 25462306a36Sopenharmony_ci last_read_pos = bmp_pos >> 3; 25562306a36Sopenharmony_ci ntfs_debug("last_read_pos 0x%llx.", 25662306a36Sopenharmony_ci (unsigned long long)last_read_pos); 25762306a36Sopenharmony_ci if (last_read_pos > i_size) { 25862306a36Sopenharmony_ci ntfs_debug("End of attribute reached. " 25962306a36Sopenharmony_ci "Skipping to zone_pass_done."); 26062306a36Sopenharmony_ci goto zone_pass_done; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci if (likely(page)) { 26362306a36Sopenharmony_ci if (need_writeback) { 26462306a36Sopenharmony_ci ntfs_debug("Marking page dirty."); 26562306a36Sopenharmony_ci flush_dcache_page(page); 26662306a36Sopenharmony_ci set_page_dirty(page); 26762306a36Sopenharmony_ci need_writeback = 0; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci ntfs_unmap_page(page); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci page = ntfs_map_page(mapping, last_read_pos >> 27262306a36Sopenharmony_ci PAGE_SHIFT); 27362306a36Sopenharmony_ci if (IS_ERR(page)) { 27462306a36Sopenharmony_ci err = PTR_ERR(page); 27562306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to map page."); 27662306a36Sopenharmony_ci goto out; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci buf_size = last_read_pos & ~PAGE_MASK; 27962306a36Sopenharmony_ci buf = page_address(page) + buf_size; 28062306a36Sopenharmony_ci buf_size = PAGE_SIZE - buf_size; 28162306a36Sopenharmony_ci if (unlikely(last_read_pos + buf_size > i_size)) 28262306a36Sopenharmony_ci buf_size = i_size - last_read_pos; 28362306a36Sopenharmony_ci buf_size <<= 3; 28462306a36Sopenharmony_ci lcn = bmp_pos & 7; 28562306a36Sopenharmony_ci bmp_pos &= ~(LCN)7; 28662306a36Sopenharmony_ci ntfs_debug("Before inner while loop: buf_size %i, lcn 0x%llx, " 28762306a36Sopenharmony_ci "bmp_pos 0x%llx, need_writeback %i.", buf_size, 28862306a36Sopenharmony_ci (unsigned long long)lcn, 28962306a36Sopenharmony_ci (unsigned long long)bmp_pos, need_writeback); 29062306a36Sopenharmony_ci while (lcn < buf_size && lcn + bmp_pos < zone_end) { 29162306a36Sopenharmony_ci byte = buf + (lcn >> 3); 29262306a36Sopenharmony_ci ntfs_debug("In inner while loop: buf_size %i, " 29362306a36Sopenharmony_ci "lcn 0x%llx, bmp_pos 0x%llx, " 29462306a36Sopenharmony_ci "need_writeback %i, byte ofs 0x%x, " 29562306a36Sopenharmony_ci "*byte 0x%x.", buf_size, 29662306a36Sopenharmony_ci (unsigned long long)lcn, 29762306a36Sopenharmony_ci (unsigned long long)bmp_pos, 29862306a36Sopenharmony_ci need_writeback, 29962306a36Sopenharmony_ci (unsigned int)(lcn >> 3), 30062306a36Sopenharmony_ci (unsigned int)*byte); 30162306a36Sopenharmony_ci /* Skip full bytes. */ 30262306a36Sopenharmony_ci if (*byte == 0xff) { 30362306a36Sopenharmony_ci lcn = (lcn + 8) & ~(LCN)7; 30462306a36Sopenharmony_ci ntfs_debug("Continuing while loop 1."); 30562306a36Sopenharmony_ci continue; 30662306a36Sopenharmony_ci } 30762306a36Sopenharmony_ci bit = 1 << (lcn & 7); 30862306a36Sopenharmony_ci ntfs_debug("bit 0x%x.", bit); 30962306a36Sopenharmony_ci /* If the bit is already set, go onto the next one. */ 31062306a36Sopenharmony_ci if (*byte & bit) { 31162306a36Sopenharmony_ci lcn++; 31262306a36Sopenharmony_ci ntfs_debug("Continuing while loop 2."); 31362306a36Sopenharmony_ci continue; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci /* 31662306a36Sopenharmony_ci * Allocate more memory if needed, including space for 31762306a36Sopenharmony_ci * the terminator element. 31862306a36Sopenharmony_ci * ntfs_malloc_nofs() operates on whole pages only. 31962306a36Sopenharmony_ci */ 32062306a36Sopenharmony_ci if ((rlpos + 2) * sizeof(*rl) > rlsize) { 32162306a36Sopenharmony_ci runlist_element *rl2; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ntfs_debug("Reallocating memory."); 32462306a36Sopenharmony_ci if (!rl) 32562306a36Sopenharmony_ci ntfs_debug("First free bit is at LCN " 32662306a36Sopenharmony_ci "0x%llx.", 32762306a36Sopenharmony_ci (unsigned long long) 32862306a36Sopenharmony_ci (lcn + bmp_pos)); 32962306a36Sopenharmony_ci rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE); 33062306a36Sopenharmony_ci if (unlikely(!rl2)) { 33162306a36Sopenharmony_ci err = -ENOMEM; 33262306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to " 33362306a36Sopenharmony_ci "allocate memory."); 33462306a36Sopenharmony_ci goto out; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci memcpy(rl2, rl, rlsize); 33762306a36Sopenharmony_ci ntfs_free(rl); 33862306a36Sopenharmony_ci rl = rl2; 33962306a36Sopenharmony_ci rlsize += PAGE_SIZE; 34062306a36Sopenharmony_ci ntfs_debug("Reallocated memory, rlsize 0x%x.", 34162306a36Sopenharmony_ci rlsize); 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci /* Allocate the bitmap bit. */ 34462306a36Sopenharmony_ci *byte |= bit; 34562306a36Sopenharmony_ci /* We need to write this bitmap page to disk. */ 34662306a36Sopenharmony_ci need_writeback = 1; 34762306a36Sopenharmony_ci ntfs_debug("*byte 0x%x, need_writeback is set.", 34862306a36Sopenharmony_ci (unsigned int)*byte); 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * Coalesce with previous run if adjacent LCNs. 35162306a36Sopenharmony_ci * Otherwise, append a new run. 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci ntfs_debug("Adding run (lcn 0x%llx, len 0x%llx), " 35462306a36Sopenharmony_ci "prev_lcn 0x%llx, lcn 0x%llx, " 35562306a36Sopenharmony_ci "bmp_pos 0x%llx, prev_run_len 0x%llx, " 35662306a36Sopenharmony_ci "rlpos %i.", 35762306a36Sopenharmony_ci (unsigned long long)(lcn + bmp_pos), 35862306a36Sopenharmony_ci 1ULL, (unsigned long long)prev_lcn, 35962306a36Sopenharmony_ci (unsigned long long)lcn, 36062306a36Sopenharmony_ci (unsigned long long)bmp_pos, 36162306a36Sopenharmony_ci (unsigned long long)prev_run_len, 36262306a36Sopenharmony_ci rlpos); 36362306a36Sopenharmony_ci if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) { 36462306a36Sopenharmony_ci ntfs_debug("Coalescing to run (lcn 0x%llx, " 36562306a36Sopenharmony_ci "len 0x%llx).", 36662306a36Sopenharmony_ci (unsigned long long) 36762306a36Sopenharmony_ci rl[rlpos - 1].lcn, 36862306a36Sopenharmony_ci (unsigned long long) 36962306a36Sopenharmony_ci rl[rlpos - 1].length); 37062306a36Sopenharmony_ci rl[rlpos - 1].length = ++prev_run_len; 37162306a36Sopenharmony_ci ntfs_debug("Run now (lcn 0x%llx, len 0x%llx), " 37262306a36Sopenharmony_ci "prev_run_len 0x%llx.", 37362306a36Sopenharmony_ci (unsigned long long) 37462306a36Sopenharmony_ci rl[rlpos - 1].lcn, 37562306a36Sopenharmony_ci (unsigned long long) 37662306a36Sopenharmony_ci rl[rlpos - 1].length, 37762306a36Sopenharmony_ci (unsigned long long) 37862306a36Sopenharmony_ci prev_run_len); 37962306a36Sopenharmony_ci } else { 38062306a36Sopenharmony_ci if (likely(rlpos)) { 38162306a36Sopenharmony_ci ntfs_debug("Adding new run, (previous " 38262306a36Sopenharmony_ci "run lcn 0x%llx, " 38362306a36Sopenharmony_ci "len 0x%llx).", 38462306a36Sopenharmony_ci (unsigned long long) 38562306a36Sopenharmony_ci rl[rlpos - 1].lcn, 38662306a36Sopenharmony_ci (unsigned long long) 38762306a36Sopenharmony_ci rl[rlpos - 1].length); 38862306a36Sopenharmony_ci rl[rlpos].vcn = rl[rlpos - 1].vcn + 38962306a36Sopenharmony_ci prev_run_len; 39062306a36Sopenharmony_ci } else { 39162306a36Sopenharmony_ci ntfs_debug("Adding new run, is first " 39262306a36Sopenharmony_ci "run."); 39362306a36Sopenharmony_ci rl[rlpos].vcn = start_vcn; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci rl[rlpos].lcn = prev_lcn = lcn + bmp_pos; 39662306a36Sopenharmony_ci rl[rlpos].length = prev_run_len = 1; 39762306a36Sopenharmony_ci rlpos++; 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci /* Done? */ 40062306a36Sopenharmony_ci if (!--clusters) { 40162306a36Sopenharmony_ci LCN tc; 40262306a36Sopenharmony_ci /* 40362306a36Sopenharmony_ci * Update the current zone position. Positions 40462306a36Sopenharmony_ci * of already scanned zones have been updated 40562306a36Sopenharmony_ci * during the respective zone switches. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ci tc = lcn + bmp_pos + 1; 40862306a36Sopenharmony_ci ntfs_debug("Done. Updating current zone " 40962306a36Sopenharmony_ci "position, tc 0x%llx, " 41062306a36Sopenharmony_ci "search_zone %i.", 41162306a36Sopenharmony_ci (unsigned long long)tc, 41262306a36Sopenharmony_ci search_zone); 41362306a36Sopenharmony_ci switch (search_zone) { 41462306a36Sopenharmony_ci case 1: 41562306a36Sopenharmony_ci ntfs_debug("Before checks, " 41662306a36Sopenharmony_ci "vol->mft_zone_pos " 41762306a36Sopenharmony_ci "0x%llx.", 41862306a36Sopenharmony_ci (unsigned long long) 41962306a36Sopenharmony_ci vol->mft_zone_pos); 42062306a36Sopenharmony_ci if (tc >= vol->mft_zone_end) { 42162306a36Sopenharmony_ci vol->mft_zone_pos = 42262306a36Sopenharmony_ci vol->mft_lcn; 42362306a36Sopenharmony_ci if (!vol->mft_zone_end) 42462306a36Sopenharmony_ci vol->mft_zone_pos = 0; 42562306a36Sopenharmony_ci } else if ((bmp_initial_pos >= 42662306a36Sopenharmony_ci vol->mft_zone_pos || 42762306a36Sopenharmony_ci tc > vol->mft_zone_pos) 42862306a36Sopenharmony_ci && tc >= vol->mft_lcn) 42962306a36Sopenharmony_ci vol->mft_zone_pos = tc; 43062306a36Sopenharmony_ci ntfs_debug("After checks, " 43162306a36Sopenharmony_ci "vol->mft_zone_pos " 43262306a36Sopenharmony_ci "0x%llx.", 43362306a36Sopenharmony_ci (unsigned long long) 43462306a36Sopenharmony_ci vol->mft_zone_pos); 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci case 2: 43762306a36Sopenharmony_ci ntfs_debug("Before checks, " 43862306a36Sopenharmony_ci "vol->data1_zone_pos " 43962306a36Sopenharmony_ci "0x%llx.", 44062306a36Sopenharmony_ci (unsigned long long) 44162306a36Sopenharmony_ci vol->data1_zone_pos); 44262306a36Sopenharmony_ci if (tc >= vol->nr_clusters) 44362306a36Sopenharmony_ci vol->data1_zone_pos = 44462306a36Sopenharmony_ci vol->mft_zone_end; 44562306a36Sopenharmony_ci else if ((bmp_initial_pos >= 44662306a36Sopenharmony_ci vol->data1_zone_pos || 44762306a36Sopenharmony_ci tc > vol->data1_zone_pos) 44862306a36Sopenharmony_ci && tc >= vol->mft_zone_end) 44962306a36Sopenharmony_ci vol->data1_zone_pos = tc; 45062306a36Sopenharmony_ci ntfs_debug("After checks, " 45162306a36Sopenharmony_ci "vol->data1_zone_pos " 45262306a36Sopenharmony_ci "0x%llx.", 45362306a36Sopenharmony_ci (unsigned long long) 45462306a36Sopenharmony_ci vol->data1_zone_pos); 45562306a36Sopenharmony_ci break; 45662306a36Sopenharmony_ci case 4: 45762306a36Sopenharmony_ci ntfs_debug("Before checks, " 45862306a36Sopenharmony_ci "vol->data2_zone_pos " 45962306a36Sopenharmony_ci "0x%llx.", 46062306a36Sopenharmony_ci (unsigned long long) 46162306a36Sopenharmony_ci vol->data2_zone_pos); 46262306a36Sopenharmony_ci if (tc >= vol->mft_zone_start) 46362306a36Sopenharmony_ci vol->data2_zone_pos = 0; 46462306a36Sopenharmony_ci else if (bmp_initial_pos >= 46562306a36Sopenharmony_ci vol->data2_zone_pos || 46662306a36Sopenharmony_ci tc > vol->data2_zone_pos) 46762306a36Sopenharmony_ci vol->data2_zone_pos = tc; 46862306a36Sopenharmony_ci ntfs_debug("After checks, " 46962306a36Sopenharmony_ci "vol->data2_zone_pos " 47062306a36Sopenharmony_ci "0x%llx.", 47162306a36Sopenharmony_ci (unsigned long long) 47262306a36Sopenharmony_ci vol->data2_zone_pos); 47362306a36Sopenharmony_ci break; 47462306a36Sopenharmony_ci default: 47562306a36Sopenharmony_ci BUG(); 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci ntfs_debug("Finished. Going to out."); 47862306a36Sopenharmony_ci goto out; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci lcn++; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci bmp_pos += buf_size; 48362306a36Sopenharmony_ci ntfs_debug("After inner while loop: buf_size 0x%x, lcn " 48462306a36Sopenharmony_ci "0x%llx, bmp_pos 0x%llx, need_writeback %i.", 48562306a36Sopenharmony_ci buf_size, (unsigned long long)lcn, 48662306a36Sopenharmony_ci (unsigned long long)bmp_pos, need_writeback); 48762306a36Sopenharmony_ci if (bmp_pos < zone_end) { 48862306a36Sopenharmony_ci ntfs_debug("Continuing outer while loop, " 48962306a36Sopenharmony_ci "bmp_pos 0x%llx, zone_end 0x%llx.", 49062306a36Sopenharmony_ci (unsigned long long)bmp_pos, 49162306a36Sopenharmony_ci (unsigned long long)zone_end); 49262306a36Sopenharmony_ci continue; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_cizone_pass_done: /* Finished with the current zone pass. */ 49562306a36Sopenharmony_ci ntfs_debug("At zone_pass_done, pass %i.", pass); 49662306a36Sopenharmony_ci if (pass == 1) { 49762306a36Sopenharmony_ci /* 49862306a36Sopenharmony_ci * Now do pass 2, scanning the first part of the zone 49962306a36Sopenharmony_ci * we omitted in pass 1. 50062306a36Sopenharmony_ci */ 50162306a36Sopenharmony_ci pass = 2; 50262306a36Sopenharmony_ci zone_end = zone_start; 50362306a36Sopenharmony_ci switch (search_zone) { 50462306a36Sopenharmony_ci case 1: /* mft_zone */ 50562306a36Sopenharmony_ci zone_start = vol->mft_zone_start; 50662306a36Sopenharmony_ci break; 50762306a36Sopenharmony_ci case 2: /* data1_zone */ 50862306a36Sopenharmony_ci zone_start = vol->mft_zone_end; 50962306a36Sopenharmony_ci break; 51062306a36Sopenharmony_ci case 4: /* data2_zone */ 51162306a36Sopenharmony_ci zone_start = 0; 51262306a36Sopenharmony_ci break; 51362306a36Sopenharmony_ci default: 51462306a36Sopenharmony_ci BUG(); 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci /* Sanity check. */ 51762306a36Sopenharmony_ci if (zone_end < zone_start) 51862306a36Sopenharmony_ci zone_end = zone_start; 51962306a36Sopenharmony_ci bmp_pos = zone_start; 52062306a36Sopenharmony_ci ntfs_debug("Continuing outer while loop, pass 2, " 52162306a36Sopenharmony_ci "zone_start 0x%llx, zone_end 0x%llx, " 52262306a36Sopenharmony_ci "bmp_pos 0x%llx.", 52362306a36Sopenharmony_ci (unsigned long long)zone_start, 52462306a36Sopenharmony_ci (unsigned long long)zone_end, 52562306a36Sopenharmony_ci (unsigned long long)bmp_pos); 52662306a36Sopenharmony_ci continue; 52762306a36Sopenharmony_ci } /* pass == 2 */ 52862306a36Sopenharmony_cidone_zones_check: 52962306a36Sopenharmony_ci ntfs_debug("At done_zones_check, search_zone %i, done_zones " 53062306a36Sopenharmony_ci "before 0x%x, done_zones after 0x%x.", 53162306a36Sopenharmony_ci search_zone, done_zones, 53262306a36Sopenharmony_ci done_zones | search_zone); 53362306a36Sopenharmony_ci done_zones |= search_zone; 53462306a36Sopenharmony_ci if (done_zones < 7) { 53562306a36Sopenharmony_ci ntfs_debug("Switching zone."); 53662306a36Sopenharmony_ci /* Now switch to the next zone we haven't done yet. */ 53762306a36Sopenharmony_ci pass = 1; 53862306a36Sopenharmony_ci switch (search_zone) { 53962306a36Sopenharmony_ci case 1: 54062306a36Sopenharmony_ci ntfs_debug("Switching from mft zone to data1 " 54162306a36Sopenharmony_ci "zone."); 54262306a36Sopenharmony_ci /* Update mft zone position. */ 54362306a36Sopenharmony_ci if (rlpos) { 54462306a36Sopenharmony_ci LCN tc; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci ntfs_debug("Before checks, " 54762306a36Sopenharmony_ci "vol->mft_zone_pos " 54862306a36Sopenharmony_ci "0x%llx.", 54962306a36Sopenharmony_ci (unsigned long long) 55062306a36Sopenharmony_ci vol->mft_zone_pos); 55162306a36Sopenharmony_ci tc = rl[rlpos - 1].lcn + 55262306a36Sopenharmony_ci rl[rlpos - 1].length; 55362306a36Sopenharmony_ci if (tc >= vol->mft_zone_end) { 55462306a36Sopenharmony_ci vol->mft_zone_pos = 55562306a36Sopenharmony_ci vol->mft_lcn; 55662306a36Sopenharmony_ci if (!vol->mft_zone_end) 55762306a36Sopenharmony_ci vol->mft_zone_pos = 0; 55862306a36Sopenharmony_ci } else if ((bmp_initial_pos >= 55962306a36Sopenharmony_ci vol->mft_zone_pos || 56062306a36Sopenharmony_ci tc > vol->mft_zone_pos) 56162306a36Sopenharmony_ci && tc >= vol->mft_lcn) 56262306a36Sopenharmony_ci vol->mft_zone_pos = tc; 56362306a36Sopenharmony_ci ntfs_debug("After checks, " 56462306a36Sopenharmony_ci "vol->mft_zone_pos " 56562306a36Sopenharmony_ci "0x%llx.", 56662306a36Sopenharmony_ci (unsigned long long) 56762306a36Sopenharmony_ci vol->mft_zone_pos); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci /* Switch from mft zone to data1 zone. */ 57062306a36Sopenharmony_ciswitch_to_data1_zone: search_zone = 2; 57162306a36Sopenharmony_ci zone_start = bmp_initial_pos = 57262306a36Sopenharmony_ci vol->data1_zone_pos; 57362306a36Sopenharmony_ci zone_end = vol->nr_clusters; 57462306a36Sopenharmony_ci if (zone_start == vol->mft_zone_end) 57562306a36Sopenharmony_ci pass = 2; 57662306a36Sopenharmony_ci if (zone_start >= zone_end) { 57762306a36Sopenharmony_ci vol->data1_zone_pos = zone_start = 57862306a36Sopenharmony_ci vol->mft_zone_end; 57962306a36Sopenharmony_ci pass = 2; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci case 2: 58362306a36Sopenharmony_ci ntfs_debug("Switching from data1 zone to " 58462306a36Sopenharmony_ci "data2 zone."); 58562306a36Sopenharmony_ci /* Update data1 zone position. */ 58662306a36Sopenharmony_ci if (rlpos) { 58762306a36Sopenharmony_ci LCN tc; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci ntfs_debug("Before checks, " 59062306a36Sopenharmony_ci "vol->data1_zone_pos " 59162306a36Sopenharmony_ci "0x%llx.", 59262306a36Sopenharmony_ci (unsigned long long) 59362306a36Sopenharmony_ci vol->data1_zone_pos); 59462306a36Sopenharmony_ci tc = rl[rlpos - 1].lcn + 59562306a36Sopenharmony_ci rl[rlpos - 1].length; 59662306a36Sopenharmony_ci if (tc >= vol->nr_clusters) 59762306a36Sopenharmony_ci vol->data1_zone_pos = 59862306a36Sopenharmony_ci vol->mft_zone_end; 59962306a36Sopenharmony_ci else if ((bmp_initial_pos >= 60062306a36Sopenharmony_ci vol->data1_zone_pos || 60162306a36Sopenharmony_ci tc > vol->data1_zone_pos) 60262306a36Sopenharmony_ci && tc >= vol->mft_zone_end) 60362306a36Sopenharmony_ci vol->data1_zone_pos = tc; 60462306a36Sopenharmony_ci ntfs_debug("After checks, " 60562306a36Sopenharmony_ci "vol->data1_zone_pos " 60662306a36Sopenharmony_ci "0x%llx.", 60762306a36Sopenharmony_ci (unsigned long long) 60862306a36Sopenharmony_ci vol->data1_zone_pos); 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci /* Switch from data1 zone to data2 zone. */ 61162306a36Sopenharmony_ci search_zone = 4; 61262306a36Sopenharmony_ci zone_start = bmp_initial_pos = 61362306a36Sopenharmony_ci vol->data2_zone_pos; 61462306a36Sopenharmony_ci zone_end = vol->mft_zone_start; 61562306a36Sopenharmony_ci if (!zone_start) 61662306a36Sopenharmony_ci pass = 2; 61762306a36Sopenharmony_ci if (zone_start >= zone_end) { 61862306a36Sopenharmony_ci vol->data2_zone_pos = zone_start = 61962306a36Sopenharmony_ci bmp_initial_pos = 0; 62062306a36Sopenharmony_ci pass = 2; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci case 4: 62462306a36Sopenharmony_ci ntfs_debug("Switching from data2 zone to " 62562306a36Sopenharmony_ci "data1 zone."); 62662306a36Sopenharmony_ci /* Update data2 zone position. */ 62762306a36Sopenharmony_ci if (rlpos) { 62862306a36Sopenharmony_ci LCN tc; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci ntfs_debug("Before checks, " 63162306a36Sopenharmony_ci "vol->data2_zone_pos " 63262306a36Sopenharmony_ci "0x%llx.", 63362306a36Sopenharmony_ci (unsigned long long) 63462306a36Sopenharmony_ci vol->data2_zone_pos); 63562306a36Sopenharmony_ci tc = rl[rlpos - 1].lcn + 63662306a36Sopenharmony_ci rl[rlpos - 1].length; 63762306a36Sopenharmony_ci if (tc >= vol->mft_zone_start) 63862306a36Sopenharmony_ci vol->data2_zone_pos = 0; 63962306a36Sopenharmony_ci else if (bmp_initial_pos >= 64062306a36Sopenharmony_ci vol->data2_zone_pos || 64162306a36Sopenharmony_ci tc > vol->data2_zone_pos) 64262306a36Sopenharmony_ci vol->data2_zone_pos = tc; 64362306a36Sopenharmony_ci ntfs_debug("After checks, " 64462306a36Sopenharmony_ci "vol->data2_zone_pos " 64562306a36Sopenharmony_ci "0x%llx.", 64662306a36Sopenharmony_ci (unsigned long long) 64762306a36Sopenharmony_ci vol->data2_zone_pos); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci /* Switch from data2 zone to data1 zone. */ 65062306a36Sopenharmony_ci goto switch_to_data1_zone; 65162306a36Sopenharmony_ci default: 65262306a36Sopenharmony_ci BUG(); 65362306a36Sopenharmony_ci } 65462306a36Sopenharmony_ci ntfs_debug("After zone switch, search_zone %i, " 65562306a36Sopenharmony_ci "pass %i, bmp_initial_pos 0x%llx, " 65662306a36Sopenharmony_ci "zone_start 0x%llx, zone_end 0x%llx.", 65762306a36Sopenharmony_ci search_zone, pass, 65862306a36Sopenharmony_ci (unsigned long long)bmp_initial_pos, 65962306a36Sopenharmony_ci (unsigned long long)zone_start, 66062306a36Sopenharmony_ci (unsigned long long)zone_end); 66162306a36Sopenharmony_ci bmp_pos = zone_start; 66262306a36Sopenharmony_ci if (zone_start == zone_end) { 66362306a36Sopenharmony_ci ntfs_debug("Empty zone, going to " 66462306a36Sopenharmony_ci "done_zones_check."); 66562306a36Sopenharmony_ci /* Empty zone. Don't bother searching it. */ 66662306a36Sopenharmony_ci goto done_zones_check; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci ntfs_debug("Continuing outer while loop."); 66962306a36Sopenharmony_ci continue; 67062306a36Sopenharmony_ci } /* done_zones == 7 */ 67162306a36Sopenharmony_ci ntfs_debug("All zones are finished."); 67262306a36Sopenharmony_ci /* 67362306a36Sopenharmony_ci * All zones are finished! If DATA_ZONE, shrink mft zone. If 67462306a36Sopenharmony_ci * MFT_ZONE, we have really run out of space. 67562306a36Sopenharmony_ci */ 67662306a36Sopenharmony_ci mft_zone_size = vol->mft_zone_end - vol->mft_zone_start; 67762306a36Sopenharmony_ci ntfs_debug("vol->mft_zone_start 0x%llx, vol->mft_zone_end " 67862306a36Sopenharmony_ci "0x%llx, mft_zone_size 0x%llx.", 67962306a36Sopenharmony_ci (unsigned long long)vol->mft_zone_start, 68062306a36Sopenharmony_ci (unsigned long long)vol->mft_zone_end, 68162306a36Sopenharmony_ci (unsigned long long)mft_zone_size); 68262306a36Sopenharmony_ci if (zone == MFT_ZONE || mft_zone_size <= 0) { 68362306a36Sopenharmony_ci ntfs_debug("No free clusters left, going to out."); 68462306a36Sopenharmony_ci /* Really no more space left on device. */ 68562306a36Sopenharmony_ci err = -ENOSPC; 68662306a36Sopenharmony_ci goto out; 68762306a36Sopenharmony_ci } /* zone == DATA_ZONE && mft_zone_size > 0 */ 68862306a36Sopenharmony_ci ntfs_debug("Shrinking mft zone."); 68962306a36Sopenharmony_ci zone_end = vol->mft_zone_end; 69062306a36Sopenharmony_ci mft_zone_size >>= 1; 69162306a36Sopenharmony_ci if (mft_zone_size > 0) 69262306a36Sopenharmony_ci vol->mft_zone_end = vol->mft_zone_start + mft_zone_size; 69362306a36Sopenharmony_ci else /* mft zone and data2 zone no longer exist. */ 69462306a36Sopenharmony_ci vol->data2_zone_pos = vol->mft_zone_start = 69562306a36Sopenharmony_ci vol->mft_zone_end = 0; 69662306a36Sopenharmony_ci if (vol->mft_zone_pos >= vol->mft_zone_end) { 69762306a36Sopenharmony_ci vol->mft_zone_pos = vol->mft_lcn; 69862306a36Sopenharmony_ci if (!vol->mft_zone_end) 69962306a36Sopenharmony_ci vol->mft_zone_pos = 0; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci bmp_pos = zone_start = bmp_initial_pos = 70262306a36Sopenharmony_ci vol->data1_zone_pos = vol->mft_zone_end; 70362306a36Sopenharmony_ci search_zone = 2; 70462306a36Sopenharmony_ci pass = 2; 70562306a36Sopenharmony_ci done_zones &= ~2; 70662306a36Sopenharmony_ci ntfs_debug("After shrinking mft zone, mft_zone_size 0x%llx, " 70762306a36Sopenharmony_ci "vol->mft_zone_start 0x%llx, " 70862306a36Sopenharmony_ci "vol->mft_zone_end 0x%llx, " 70962306a36Sopenharmony_ci "vol->mft_zone_pos 0x%llx, search_zone 2, " 71062306a36Sopenharmony_ci "pass 2, dones_zones 0x%x, zone_start 0x%llx, " 71162306a36Sopenharmony_ci "zone_end 0x%llx, vol->data1_zone_pos 0x%llx, " 71262306a36Sopenharmony_ci "continuing outer while loop.", 71362306a36Sopenharmony_ci (unsigned long long)mft_zone_size, 71462306a36Sopenharmony_ci (unsigned long long)vol->mft_zone_start, 71562306a36Sopenharmony_ci (unsigned long long)vol->mft_zone_end, 71662306a36Sopenharmony_ci (unsigned long long)vol->mft_zone_pos, 71762306a36Sopenharmony_ci done_zones, (unsigned long long)zone_start, 71862306a36Sopenharmony_ci (unsigned long long)zone_end, 71962306a36Sopenharmony_ci (unsigned long long)vol->data1_zone_pos); 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci ntfs_debug("After outer while loop."); 72262306a36Sopenharmony_ciout: 72362306a36Sopenharmony_ci ntfs_debug("At out."); 72462306a36Sopenharmony_ci /* Add runlist terminator element. */ 72562306a36Sopenharmony_ci if (likely(rl)) { 72662306a36Sopenharmony_ci rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; 72762306a36Sopenharmony_ci rl[rlpos].lcn = is_extension ? LCN_ENOENT : LCN_RL_NOT_MAPPED; 72862306a36Sopenharmony_ci rl[rlpos].length = 0; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci if (likely(page && !IS_ERR(page))) { 73162306a36Sopenharmony_ci if (need_writeback) { 73262306a36Sopenharmony_ci ntfs_debug("Marking page dirty."); 73362306a36Sopenharmony_ci flush_dcache_page(page); 73462306a36Sopenharmony_ci set_page_dirty(page); 73562306a36Sopenharmony_ci need_writeback = 0; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci ntfs_unmap_page(page); 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci if (likely(!err)) { 74062306a36Sopenharmony_ci up_write(&vol->lcnbmp_lock); 74162306a36Sopenharmony_ci ntfs_debug("Done."); 74262306a36Sopenharmony_ci return rl; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to allocate clusters, aborting " 74562306a36Sopenharmony_ci "(error %i).", err); 74662306a36Sopenharmony_ci if (rl) { 74762306a36Sopenharmony_ci int err2; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (err == -ENOSPC) 75062306a36Sopenharmony_ci ntfs_debug("Not enough space to complete allocation, " 75162306a36Sopenharmony_ci "err -ENOSPC, first free lcn 0x%llx, " 75262306a36Sopenharmony_ci "could allocate up to 0x%llx " 75362306a36Sopenharmony_ci "clusters.", 75462306a36Sopenharmony_ci (unsigned long long)rl[0].lcn, 75562306a36Sopenharmony_ci (unsigned long long)(count - clusters)); 75662306a36Sopenharmony_ci /* Deallocate all allocated clusters. */ 75762306a36Sopenharmony_ci ntfs_debug("Attempting rollback..."); 75862306a36Sopenharmony_ci err2 = ntfs_cluster_free_from_rl_nolock(vol, rl); 75962306a36Sopenharmony_ci if (err2) { 76062306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to rollback (error %i). " 76162306a36Sopenharmony_ci "Leaving inconsistent metadata! " 76262306a36Sopenharmony_ci "Unmount and run chkdsk.", err2); 76362306a36Sopenharmony_ci NVolSetErrors(vol); 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci /* Free the runlist. */ 76662306a36Sopenharmony_ci ntfs_free(rl); 76762306a36Sopenharmony_ci } else if (err == -ENOSPC) 76862306a36Sopenharmony_ci ntfs_debug("No space left at all, err = -ENOSPC, first free " 76962306a36Sopenharmony_ci "lcn = 0x%llx.", 77062306a36Sopenharmony_ci (long long)vol->data1_zone_pos); 77162306a36Sopenharmony_ci up_write(&vol->lcnbmp_lock); 77262306a36Sopenharmony_ci return ERR_PTR(err); 77362306a36Sopenharmony_ci} 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci/** 77662306a36Sopenharmony_ci * __ntfs_cluster_free - free clusters on an ntfs volume 77762306a36Sopenharmony_ci * @ni: ntfs inode whose runlist describes the clusters to free 77862306a36Sopenharmony_ci * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters 77962306a36Sopenharmony_ci * @count: number of clusters to free or -1 for all clusters 78062306a36Sopenharmony_ci * @ctx: active attribute search context if present or NULL if not 78162306a36Sopenharmony_ci * @is_rollback: true if this is a rollback operation 78262306a36Sopenharmony_ci * 78362306a36Sopenharmony_ci * Free @count clusters starting at the cluster @start_vcn in the runlist 78462306a36Sopenharmony_ci * described by the vfs inode @ni. 78562306a36Sopenharmony_ci * 78662306a36Sopenharmony_ci * If @count is -1, all clusters from @start_vcn to the end of the runlist are 78762306a36Sopenharmony_ci * deallocated. Thus, to completely free all clusters in a runlist, use 78862306a36Sopenharmony_ci * @start_vcn = 0 and @count = -1. 78962306a36Sopenharmony_ci * 79062306a36Sopenharmony_ci * If @ctx is specified, it is an active search context of @ni and its base mft 79162306a36Sopenharmony_ci * record. This is needed when __ntfs_cluster_free() encounters unmapped 79262306a36Sopenharmony_ci * runlist fragments and allows their mapping. If you do not have the mft 79362306a36Sopenharmony_ci * record mapped, you can specify @ctx as NULL and __ntfs_cluster_free() will 79462306a36Sopenharmony_ci * perform the necessary mapping and unmapping. 79562306a36Sopenharmony_ci * 79662306a36Sopenharmony_ci * Note, __ntfs_cluster_free() saves the state of @ctx on entry and restores it 79762306a36Sopenharmony_ci * before returning. Thus, @ctx will be left pointing to the same attribute on 79862306a36Sopenharmony_ci * return as on entry. However, the actual pointers in @ctx may point to 79962306a36Sopenharmony_ci * different memory locations on return, so you must remember to reset any 80062306a36Sopenharmony_ci * cached pointers from the @ctx, i.e. after the call to __ntfs_cluster_free(), 80162306a36Sopenharmony_ci * you will probably want to do: 80262306a36Sopenharmony_ci * m = ctx->mrec; 80362306a36Sopenharmony_ci * a = ctx->attr; 80462306a36Sopenharmony_ci * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that 80562306a36Sopenharmony_ci * you cache ctx->mrec in a variable @m of type MFT_RECORD *. 80662306a36Sopenharmony_ci * 80762306a36Sopenharmony_ci * @is_rollback should always be 'false', it is for internal use to rollback 80862306a36Sopenharmony_ci * errors. You probably want to use ntfs_cluster_free() instead. 80962306a36Sopenharmony_ci * 81062306a36Sopenharmony_ci * Note, __ntfs_cluster_free() does not modify the runlist, so you have to 81162306a36Sopenharmony_ci * remove from the runlist or mark sparse the freed runs later. 81262306a36Sopenharmony_ci * 81362306a36Sopenharmony_ci * Return the number of deallocated clusters (not counting sparse ones) on 81462306a36Sopenharmony_ci * success and -errno on error. 81562306a36Sopenharmony_ci * 81662306a36Sopenharmony_ci * WARNING: If @ctx is supplied, regardless of whether success or failure is 81762306a36Sopenharmony_ci * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx 81862306a36Sopenharmony_ci * is no longer valid, i.e. you need to either call 81962306a36Sopenharmony_ci * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. 82062306a36Sopenharmony_ci * In that case PTR_ERR(@ctx->mrec) will give you the error code for 82162306a36Sopenharmony_ci * why the mapping of the old inode failed. 82262306a36Sopenharmony_ci * 82362306a36Sopenharmony_ci * Locking: - The runlist described by @ni must be locked for writing on entry 82462306a36Sopenharmony_ci * and is locked on return. Note the runlist may be modified when 82562306a36Sopenharmony_ci * needed runlist fragments need to be mapped. 82662306a36Sopenharmony_ci * - The volume lcn bitmap must be unlocked on entry and is unlocked 82762306a36Sopenharmony_ci * on return. 82862306a36Sopenharmony_ci * - This function takes the volume lcn bitmap lock for writing and 82962306a36Sopenharmony_ci * modifies the bitmap contents. 83062306a36Sopenharmony_ci * - If @ctx is NULL, the base mft record of @ni must not be mapped on 83162306a36Sopenharmony_ci * entry and it will be left unmapped on return. 83262306a36Sopenharmony_ci * - If @ctx is not NULL, the base mft record must be mapped on entry 83362306a36Sopenharmony_ci * and it will be left mapped on return. 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_cis64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count, 83662306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx, const bool is_rollback) 83762306a36Sopenharmony_ci{ 83862306a36Sopenharmony_ci s64 delta, to_free, total_freed, real_freed; 83962306a36Sopenharmony_ci ntfs_volume *vol; 84062306a36Sopenharmony_ci struct inode *lcnbmp_vi; 84162306a36Sopenharmony_ci runlist_element *rl; 84262306a36Sopenharmony_ci int err; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci BUG_ON(!ni); 84562306a36Sopenharmony_ci ntfs_debug("Entering for i_ino 0x%lx, start_vcn 0x%llx, count " 84662306a36Sopenharmony_ci "0x%llx.%s", ni->mft_no, (unsigned long long)start_vcn, 84762306a36Sopenharmony_ci (unsigned long long)count, 84862306a36Sopenharmony_ci is_rollback ? " (rollback)" : ""); 84962306a36Sopenharmony_ci vol = ni->vol; 85062306a36Sopenharmony_ci lcnbmp_vi = vol->lcnbmp_ino; 85162306a36Sopenharmony_ci BUG_ON(!lcnbmp_vi); 85262306a36Sopenharmony_ci BUG_ON(start_vcn < 0); 85362306a36Sopenharmony_ci BUG_ON(count < -1); 85462306a36Sopenharmony_ci /* 85562306a36Sopenharmony_ci * Lock the lcn bitmap for writing but only if not rolling back. We 85662306a36Sopenharmony_ci * must hold the lock all the way including through rollback otherwise 85762306a36Sopenharmony_ci * rollback is not possible because once we have cleared a bit and 85862306a36Sopenharmony_ci * dropped the lock, anyone could have set the bit again, thus 85962306a36Sopenharmony_ci * allocating the cluster for another use. 86062306a36Sopenharmony_ci */ 86162306a36Sopenharmony_ci if (likely(!is_rollback)) 86262306a36Sopenharmony_ci down_write(&vol->lcnbmp_lock); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci total_freed = real_freed = 0; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, ctx); 86762306a36Sopenharmony_ci if (IS_ERR(rl)) { 86862306a36Sopenharmony_ci if (!is_rollback) 86962306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to find first runlist " 87062306a36Sopenharmony_ci "element (error %li), aborting.", 87162306a36Sopenharmony_ci PTR_ERR(rl)); 87262306a36Sopenharmony_ci err = PTR_ERR(rl); 87362306a36Sopenharmony_ci goto err_out; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci if (unlikely(rl->lcn < LCN_HOLE)) { 87662306a36Sopenharmony_ci if (!is_rollback) 87762306a36Sopenharmony_ci ntfs_error(vol->sb, "First runlist element has " 87862306a36Sopenharmony_ci "invalid lcn, aborting."); 87962306a36Sopenharmony_ci err = -EIO; 88062306a36Sopenharmony_ci goto err_out; 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci /* Find the starting cluster inside the run that needs freeing. */ 88362306a36Sopenharmony_ci delta = start_vcn - rl->vcn; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci /* The number of clusters in this run that need freeing. */ 88662306a36Sopenharmony_ci to_free = rl->length - delta; 88762306a36Sopenharmony_ci if (count >= 0 && to_free > count) 88862306a36Sopenharmony_ci to_free = count; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (likely(rl->lcn >= 0)) { 89162306a36Sopenharmony_ci /* Do the actual freeing of the clusters in this run. */ 89262306a36Sopenharmony_ci err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn + delta, 89362306a36Sopenharmony_ci to_free, likely(!is_rollback) ? 0 : 1); 89462306a36Sopenharmony_ci if (unlikely(err)) { 89562306a36Sopenharmony_ci if (!is_rollback) 89662306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to clear first run " 89762306a36Sopenharmony_ci "(error %i), aborting.", err); 89862306a36Sopenharmony_ci goto err_out; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci /* We have freed @to_free real clusters. */ 90162306a36Sopenharmony_ci real_freed = to_free; 90262306a36Sopenharmony_ci }; 90362306a36Sopenharmony_ci /* Go to the next run and adjust the number of clusters left to free. */ 90462306a36Sopenharmony_ci ++rl; 90562306a36Sopenharmony_ci if (count >= 0) 90662306a36Sopenharmony_ci count -= to_free; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci /* Keep track of the total "freed" clusters, including sparse ones. */ 90962306a36Sopenharmony_ci total_freed = to_free; 91062306a36Sopenharmony_ci /* 91162306a36Sopenharmony_ci * Loop over the remaining runs, using @count as a capping value, and 91262306a36Sopenharmony_ci * free them. 91362306a36Sopenharmony_ci */ 91462306a36Sopenharmony_ci for (; rl->length && count != 0; ++rl) { 91562306a36Sopenharmony_ci if (unlikely(rl->lcn < LCN_HOLE)) { 91662306a36Sopenharmony_ci VCN vcn; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci /* Attempt to map runlist. */ 91962306a36Sopenharmony_ci vcn = rl->vcn; 92062306a36Sopenharmony_ci rl = ntfs_attr_find_vcn_nolock(ni, vcn, ctx); 92162306a36Sopenharmony_ci if (IS_ERR(rl)) { 92262306a36Sopenharmony_ci err = PTR_ERR(rl); 92362306a36Sopenharmony_ci if (!is_rollback) 92462306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to map " 92562306a36Sopenharmony_ci "runlist fragment or " 92662306a36Sopenharmony_ci "failed to find " 92762306a36Sopenharmony_ci "subsequent runlist " 92862306a36Sopenharmony_ci "element."); 92962306a36Sopenharmony_ci goto err_out; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci if (unlikely(rl->lcn < LCN_HOLE)) { 93262306a36Sopenharmony_ci if (!is_rollback) 93362306a36Sopenharmony_ci ntfs_error(vol->sb, "Runlist element " 93462306a36Sopenharmony_ci "has invalid lcn " 93562306a36Sopenharmony_ci "(0x%llx).", 93662306a36Sopenharmony_ci (unsigned long long) 93762306a36Sopenharmony_ci rl->lcn); 93862306a36Sopenharmony_ci err = -EIO; 93962306a36Sopenharmony_ci goto err_out; 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci } 94262306a36Sopenharmony_ci /* The number of clusters in this run that need freeing. */ 94362306a36Sopenharmony_ci to_free = rl->length; 94462306a36Sopenharmony_ci if (count >= 0 && to_free > count) 94562306a36Sopenharmony_ci to_free = count; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci if (likely(rl->lcn >= 0)) { 94862306a36Sopenharmony_ci /* Do the actual freeing of the clusters in the run. */ 94962306a36Sopenharmony_ci err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn, 95062306a36Sopenharmony_ci to_free, likely(!is_rollback) ? 0 : 1); 95162306a36Sopenharmony_ci if (unlikely(err)) { 95262306a36Sopenharmony_ci if (!is_rollback) 95362306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to clear " 95462306a36Sopenharmony_ci "subsequent run."); 95562306a36Sopenharmony_ci goto err_out; 95662306a36Sopenharmony_ci } 95762306a36Sopenharmony_ci /* We have freed @to_free real clusters. */ 95862306a36Sopenharmony_ci real_freed += to_free; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci /* Adjust the number of clusters left to free. */ 96162306a36Sopenharmony_ci if (count >= 0) 96262306a36Sopenharmony_ci count -= to_free; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* Update the total done clusters. */ 96562306a36Sopenharmony_ci total_freed += to_free; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci if (likely(!is_rollback)) 96862306a36Sopenharmony_ci up_write(&vol->lcnbmp_lock); 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci BUG_ON(count > 0); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci /* We are done. Return the number of actually freed clusters. */ 97362306a36Sopenharmony_ci ntfs_debug("Done."); 97462306a36Sopenharmony_ci return real_freed; 97562306a36Sopenharmony_cierr_out: 97662306a36Sopenharmony_ci if (is_rollback) 97762306a36Sopenharmony_ci return err; 97862306a36Sopenharmony_ci /* If no real clusters were freed, no need to rollback. */ 97962306a36Sopenharmony_ci if (!real_freed) { 98062306a36Sopenharmony_ci up_write(&vol->lcnbmp_lock); 98162306a36Sopenharmony_ci return err; 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci /* 98462306a36Sopenharmony_ci * Attempt to rollback and if that succeeds just return the error code. 98562306a36Sopenharmony_ci * If rollback fails, set the volume errors flag, emit an error 98662306a36Sopenharmony_ci * message, and return the error code. 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_ci delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, true); 98962306a36Sopenharmony_ci if (delta < 0) { 99062306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving " 99162306a36Sopenharmony_ci "inconsistent metadata! Unmount and run " 99262306a36Sopenharmony_ci "chkdsk.", (int)delta); 99362306a36Sopenharmony_ci NVolSetErrors(vol); 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci up_write(&vol->lcnbmp_lock); 99662306a36Sopenharmony_ci ntfs_error(vol->sb, "Aborting (error %i).", err); 99762306a36Sopenharmony_ci return err; 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci#endif /* NTFS_RW */ 1001