11e9ea7e0SNamjae Jeon // SPDX-License-Identifier: GPL-2.0-or-later 21e9ea7e0SNamjae Jeon /* 311ccc910SNamjae Jeon * Cluster (de)allocation code. 41e9ea7e0SNamjae Jeon * 51e9ea7e0SNamjae Jeon * Copyright (c) 2004-2005 Anton Altaparmakov 611ccc910SNamjae Jeon * Copyright (c) 2025 LG Electronics Co., Ltd. 711ccc910SNamjae Jeon * 811ccc910SNamjae Jeon * Part of this file is based on code from the NTFS-3G. 911ccc910SNamjae Jeon * and is copyrighted by the respective authors below: 1011ccc910SNamjae Jeon * Copyright (c) 2002-2004 Anton Altaparmakov 1111ccc910SNamjae Jeon * Copyright (c) 2004 Yura Pakhuchiy 1211ccc910SNamjae Jeon * Copyright (c) 2004-2008 Szabolcs Szakacsits 1311ccc910SNamjae Jeon * Copyright (c) 2008-2009 Jean-Pierre Andre 141e9ea7e0SNamjae Jeon */ 151e9ea7e0SNamjae Jeon 1611ccc910SNamjae Jeon #include <linux/blkdev.h> 171e9ea7e0SNamjae Jeon 181e9ea7e0SNamjae Jeon #include "lcnalloc.h" 191e9ea7e0SNamjae Jeon #include "bitmap.h" 201e9ea7e0SNamjae Jeon #include "ntfs.h" 211e9ea7e0SNamjae Jeon 2211ccc910SNamjae Jeon /* 231e9ea7e0SNamjae Jeon * ntfs_cluster_free_from_rl_nolock - free clusters from runlist 241e9ea7e0SNamjae Jeon * @vol: mounted ntfs volume on which to free the clusters 251e9ea7e0SNamjae Jeon * @rl: runlist describing the clusters to free 261e9ea7e0SNamjae Jeon * 271e9ea7e0SNamjae Jeon * Free all the clusters described by the runlist @rl on the volume @vol. In 281e9ea7e0SNamjae Jeon * the case of an error being returned, at least some of the clusters were not 291e9ea7e0SNamjae Jeon * freed. 301e9ea7e0SNamjae Jeon * 311e9ea7e0SNamjae Jeon * Return 0 on success and -errno on error. 321e9ea7e0SNamjae Jeon * 331e9ea7e0SNamjae Jeon * Locking: - The volume lcn bitmap must be locked for writing on entry and is 341e9ea7e0SNamjae Jeon * left locked on return. 351e9ea7e0SNamjae Jeon */ 3611ccc910SNamjae Jeon int ntfs_cluster_free_from_rl_nolock(struct ntfs_volume *vol, 3711ccc910SNamjae Jeon const struct runlist_element *rl) 381e9ea7e0SNamjae Jeon { 391e9ea7e0SNamjae Jeon struct inode *lcnbmp_vi = vol->lcnbmp_ino; 401e9ea7e0SNamjae Jeon int ret = 0; 4111ccc910SNamjae Jeon s64 nr_freed = 0; 421e9ea7e0SNamjae Jeon 431e9ea7e0SNamjae Jeon ntfs_debug("Entering."); 441e9ea7e0SNamjae Jeon if (!rl) 451e9ea7e0SNamjae Jeon return 0; 4611ccc910SNamjae Jeon 4711ccc910SNamjae Jeon if (!NVolFreeClusterKnown(vol)) 4811ccc910SNamjae Jeon wait_event(vol->free_waitq, NVolFreeClusterKnown(vol)); 4911ccc910SNamjae Jeon 501e9ea7e0SNamjae Jeon for (; rl->length; rl++) { 511e9ea7e0SNamjae Jeon int err; 521e9ea7e0SNamjae Jeon 531e9ea7e0SNamjae Jeon if (rl->lcn < 0) 541e9ea7e0SNamjae Jeon continue; 551e9ea7e0SNamjae Jeon err = ntfs_bitmap_clear_run(lcnbmp_vi, rl->lcn, rl->length); 561e9ea7e0SNamjae Jeon if (unlikely(err && (!ret || ret == -ENOMEM) && ret != err)) 571e9ea7e0SNamjae Jeon ret = err; 5811ccc910SNamjae Jeon else 5911ccc910SNamjae Jeon nr_freed += rl->length; 601e9ea7e0SNamjae Jeon } 6111ccc910SNamjae Jeon ntfs_inc_free_clusters(vol, nr_freed); 621e9ea7e0SNamjae Jeon ntfs_debug("Done."); 631e9ea7e0SNamjae Jeon return ret; 641e9ea7e0SNamjae Jeon } 651e9ea7e0SNamjae Jeon 6611ccc910SNamjae Jeon static s64 max_empty_bit_range(unsigned char *buf, int size) 6711ccc910SNamjae Jeon { 6811ccc910SNamjae Jeon int i, j, run = 0; 6911ccc910SNamjae Jeon int max_range = 0; 7011ccc910SNamjae Jeon s64 start_pos = -1; 7111ccc910SNamjae Jeon 7211ccc910SNamjae Jeon ntfs_debug("Entering\n"); 7311ccc910SNamjae Jeon 7411ccc910SNamjae Jeon i = 0; 7511ccc910SNamjae Jeon while (i < size) { 7611ccc910SNamjae Jeon switch (*buf) { 7711ccc910SNamjae Jeon case 0: 7811ccc910SNamjae Jeon do { 7911ccc910SNamjae Jeon buf++; 8011ccc910SNamjae Jeon run += 8; 8111ccc910SNamjae Jeon i++; 8211ccc910SNamjae Jeon } while ((i < size) && !*buf); 8311ccc910SNamjae Jeon break; 8411ccc910SNamjae Jeon case 255: 8511ccc910SNamjae Jeon if (run > max_range) { 8611ccc910SNamjae Jeon max_range = run; 8711ccc910SNamjae Jeon start_pos = (s64)i * 8 - run; 8811ccc910SNamjae Jeon } 8911ccc910SNamjae Jeon run = 0; 9011ccc910SNamjae Jeon do { 9111ccc910SNamjae Jeon buf++; 9211ccc910SNamjae Jeon i++; 9311ccc910SNamjae Jeon } while ((i < size) && (*buf == 255)); 9411ccc910SNamjae Jeon break; 9511ccc910SNamjae Jeon default: 9611ccc910SNamjae Jeon for (j = 0; j < 8; j++) { 9711ccc910SNamjae Jeon int bit = *buf & (1 << j); 9811ccc910SNamjae Jeon 9911ccc910SNamjae Jeon if (bit) { 10011ccc910SNamjae Jeon if (run > max_range) { 10111ccc910SNamjae Jeon max_range = run; 10211ccc910SNamjae Jeon start_pos = (s64)i * 8 + (j - run); 10311ccc910SNamjae Jeon } 10411ccc910SNamjae Jeon run = 0; 10511ccc910SNamjae Jeon } else 10611ccc910SNamjae Jeon run++; 10711ccc910SNamjae Jeon } 10811ccc910SNamjae Jeon i++; 10911ccc910SNamjae Jeon buf++; 11011ccc910SNamjae Jeon } 11111ccc910SNamjae Jeon } 11211ccc910SNamjae Jeon 11311ccc910SNamjae Jeon if (run > max_range) 11411ccc910SNamjae Jeon start_pos = (s64)i * 8 - run; 11511ccc910SNamjae Jeon 11611ccc910SNamjae Jeon return start_pos; 11711ccc910SNamjae Jeon } 11811ccc910SNamjae Jeon 11911ccc910SNamjae Jeon /* 1201e9ea7e0SNamjae Jeon * ntfs_cluster_alloc - allocate clusters on an ntfs volume 12111ccc910SNamjae Jeon * @vol: mounted ntfs volume on which to allocate clusters 12211ccc910SNamjae Jeon * @start_vcn: vcn of the first allocated cluster 1231e9ea7e0SNamjae Jeon * @count: number of clusters to allocate 12411ccc910SNamjae Jeon * @start_lcn: starting lcn at which to allocate the clusters or -1 if none 12511ccc910SNamjae Jeon * @zone: zone from which to allocate (MFT_ZONE or DATA_ZONE) 12611ccc910SNamjae Jeon * @is_extension: if true, the caller is extending an attribute 12711ccc910SNamjae Jeon * @is_contig: if true, require contiguous allocation 12811ccc910SNamjae Jeon * @is_dealloc: if true, the allocation is for deallocation purposes 1291e9ea7e0SNamjae Jeon * 1301e9ea7e0SNamjae Jeon * Allocate @count clusters preferably starting at cluster @start_lcn or at the 1311e9ea7e0SNamjae Jeon * current allocator position if @start_lcn is -1, on the mounted ntfs volume 1321e9ea7e0SNamjae Jeon * @vol. @zone is either DATA_ZONE for allocation of normal clusters or 1331e9ea7e0SNamjae Jeon * MFT_ZONE for allocation of clusters for the master file table, i.e. the 1341e9ea7e0SNamjae Jeon * $MFT/$DATA attribute. 1351e9ea7e0SNamjae Jeon * 1361e9ea7e0SNamjae Jeon * @start_vcn specifies the vcn of the first allocated cluster. This makes 1371e9ea7e0SNamjae Jeon * merging the resulting runlist with the old runlist easier. 1381e9ea7e0SNamjae Jeon * 1391e9ea7e0SNamjae Jeon * If @is_extension is 'true', the caller is allocating clusters to extend an 1401e9ea7e0SNamjae Jeon * attribute and if it is 'false', the caller is allocating clusters to fill a 1411e9ea7e0SNamjae Jeon * hole in an attribute. Practically the difference is that if @is_extension 1421e9ea7e0SNamjae Jeon * is 'true' the returned runlist will be terminated with LCN_ENOENT and if 1431e9ea7e0SNamjae Jeon * @is_extension is 'false' the runlist will be terminated with 1441e9ea7e0SNamjae Jeon * LCN_RL_NOT_MAPPED. 1451e9ea7e0SNamjae Jeon * 1461e9ea7e0SNamjae Jeon * You need to check the return value with IS_ERR(). If this is false, the 1471e9ea7e0SNamjae Jeon * function was successful and the return value is a runlist describing the 1481e9ea7e0SNamjae Jeon * allocated cluster(s). If IS_ERR() is true, the function failed and 1491e9ea7e0SNamjae Jeon * PTR_ERR() gives you the error code. 1501e9ea7e0SNamjae Jeon * 1511e9ea7e0SNamjae Jeon * Notes on the allocation algorithm 1521e9ea7e0SNamjae Jeon * ================================= 1531e9ea7e0SNamjae Jeon * 1541e9ea7e0SNamjae Jeon * There are two data zones. First is the area between the end of the mft zone 1551e9ea7e0SNamjae Jeon * and the end of the volume, and second is the area between the start of the 1561e9ea7e0SNamjae Jeon * volume and the start of the mft zone. On unmodified/standard NTFS 1.x 1571e9ea7e0SNamjae Jeon * volumes, the second data zone does not exist due to the mft zone being 1581e9ea7e0SNamjae Jeon * expanded to cover the start of the volume in order to reserve space for the 1591e9ea7e0SNamjae Jeon * mft bitmap attribute. 1601e9ea7e0SNamjae Jeon * 1611e9ea7e0SNamjae Jeon * This is not the prettiest function but the complexity stems from the need of 1621e9ea7e0SNamjae Jeon * implementing the mft vs data zoned approach and from the fact that we have 1631e9ea7e0SNamjae Jeon * access to the lcn bitmap in portions of up to 8192 bytes at a time, so we 1641e9ea7e0SNamjae Jeon * need to cope with crossing over boundaries of two buffers. Further, the 1651e9ea7e0SNamjae Jeon * fact that the allocator allows for caller supplied hints as to the location 1661e9ea7e0SNamjae Jeon * of where allocation should begin and the fact that the allocator keeps track 1671e9ea7e0SNamjae Jeon * of where in the data zones the next natural allocation should occur, 1681e9ea7e0SNamjae Jeon * contribute to the complexity of the function. But it should all be 1691e9ea7e0SNamjae Jeon * worthwhile, because this allocator should: 1) be a full implementation of 1701e9ea7e0SNamjae Jeon * the MFT zone approach used by Windows NT, 2) cause reduction in 1711e9ea7e0SNamjae Jeon * fragmentation, and 3) be speedy in allocations (the code is not optimized 1721e9ea7e0SNamjae Jeon * for speed, but the algorithm is, so further speed improvements are probably 1731e9ea7e0SNamjae Jeon * possible). 1741e9ea7e0SNamjae Jeon * 1751e9ea7e0SNamjae Jeon * Locking: - The volume lcn bitmap must be unlocked on entry and is unlocked 1761e9ea7e0SNamjae Jeon * on return. 1771e9ea7e0SNamjae Jeon * - This function takes the volume lcn bitmap lock for writing and 1781e9ea7e0SNamjae Jeon * modifies the bitmap contents. 17911ccc910SNamjae Jeon * 18011ccc910SNamjae Jeon * Return: Runlist describing the allocated cluster(s) on success, error pointer 18111ccc910SNamjae Jeon * on failure. 1821e9ea7e0SNamjae Jeon */ 18311ccc910SNamjae Jeon struct runlist_element *ntfs_cluster_alloc(struct ntfs_volume *vol, const s64 start_vcn, 18411ccc910SNamjae Jeon const s64 count, const s64 start_lcn, 18511ccc910SNamjae Jeon const int zone, 18611ccc910SNamjae Jeon const bool is_extension, 18711ccc910SNamjae Jeon const bool is_contig, 18811ccc910SNamjae Jeon const bool is_dealloc) 1891e9ea7e0SNamjae Jeon { 19011ccc910SNamjae Jeon s64 zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn; 19111ccc910SNamjae Jeon s64 prev_lcn = 0, prev_run_len = 0, mft_zone_size; 19211ccc910SNamjae Jeon s64 clusters, free_clusters; 1931e9ea7e0SNamjae Jeon loff_t i_size; 1941e9ea7e0SNamjae Jeon struct inode *lcnbmp_vi; 19511ccc910SNamjae Jeon struct runlist_element *rl = NULL; 1961e9ea7e0SNamjae Jeon struct address_space *mapping; 19711ccc910SNamjae Jeon struct folio *folio = NULL; 19811ccc910SNamjae Jeon u8 *buf = NULL, *byte; 19911ccc910SNamjae Jeon int err = 0, rlpos, rlsize, buf_size, pg_off; 2001e9ea7e0SNamjae Jeon u8 pass, done_zones, search_zone, need_writeback = 0, bit; 20111ccc910SNamjae Jeon unsigned int memalloc_flags; 20211ccc910SNamjae Jeon u8 has_guess, used_zone_pos; 20311ccc910SNamjae Jeon pgoff_t index; 2041e9ea7e0SNamjae Jeon 20511ccc910SNamjae Jeon ntfs_debug("Entering for start_vcn 0x%llx, count 0x%llx, start_lcn 0x%llx, zone %s_ZONE.", 20611ccc910SNamjae Jeon start_vcn, count, start_lcn, 2071e9ea7e0SNamjae Jeon zone == MFT_ZONE ? "MFT" : "DATA"); 20811ccc910SNamjae Jeon 2091e9ea7e0SNamjae Jeon lcnbmp_vi = vol->lcnbmp_ino; 21011ccc910SNamjae Jeon if (start_vcn < 0 || start_lcn < LCN_HOLE || 21111ccc910SNamjae Jeon zone < FIRST_ZONE || zone > LAST_ZONE) 21211ccc910SNamjae Jeon return ERR_PTR(-EINVAL); 2131e9ea7e0SNamjae Jeon 2141e9ea7e0SNamjae Jeon /* Return NULL if @count is zero. */ 21511ccc910SNamjae Jeon if (count < 0 || !count) 21611ccc910SNamjae Jeon return ERR_PTR(-EINVAL); 21711ccc910SNamjae Jeon 21811ccc910SNamjae Jeon memalloc_flags = memalloc_nofs_save(); 21911ccc910SNamjae Jeon 22011ccc910SNamjae Jeon if (!NVolFreeClusterKnown(vol)) 22111ccc910SNamjae Jeon wait_event(vol->free_waitq, NVolFreeClusterKnown(vol)); 22211ccc910SNamjae Jeon free_clusters = atomic64_read(&vol->free_clusters); 22311ccc910SNamjae Jeon 2241e9ea7e0SNamjae Jeon /* Take the lcnbmp lock for writing. */ 2251e9ea7e0SNamjae Jeon down_write(&vol->lcnbmp_lock); 22611ccc910SNamjae Jeon if (is_dealloc == false) 22711ccc910SNamjae Jeon free_clusters -= atomic64_read(&vol->dirty_clusters); 22811ccc910SNamjae Jeon 22911ccc910SNamjae Jeon if (free_clusters < count) { 23011ccc910SNamjae Jeon err = -ENOSPC; 23111ccc910SNamjae Jeon goto out_restore; 23211ccc910SNamjae Jeon } 23311ccc910SNamjae Jeon 2341e9ea7e0SNamjae Jeon /* 2351e9ea7e0SNamjae Jeon * If no specific @start_lcn was requested, use the current data zone 2361e9ea7e0SNamjae Jeon * position, otherwise use the requested @start_lcn but make sure it 2371e9ea7e0SNamjae Jeon * lies outside the mft zone. Also set done_zones to 0 (no zones done) 2381e9ea7e0SNamjae Jeon * and pass depending on whether we are starting inside a zone (1) or 2391e9ea7e0SNamjae Jeon * at the beginning of a zone (2). If requesting from the MFT_ZONE, 2401e9ea7e0SNamjae Jeon * we either start at the current position within the mft zone or at 2411e9ea7e0SNamjae Jeon * the specified position. If the latter is out of bounds then we start 2421e9ea7e0SNamjae Jeon * at the beginning of the MFT_ZONE. 2431e9ea7e0SNamjae Jeon */ 2441e9ea7e0SNamjae Jeon done_zones = 0; 2451e9ea7e0SNamjae Jeon pass = 1; 2461e9ea7e0SNamjae Jeon /* 2471e9ea7e0SNamjae Jeon * zone_start and zone_end are the current search range. search_zone 2481e9ea7e0SNamjae Jeon * is 1 for mft zone, 2 for data zone 1 (end of mft zone till end of 2491e9ea7e0SNamjae Jeon * volume) and 4 for data zone 2 (start of volume till start of mft 2501e9ea7e0SNamjae Jeon * zone). 2511e9ea7e0SNamjae Jeon */ 25211ccc910SNamjae Jeon has_guess = 1; 2531e9ea7e0SNamjae Jeon zone_start = start_lcn; 25411ccc910SNamjae Jeon 2551e9ea7e0SNamjae Jeon if (zone_start < 0) { 2561e9ea7e0SNamjae Jeon if (zone == DATA_ZONE) 2571e9ea7e0SNamjae Jeon zone_start = vol->data1_zone_pos; 2581e9ea7e0SNamjae Jeon else 2591e9ea7e0SNamjae Jeon zone_start = vol->mft_zone_pos; 2601e9ea7e0SNamjae Jeon if (!zone_start) { 2611e9ea7e0SNamjae Jeon /* 2621e9ea7e0SNamjae Jeon * Zone starts at beginning of volume which means a 2631e9ea7e0SNamjae Jeon * single pass is sufficient. 2641e9ea7e0SNamjae Jeon */ 2651e9ea7e0SNamjae Jeon pass = 2; 2661e9ea7e0SNamjae Jeon } 26711ccc910SNamjae Jeon has_guess = 0; 2681e9ea7e0SNamjae Jeon } 26911ccc910SNamjae Jeon 27011ccc910SNamjae Jeon used_zone_pos = has_guess ? 0 : 1; 27111ccc910SNamjae Jeon 27211ccc910SNamjae Jeon if (!zone_start || zone_start == vol->mft_zone_start || 27311ccc910SNamjae Jeon zone_start == vol->mft_zone_end) 27411ccc910SNamjae Jeon pass = 2; 27511ccc910SNamjae Jeon 27611ccc910SNamjae Jeon if (zone_start < vol->mft_zone_start) { 2771e9ea7e0SNamjae Jeon zone_end = vol->mft_zone_start; 2781e9ea7e0SNamjae Jeon search_zone = 4; 27911ccc910SNamjae Jeon /* Skip searching the mft zone. */ 28011ccc910SNamjae Jeon done_zones |= 1; 28111ccc910SNamjae Jeon } else if (zone_start < vol->mft_zone_end) { 28211ccc910SNamjae Jeon zone_end = vol->mft_zone_end; 28311ccc910SNamjae Jeon search_zone = 1; 28411ccc910SNamjae Jeon } else { 28511ccc910SNamjae Jeon zone_end = vol->nr_clusters; 28611ccc910SNamjae Jeon search_zone = 2; 28711ccc910SNamjae Jeon /* Skip searching the mft zone. */ 28811ccc910SNamjae Jeon done_zones |= 1; 2891e9ea7e0SNamjae Jeon } 29011ccc910SNamjae Jeon 2911e9ea7e0SNamjae Jeon /* 2921e9ea7e0SNamjae Jeon * bmp_pos is the current bit position inside the bitmap. We use 2931e9ea7e0SNamjae Jeon * bmp_initial_pos to determine whether or not to do a zone switch. 2941e9ea7e0SNamjae Jeon */ 2951e9ea7e0SNamjae Jeon bmp_pos = bmp_initial_pos = zone_start; 2961e9ea7e0SNamjae Jeon 2971e9ea7e0SNamjae Jeon /* Loop until all clusters are allocated, i.e. clusters == 0. */ 2981e9ea7e0SNamjae Jeon clusters = count; 2991e9ea7e0SNamjae Jeon rlpos = rlsize = 0; 3001e9ea7e0SNamjae Jeon mapping = lcnbmp_vi->i_mapping; 3011e9ea7e0SNamjae Jeon i_size = i_size_read(lcnbmp_vi); 3021e9ea7e0SNamjae Jeon while (1) { 30311ccc910SNamjae Jeon ntfs_debug("Start of outer while loop: done_zones 0x%x, search_zone %i, pass %i, zone_start 0x%llx, zone_end 0x%llx, bmp_initial_pos 0x%llx, bmp_pos 0x%llx, rlpos %i, rlsize %i.", 3041e9ea7e0SNamjae Jeon done_zones, search_zone, pass, 30511ccc910SNamjae Jeon zone_start, zone_end, bmp_initial_pos, 30611ccc910SNamjae Jeon bmp_pos, rlpos, rlsize); 3071e9ea7e0SNamjae Jeon /* Loop until we run out of free clusters. */ 3081e9ea7e0SNamjae Jeon last_read_pos = bmp_pos >> 3; 30911ccc910SNamjae Jeon ntfs_debug("last_read_pos 0x%llx.", last_read_pos); 31011ccc910SNamjae Jeon if (last_read_pos >= i_size) { 31111ccc910SNamjae Jeon ntfs_debug("End of attribute reached. Skipping to zone_pass_done."); 3121e9ea7e0SNamjae Jeon goto zone_pass_done; 3131e9ea7e0SNamjae Jeon } 31411ccc910SNamjae Jeon if (likely(folio)) { 3151e9ea7e0SNamjae Jeon if (need_writeback) { 3161e9ea7e0SNamjae Jeon ntfs_debug("Marking page dirty."); 31711ccc910SNamjae Jeon folio_mark_dirty(folio); 3181e9ea7e0SNamjae Jeon need_writeback = 0; 3191e9ea7e0SNamjae Jeon } 32011ccc910SNamjae Jeon folio_unlock(folio); 32111ccc910SNamjae Jeon kunmap_local(buf); 32211ccc910SNamjae Jeon folio_put(folio); 32311ccc910SNamjae Jeon folio = NULL; 3241e9ea7e0SNamjae Jeon } 32511ccc910SNamjae Jeon 32611ccc910SNamjae Jeon index = last_read_pos >> PAGE_SHIFT; 32711ccc910SNamjae Jeon pg_off = last_read_pos & ~PAGE_MASK; 32811ccc910SNamjae Jeon buf_size = PAGE_SIZE - pg_off; 3291e9ea7e0SNamjae Jeon if (unlikely(last_read_pos + buf_size > i_size)) 3301e9ea7e0SNamjae Jeon buf_size = i_size - last_read_pos; 3311e9ea7e0SNamjae Jeon buf_size <<= 3; 3321e9ea7e0SNamjae Jeon lcn = bmp_pos & 7; 33311ccc910SNamjae Jeon bmp_pos &= ~(s64)7; 33411ccc910SNamjae Jeon 33511ccc910SNamjae Jeon if (vol->lcn_empty_bits_per_page[index] == 0) 33611ccc910SNamjae Jeon goto next_bmp_pos; 33711ccc910SNamjae Jeon 33811ccc910SNamjae Jeon folio = read_mapping_folio(mapping, index, NULL); 33911ccc910SNamjae Jeon if (IS_ERR(folio)) { 34011ccc910SNamjae Jeon err = PTR_ERR(folio); 34111ccc910SNamjae Jeon ntfs_error(vol->sb, "Failed to map page."); 34211ccc910SNamjae Jeon goto out; 34311ccc910SNamjae Jeon } 34411ccc910SNamjae Jeon 34511ccc910SNamjae Jeon folio_lock(folio); 34611ccc910SNamjae Jeon buf = kmap_local_folio(folio, 0) + pg_off; 34711ccc910SNamjae Jeon ntfs_debug("Before inner while loop: buf_size %i, lcn 0x%llx, bmp_pos 0x%llx, need_writeback %i.", 34811ccc910SNamjae Jeon buf_size, lcn, bmp_pos, need_writeback); 3491e9ea7e0SNamjae Jeon while (lcn < buf_size && lcn + bmp_pos < zone_end) { 3501e9ea7e0SNamjae Jeon byte = buf + (lcn >> 3); 35111ccc910SNamjae Jeon ntfs_debug("In inner while loop: buf_size %i, lcn 0x%llx, bmp_pos 0x%llx, need_writeback %i, byte ofs 0x%x, *byte 0x%x.", 35211ccc910SNamjae Jeon buf_size, lcn, bmp_pos, need_writeback, 3531e9ea7e0SNamjae Jeon (unsigned int)(lcn >> 3), 3541e9ea7e0SNamjae Jeon (unsigned int)*byte); 3551e9ea7e0SNamjae Jeon bit = 1 << (lcn & 7); 3561e9ea7e0SNamjae Jeon ntfs_debug("bit 0x%x.", bit); 35711ccc910SNamjae Jeon 35811ccc910SNamjae Jeon if (has_guess) { 3591e9ea7e0SNamjae Jeon if (*byte & bit) { 36011ccc910SNamjae Jeon if (is_contig == true && prev_run_len > 0) 36111ccc910SNamjae Jeon goto done; 36211ccc910SNamjae Jeon 36311ccc910SNamjae Jeon has_guess = 0; 36411ccc910SNamjae Jeon break; 36511ccc910SNamjae Jeon } 36611ccc910SNamjae Jeon } else { 36711ccc910SNamjae Jeon lcn = max_empty_bit_range(buf, buf_size >> 3); 36811ccc910SNamjae Jeon if (lcn < 0) 36911ccc910SNamjae Jeon break; 37011ccc910SNamjae Jeon has_guess = 1; 3711e9ea7e0SNamjae Jeon continue; 3721e9ea7e0SNamjae Jeon } 3731e9ea7e0SNamjae Jeon /* 3741e9ea7e0SNamjae Jeon * Allocate more memory if needed, including space for 3751e9ea7e0SNamjae Jeon * the terminator element. 37611ccc910SNamjae Jeon * kvzalloc() operates on whole pages only. 3771e9ea7e0SNamjae Jeon */ 3781e9ea7e0SNamjae Jeon if ((rlpos + 2) * sizeof(*rl) > rlsize) { 37911ccc910SNamjae Jeon struct runlist_element *rl2; 3801e9ea7e0SNamjae Jeon 3811e9ea7e0SNamjae Jeon ntfs_debug("Reallocating memory."); 3821e9ea7e0SNamjae Jeon if (!rl) 38311ccc910SNamjae Jeon ntfs_debug("First free bit is at s64 0x%llx.", 38411ccc910SNamjae Jeon lcn + bmp_pos); 38511ccc910SNamjae Jeon rl2 = kvzalloc(rlsize + PAGE_SIZE, GFP_NOFS); 3861e9ea7e0SNamjae Jeon if (unlikely(!rl2)) { 3871e9ea7e0SNamjae Jeon err = -ENOMEM; 38811ccc910SNamjae Jeon ntfs_error(vol->sb, "Failed to allocate memory."); 3891e9ea7e0SNamjae Jeon goto out; 3901e9ea7e0SNamjae Jeon } 3911e9ea7e0SNamjae Jeon memcpy(rl2, rl, rlsize); 39211ccc910SNamjae Jeon kvfree(rl); 3931e9ea7e0SNamjae Jeon rl = rl2; 3941e9ea7e0SNamjae Jeon rlsize += PAGE_SIZE; 3951e9ea7e0SNamjae Jeon ntfs_debug("Reallocated memory, rlsize 0x%x.", 3961e9ea7e0SNamjae Jeon rlsize); 3971e9ea7e0SNamjae Jeon } 3981e9ea7e0SNamjae Jeon /* Allocate the bitmap bit. */ 3991e9ea7e0SNamjae Jeon *byte |= bit; 4001e9ea7e0SNamjae Jeon /* We need to write this bitmap page to disk. */ 4011e9ea7e0SNamjae Jeon need_writeback = 1; 4021e9ea7e0SNamjae Jeon ntfs_debug("*byte 0x%x, need_writeback is set.", 4031e9ea7e0SNamjae Jeon (unsigned int)*byte); 40411ccc910SNamjae Jeon ntfs_dec_free_clusters(vol, 1); 40511ccc910SNamjae Jeon ntfs_set_lcn_empty_bits(vol, index, 1, 1); 40611ccc910SNamjae Jeon 4071e9ea7e0SNamjae Jeon /* 4081e9ea7e0SNamjae Jeon * Coalesce with previous run if adjacent LCNs. 4091e9ea7e0SNamjae Jeon * Otherwise, append a new run. 4101e9ea7e0SNamjae Jeon */ 41111ccc910SNamjae Jeon ntfs_debug("Adding run (lcn 0x%llx, len 0x%llx), prev_lcn 0x%llx, lcn 0x%llx, bmp_pos 0x%llx, prev_run_len 0x%llx, rlpos %i.", 41211ccc910SNamjae Jeon lcn + bmp_pos, 1ULL, prev_lcn, 41311ccc910SNamjae Jeon lcn, bmp_pos, prev_run_len, rlpos); 4141e9ea7e0SNamjae Jeon if (prev_lcn == lcn + bmp_pos - prev_run_len && rlpos) { 41511ccc910SNamjae Jeon ntfs_debug("Coalescing to run (lcn 0x%llx, len 0x%llx).", 4161e9ea7e0SNamjae Jeon rl[rlpos - 1].lcn, 4171e9ea7e0SNamjae Jeon rl[rlpos - 1].length); 4181e9ea7e0SNamjae Jeon rl[rlpos - 1].length = ++prev_run_len; 41911ccc910SNamjae Jeon ntfs_debug("Run now (lcn 0x%llx, len 0x%llx), prev_run_len 0x%llx.", 4201e9ea7e0SNamjae Jeon rl[rlpos - 1].lcn, 4211e9ea7e0SNamjae Jeon rl[rlpos - 1].length, 4221e9ea7e0SNamjae Jeon prev_run_len); 4231e9ea7e0SNamjae Jeon } else { 4241e9ea7e0SNamjae Jeon if (likely(rlpos)) { 42511ccc910SNamjae Jeon ntfs_debug("Adding new run, (previous run lcn 0x%llx, len 0x%llx).", 42611ccc910SNamjae Jeon rl[rlpos - 1].lcn, rl[rlpos - 1].length); 4271e9ea7e0SNamjae Jeon rl[rlpos].vcn = rl[rlpos - 1].vcn + 4281e9ea7e0SNamjae Jeon prev_run_len; 4291e9ea7e0SNamjae Jeon } else { 43011ccc910SNamjae Jeon ntfs_debug("Adding new run, is first run."); 4311e9ea7e0SNamjae Jeon rl[rlpos].vcn = start_vcn; 4321e9ea7e0SNamjae Jeon } 4331e9ea7e0SNamjae Jeon rl[rlpos].lcn = prev_lcn = lcn + bmp_pos; 4341e9ea7e0SNamjae Jeon rl[rlpos].length = prev_run_len = 1; 4351e9ea7e0SNamjae Jeon rlpos++; 4361e9ea7e0SNamjae Jeon } 4371e9ea7e0SNamjae Jeon /* Done? */ 4381e9ea7e0SNamjae Jeon if (!--clusters) { 43911ccc910SNamjae Jeon s64 tc; 44011ccc910SNamjae Jeon done: 44111ccc910SNamjae Jeon if (!used_zone_pos) 44211ccc910SNamjae Jeon goto out; 4431e9ea7e0SNamjae Jeon /* 4441e9ea7e0SNamjae Jeon * Update the current zone position. Positions 4451e9ea7e0SNamjae Jeon * of already scanned zones have been updated 4461e9ea7e0SNamjae Jeon * during the respective zone switches. 4471e9ea7e0SNamjae Jeon */ 4481e9ea7e0SNamjae Jeon tc = lcn + bmp_pos + 1; 44911ccc910SNamjae Jeon ntfs_debug("Done. Updating current zone position, tc 0x%llx, search_zone %i.", 45011ccc910SNamjae Jeon tc, search_zone); 4511e9ea7e0SNamjae Jeon switch (search_zone) { 4521e9ea7e0SNamjae Jeon case 1: 45311ccc910SNamjae Jeon ntfs_debug("Before checks, vol->mft_zone_pos 0x%llx.", 4541e9ea7e0SNamjae Jeon vol->mft_zone_pos); 4551e9ea7e0SNamjae Jeon if (tc >= vol->mft_zone_end) { 4561e9ea7e0SNamjae Jeon vol->mft_zone_pos = 4571e9ea7e0SNamjae Jeon vol->mft_lcn; 4581e9ea7e0SNamjae Jeon if (!vol->mft_zone_end) 4591e9ea7e0SNamjae Jeon vol->mft_zone_pos = 0; 4601e9ea7e0SNamjae Jeon } else if ((bmp_initial_pos >= 4611e9ea7e0SNamjae Jeon vol->mft_zone_pos || 4621e9ea7e0SNamjae Jeon tc > vol->mft_zone_pos) 4631e9ea7e0SNamjae Jeon && tc >= vol->mft_lcn) 4641e9ea7e0SNamjae Jeon vol->mft_zone_pos = tc; 46511ccc910SNamjae Jeon ntfs_debug("After checks, vol->mft_zone_pos 0x%llx.", 4661e9ea7e0SNamjae Jeon vol->mft_zone_pos); 4671e9ea7e0SNamjae Jeon break; 4681e9ea7e0SNamjae Jeon case 2: 46911ccc910SNamjae Jeon ntfs_debug("Before checks, vol->data1_zone_pos 0x%llx.", 4701e9ea7e0SNamjae Jeon vol->data1_zone_pos); 4711e9ea7e0SNamjae Jeon if (tc >= vol->nr_clusters) 4721e9ea7e0SNamjae Jeon vol->data1_zone_pos = 4731e9ea7e0SNamjae Jeon vol->mft_zone_end; 4741e9ea7e0SNamjae Jeon else if ((bmp_initial_pos >= 4751e9ea7e0SNamjae Jeon vol->data1_zone_pos || 4761e9ea7e0SNamjae Jeon tc > vol->data1_zone_pos) 4771e9ea7e0SNamjae Jeon && tc >= vol->mft_zone_end) 4781e9ea7e0SNamjae Jeon vol->data1_zone_pos = tc; 47911ccc910SNamjae Jeon ntfs_debug("After checks, vol->data1_zone_pos 0x%llx.", 4801e9ea7e0SNamjae Jeon vol->data1_zone_pos); 4811e9ea7e0SNamjae Jeon break; 4821e9ea7e0SNamjae Jeon case 4: 48311ccc910SNamjae Jeon ntfs_debug("Before checks, vol->data2_zone_pos 0x%llx.", 4841e9ea7e0SNamjae Jeon vol->data2_zone_pos); 4851e9ea7e0SNamjae Jeon if (tc >= vol->mft_zone_start) 4861e9ea7e0SNamjae Jeon vol->data2_zone_pos = 0; 4871e9ea7e0SNamjae Jeon else if (bmp_initial_pos >= 4881e9ea7e0SNamjae Jeon vol->data2_zone_pos || 4891e9ea7e0SNamjae Jeon tc > vol->data2_zone_pos) 4901e9ea7e0SNamjae Jeon vol->data2_zone_pos = tc; 49111ccc910SNamjae Jeon ntfs_debug("After checks, vol->data2_zone_pos 0x%llx.", 4921e9ea7e0SNamjae Jeon vol->data2_zone_pos); 4931e9ea7e0SNamjae Jeon break; 4941e9ea7e0SNamjae Jeon default: 49511ccc910SNamjae Jeon WARN_ON(1); 4961e9ea7e0SNamjae Jeon } 4971e9ea7e0SNamjae Jeon ntfs_debug("Finished. Going to out."); 4981e9ea7e0SNamjae Jeon goto out; 4991e9ea7e0SNamjae Jeon } 5001e9ea7e0SNamjae Jeon lcn++; 5011e9ea7e0SNamjae Jeon } 50211ccc910SNamjae Jeon 50311ccc910SNamjae Jeon if (!used_zone_pos) { 50411ccc910SNamjae Jeon used_zone_pos = 1; 50511ccc910SNamjae Jeon if (search_zone == 1) 50611ccc910SNamjae Jeon zone_start = vol->mft_zone_pos; 50711ccc910SNamjae Jeon else if (search_zone == 2) 50811ccc910SNamjae Jeon zone_start = vol->data1_zone_pos; 50911ccc910SNamjae Jeon else 51011ccc910SNamjae Jeon zone_start = vol->data2_zone_pos; 51111ccc910SNamjae Jeon 51211ccc910SNamjae Jeon if (!zone_start || zone_start == vol->mft_zone_start || 51311ccc910SNamjae Jeon zone_start == vol->mft_zone_end) 51411ccc910SNamjae Jeon pass = 2; 51511ccc910SNamjae Jeon bmp_pos = zone_start; 51611ccc910SNamjae Jeon } else { 51711ccc910SNamjae Jeon next_bmp_pos: 5181e9ea7e0SNamjae Jeon bmp_pos += buf_size; 51911ccc910SNamjae Jeon } 52011ccc910SNamjae Jeon 52111ccc910SNamjae Jeon ntfs_debug("After inner while loop: buf_size 0x%x, lcn 0x%llx, bmp_pos 0x%llx, need_writeback %i.", 52211ccc910SNamjae Jeon buf_size, lcn, bmp_pos, need_writeback); 5231e9ea7e0SNamjae Jeon if (bmp_pos < zone_end) { 52411ccc910SNamjae Jeon ntfs_debug("Continuing outer while loop, bmp_pos 0x%llx, zone_end 0x%llx.", 52511ccc910SNamjae Jeon bmp_pos, zone_end); 5261e9ea7e0SNamjae Jeon continue; 5271e9ea7e0SNamjae Jeon } 5281e9ea7e0SNamjae Jeon zone_pass_done: /* Finished with the current zone pass. */ 5291e9ea7e0SNamjae Jeon ntfs_debug("At zone_pass_done, pass %i.", pass); 5301e9ea7e0SNamjae Jeon if (pass == 1) { 5311e9ea7e0SNamjae Jeon /* 5321e9ea7e0SNamjae Jeon * Now do pass 2, scanning the first part of the zone 5331e9ea7e0SNamjae Jeon * we omitted in pass 1. 5341e9ea7e0SNamjae Jeon */ 5351e9ea7e0SNamjae Jeon pass = 2; 5361e9ea7e0SNamjae Jeon zone_end = zone_start; 5371e9ea7e0SNamjae Jeon switch (search_zone) { 5381e9ea7e0SNamjae Jeon case 1: /* mft_zone */ 5391e9ea7e0SNamjae Jeon zone_start = vol->mft_zone_start; 5401e9ea7e0SNamjae Jeon break; 5411e9ea7e0SNamjae Jeon case 2: /* data1_zone */ 5421e9ea7e0SNamjae Jeon zone_start = vol->mft_zone_end; 5431e9ea7e0SNamjae Jeon break; 5441e9ea7e0SNamjae Jeon case 4: /* data2_zone */ 5451e9ea7e0SNamjae Jeon zone_start = 0; 5461e9ea7e0SNamjae Jeon break; 5471e9ea7e0SNamjae Jeon default: 54811ccc910SNamjae Jeon WARN_ON(1); 5491e9ea7e0SNamjae Jeon } 5501e9ea7e0SNamjae Jeon /* Sanity check. */ 5511e9ea7e0SNamjae Jeon if (zone_end < zone_start) 5521e9ea7e0SNamjae Jeon zone_end = zone_start; 5531e9ea7e0SNamjae Jeon bmp_pos = zone_start; 55411ccc910SNamjae Jeon ntfs_debug("Continuing outer while loop, pass 2, zone_start 0x%llx, zone_end 0x%llx, bmp_pos 0x%llx.", 55511ccc910SNamjae Jeon zone_start, zone_end, bmp_pos); 5561e9ea7e0SNamjae Jeon continue; 5571e9ea7e0SNamjae Jeon } /* pass == 2 */ 5581e9ea7e0SNamjae Jeon done_zones_check: 55911ccc910SNamjae Jeon ntfs_debug("At done_zones_check, search_zone %i, done_zones before 0x%x, done_zones after 0x%x.", 5601e9ea7e0SNamjae Jeon search_zone, done_zones, 5611e9ea7e0SNamjae Jeon done_zones | search_zone); 5621e9ea7e0SNamjae Jeon done_zones |= search_zone; 5631e9ea7e0SNamjae Jeon if (done_zones < 7) { 5641e9ea7e0SNamjae Jeon ntfs_debug("Switching zone."); 5651e9ea7e0SNamjae Jeon /* Now switch to the next zone we haven't done yet. */ 5661e9ea7e0SNamjae Jeon pass = 1; 5671e9ea7e0SNamjae Jeon switch (search_zone) { 5681e9ea7e0SNamjae Jeon case 1: 56911ccc910SNamjae Jeon ntfs_debug("Switching from mft zone to data1 zone."); 5701e9ea7e0SNamjae Jeon /* Update mft zone position. */ 57111ccc910SNamjae Jeon if (rlpos && used_zone_pos) { 57211ccc910SNamjae Jeon s64 tc; 5731e9ea7e0SNamjae Jeon 57411ccc910SNamjae Jeon ntfs_debug("Before checks, vol->mft_zone_pos 0x%llx.", 5751e9ea7e0SNamjae Jeon vol->mft_zone_pos); 5761e9ea7e0SNamjae Jeon tc = rl[rlpos - 1].lcn + 5771e9ea7e0SNamjae Jeon rl[rlpos - 1].length; 5781e9ea7e0SNamjae Jeon if (tc >= vol->mft_zone_end) { 5791e9ea7e0SNamjae Jeon vol->mft_zone_pos = 5801e9ea7e0SNamjae Jeon vol->mft_lcn; 5811e9ea7e0SNamjae Jeon if (!vol->mft_zone_end) 5821e9ea7e0SNamjae Jeon vol->mft_zone_pos = 0; 5831e9ea7e0SNamjae Jeon } else if ((bmp_initial_pos >= 5841e9ea7e0SNamjae Jeon vol->mft_zone_pos || 5851e9ea7e0SNamjae Jeon tc > vol->mft_zone_pos) 5861e9ea7e0SNamjae Jeon && tc >= vol->mft_lcn) 5871e9ea7e0SNamjae Jeon vol->mft_zone_pos = tc; 58811ccc910SNamjae Jeon ntfs_debug("After checks, vol->mft_zone_pos 0x%llx.", 5891e9ea7e0SNamjae Jeon vol->mft_zone_pos); 5901e9ea7e0SNamjae Jeon } 5911e9ea7e0SNamjae Jeon /* Switch from mft zone to data1 zone. */ 5921e9ea7e0SNamjae Jeon switch_to_data1_zone: search_zone = 2; 5931e9ea7e0SNamjae Jeon zone_start = bmp_initial_pos = 5941e9ea7e0SNamjae Jeon vol->data1_zone_pos; 5951e9ea7e0SNamjae Jeon zone_end = vol->nr_clusters; 5961e9ea7e0SNamjae Jeon if (zone_start == vol->mft_zone_end) 5971e9ea7e0SNamjae Jeon pass = 2; 5981e9ea7e0SNamjae Jeon if (zone_start >= zone_end) { 5991e9ea7e0SNamjae Jeon vol->data1_zone_pos = zone_start = 6001e9ea7e0SNamjae Jeon vol->mft_zone_end; 6011e9ea7e0SNamjae Jeon pass = 2; 6021e9ea7e0SNamjae Jeon } 6031e9ea7e0SNamjae Jeon break; 6041e9ea7e0SNamjae Jeon case 2: 60511ccc910SNamjae Jeon ntfs_debug("Switching from data1 zone to data2 zone."); 6061e9ea7e0SNamjae Jeon /* Update data1 zone position. */ 60711ccc910SNamjae Jeon if (rlpos && used_zone_pos) { 60811ccc910SNamjae Jeon s64 tc; 6091e9ea7e0SNamjae Jeon 61011ccc910SNamjae Jeon ntfs_debug("Before checks, vol->data1_zone_pos 0x%llx.", 6111e9ea7e0SNamjae Jeon vol->data1_zone_pos); 6121e9ea7e0SNamjae Jeon tc = rl[rlpos - 1].lcn + 6131e9ea7e0SNamjae Jeon rl[rlpos - 1].length; 6141e9ea7e0SNamjae Jeon if (tc >= vol->nr_clusters) 6151e9ea7e0SNamjae Jeon vol->data1_zone_pos = 6161e9ea7e0SNamjae Jeon vol->mft_zone_end; 6171e9ea7e0SNamjae Jeon else if ((bmp_initial_pos >= 6181e9ea7e0SNamjae Jeon vol->data1_zone_pos || 6191e9ea7e0SNamjae Jeon tc > vol->data1_zone_pos) 6201e9ea7e0SNamjae Jeon && tc >= vol->mft_zone_end) 6211e9ea7e0SNamjae Jeon vol->data1_zone_pos = tc; 62211ccc910SNamjae Jeon ntfs_debug("After checks, vol->data1_zone_pos 0x%llx.", 6231e9ea7e0SNamjae Jeon vol->data1_zone_pos); 6241e9ea7e0SNamjae Jeon } 6251e9ea7e0SNamjae Jeon /* Switch from data1 zone to data2 zone. */ 6261e9ea7e0SNamjae Jeon search_zone = 4; 6271e9ea7e0SNamjae Jeon zone_start = bmp_initial_pos = 6281e9ea7e0SNamjae Jeon vol->data2_zone_pos; 6291e9ea7e0SNamjae Jeon zone_end = vol->mft_zone_start; 6301e9ea7e0SNamjae Jeon if (!zone_start) 6311e9ea7e0SNamjae Jeon pass = 2; 6321e9ea7e0SNamjae Jeon if (zone_start >= zone_end) { 6331e9ea7e0SNamjae Jeon vol->data2_zone_pos = zone_start = 6341e9ea7e0SNamjae Jeon bmp_initial_pos = 0; 6351e9ea7e0SNamjae Jeon pass = 2; 6361e9ea7e0SNamjae Jeon } 6371e9ea7e0SNamjae Jeon break; 6381e9ea7e0SNamjae Jeon case 4: 63911ccc910SNamjae Jeon ntfs_debug("Switching from data2 zone to data1 zone."); 6401e9ea7e0SNamjae Jeon /* Update data2 zone position. */ 64111ccc910SNamjae Jeon if (rlpos && used_zone_pos) { 64211ccc910SNamjae Jeon s64 tc; 6431e9ea7e0SNamjae Jeon 64411ccc910SNamjae Jeon ntfs_debug("Before checks, vol->data2_zone_pos 0x%llx.", 6451e9ea7e0SNamjae Jeon vol->data2_zone_pos); 6461e9ea7e0SNamjae Jeon tc = rl[rlpos - 1].lcn + 6471e9ea7e0SNamjae Jeon rl[rlpos - 1].length; 6481e9ea7e0SNamjae Jeon if (tc >= vol->mft_zone_start) 6491e9ea7e0SNamjae Jeon vol->data2_zone_pos = 0; 6501e9ea7e0SNamjae Jeon else if (bmp_initial_pos >= 6511e9ea7e0SNamjae Jeon vol->data2_zone_pos || 6521e9ea7e0SNamjae Jeon tc > vol->data2_zone_pos) 6531e9ea7e0SNamjae Jeon vol->data2_zone_pos = tc; 65411ccc910SNamjae Jeon ntfs_debug("After checks, vol->data2_zone_pos 0x%llx.", 6551e9ea7e0SNamjae Jeon vol->data2_zone_pos); 6561e9ea7e0SNamjae Jeon } 6571e9ea7e0SNamjae Jeon /* Switch from data2 zone to data1 zone. */ 6581e9ea7e0SNamjae Jeon goto switch_to_data1_zone; 6591e9ea7e0SNamjae Jeon default: 66011ccc910SNamjae Jeon WARN_ON(1); 6611e9ea7e0SNamjae Jeon } 66211ccc910SNamjae Jeon ntfs_debug("After zone switch, search_zone %i, pass %i, bmp_initial_pos 0x%llx, zone_start 0x%llx, zone_end 0x%llx.", 6631e9ea7e0SNamjae Jeon search_zone, pass, 66411ccc910SNamjae Jeon bmp_initial_pos, 66511ccc910SNamjae Jeon zone_start, 66611ccc910SNamjae Jeon zone_end); 6671e9ea7e0SNamjae Jeon bmp_pos = zone_start; 6681e9ea7e0SNamjae Jeon if (zone_start == zone_end) { 66911ccc910SNamjae Jeon ntfs_debug("Empty zone, going to done_zones_check."); 6701e9ea7e0SNamjae Jeon /* Empty zone. Don't bother searching it. */ 6711e9ea7e0SNamjae Jeon goto done_zones_check; 6721e9ea7e0SNamjae Jeon } 6731e9ea7e0SNamjae Jeon ntfs_debug("Continuing outer while loop."); 6741e9ea7e0SNamjae Jeon continue; 6751e9ea7e0SNamjae Jeon } /* done_zones == 7 */ 6761e9ea7e0SNamjae Jeon ntfs_debug("All zones are finished."); 6771e9ea7e0SNamjae Jeon /* 6781e9ea7e0SNamjae Jeon * All zones are finished! If DATA_ZONE, shrink mft zone. If 6791e9ea7e0SNamjae Jeon * MFT_ZONE, we have really run out of space. 6801e9ea7e0SNamjae Jeon */ 6811e9ea7e0SNamjae Jeon mft_zone_size = vol->mft_zone_end - vol->mft_zone_start; 68211ccc910SNamjae Jeon ntfs_debug("vol->mft_zone_start 0x%llx, vol->mft_zone_end 0x%llx, mft_zone_size 0x%llx.", 68311ccc910SNamjae Jeon vol->mft_zone_start, vol->mft_zone_end, 68411ccc910SNamjae Jeon mft_zone_size); 6851e9ea7e0SNamjae Jeon if (zone == MFT_ZONE || mft_zone_size <= 0) { 6861e9ea7e0SNamjae Jeon ntfs_debug("No free clusters left, going to out."); 6871e9ea7e0SNamjae Jeon /* Really no more space left on device. */ 6881e9ea7e0SNamjae Jeon err = -ENOSPC; 6891e9ea7e0SNamjae Jeon goto out; 6901e9ea7e0SNamjae Jeon } /* zone == DATA_ZONE && mft_zone_size > 0 */ 6911e9ea7e0SNamjae Jeon ntfs_debug("Shrinking mft zone."); 6921e9ea7e0SNamjae Jeon zone_end = vol->mft_zone_end; 6931e9ea7e0SNamjae Jeon mft_zone_size >>= 1; 6941e9ea7e0SNamjae Jeon if (mft_zone_size > 0) 6951e9ea7e0SNamjae Jeon vol->mft_zone_end = vol->mft_zone_start + mft_zone_size; 6961e9ea7e0SNamjae Jeon else /* mft zone and data2 zone no longer exist. */ 6971e9ea7e0SNamjae Jeon vol->data2_zone_pos = vol->mft_zone_start = 6981e9ea7e0SNamjae Jeon vol->mft_zone_end = 0; 6991e9ea7e0SNamjae Jeon if (vol->mft_zone_pos >= vol->mft_zone_end) { 7001e9ea7e0SNamjae Jeon vol->mft_zone_pos = vol->mft_lcn; 7011e9ea7e0SNamjae Jeon if (!vol->mft_zone_end) 7021e9ea7e0SNamjae Jeon vol->mft_zone_pos = 0; 7031e9ea7e0SNamjae Jeon } 7041e9ea7e0SNamjae Jeon bmp_pos = zone_start = bmp_initial_pos = 7051e9ea7e0SNamjae Jeon vol->data1_zone_pos = vol->mft_zone_end; 7061e9ea7e0SNamjae Jeon search_zone = 2; 7071e9ea7e0SNamjae Jeon pass = 2; 7081e9ea7e0SNamjae Jeon done_zones &= ~2; 70911ccc910SNamjae Jeon ntfs_debug("After shrinking mft zone, mft_zone_size 0x%llx, vol->mft_zone_start 0x%llx, vol->mft_zone_end 0x%llx, vol->mft_zone_pos 0x%llx, search_zone 2, pass 2, dones_zones 0x%x, zone_start 0x%llx, zone_end 0x%llx, vol->data1_zone_pos 0x%llx, continuing outer while loop.", 71011ccc910SNamjae Jeon mft_zone_size, vol->mft_zone_start, 71111ccc910SNamjae Jeon vol->mft_zone_end, vol->mft_zone_pos, 71211ccc910SNamjae Jeon done_zones, zone_start, zone_end, 71311ccc910SNamjae Jeon vol->data1_zone_pos); 7141e9ea7e0SNamjae Jeon } 7151e9ea7e0SNamjae Jeon ntfs_debug("After outer while loop."); 7161e9ea7e0SNamjae Jeon out: 7171e9ea7e0SNamjae Jeon ntfs_debug("At out."); 7181e9ea7e0SNamjae Jeon /* Add runlist terminator element. */ 7191e9ea7e0SNamjae Jeon if (likely(rl)) { 7201e9ea7e0SNamjae Jeon rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; 7211e9ea7e0SNamjae Jeon rl[rlpos].lcn = is_extension ? LCN_ENOENT : LCN_RL_NOT_MAPPED; 7221e9ea7e0SNamjae Jeon rl[rlpos].length = 0; 7231e9ea7e0SNamjae Jeon } 7247cf4b3c7SHyunchul Lee if (!IS_ERR_OR_NULL(folio)) { 7251e9ea7e0SNamjae Jeon if (need_writeback) { 7261e9ea7e0SNamjae Jeon ntfs_debug("Marking page dirty."); 72711ccc910SNamjae Jeon folio_mark_dirty(folio); 7281e9ea7e0SNamjae Jeon need_writeback = 0; 7291e9ea7e0SNamjae Jeon } 73011ccc910SNamjae Jeon folio_unlock(folio); 73111ccc910SNamjae Jeon kunmap_local(buf); 73211ccc910SNamjae Jeon folio_put(folio); 7331e9ea7e0SNamjae Jeon } 7341e9ea7e0SNamjae Jeon if (likely(!err)) { 735*4e59f8a1SHyunchul Lee if (!rl) { 736*4e59f8a1SHyunchul Lee err = -EIO; 737*4e59f8a1SHyunchul Lee goto out_restore; 738*4e59f8a1SHyunchul Lee } 73911ccc910SNamjae Jeon if (is_dealloc == true) 74011ccc910SNamjae Jeon ntfs_release_dirty_clusters(vol, rl->length); 7411e9ea7e0SNamjae Jeon ntfs_debug("Done."); 74211ccc910SNamjae Jeon goto out_restore; 7431e9ea7e0SNamjae Jeon } 74411ccc910SNamjae Jeon if (err != -ENOSPC) 74511ccc910SNamjae Jeon ntfs_error(vol->sb, 74611ccc910SNamjae Jeon "Failed to allocate clusters, aborting (error %i).", 74711ccc910SNamjae Jeon err); 7481e9ea7e0SNamjae Jeon if (rl) { 7491e9ea7e0SNamjae Jeon int err2; 7501e9ea7e0SNamjae Jeon 7511e9ea7e0SNamjae Jeon if (err == -ENOSPC) 75211ccc910SNamjae Jeon ntfs_debug("Not enough space to complete allocation, err -ENOSPC, first free lcn 0x%llx, could allocate up to 0x%llx clusters.", 75311ccc910SNamjae Jeon rl[0].lcn, count - clusters); 7541e9ea7e0SNamjae Jeon /* Deallocate all allocated clusters. */ 7551e9ea7e0SNamjae Jeon ntfs_debug("Attempting rollback..."); 7561e9ea7e0SNamjae Jeon err2 = ntfs_cluster_free_from_rl_nolock(vol, rl); 7571e9ea7e0SNamjae Jeon if (err2) { 75811ccc910SNamjae Jeon ntfs_error(vol->sb, 75911ccc910SNamjae Jeon "Failed to rollback (error %i). Leaving inconsistent metadata! Unmount and run chkdsk.", 76011ccc910SNamjae Jeon err2); 7611e9ea7e0SNamjae Jeon NVolSetErrors(vol); 7621e9ea7e0SNamjae Jeon } 7631e9ea7e0SNamjae Jeon /* Free the runlist. */ 76411ccc910SNamjae Jeon kvfree(rl); 7651e9ea7e0SNamjae Jeon } else if (err == -ENOSPC) 76611ccc910SNamjae Jeon ntfs_debug("No space left at all, err = -ENOSPC, first free lcn = 0x%llx.", 76711ccc910SNamjae Jeon vol->data1_zone_pos); 76811ccc910SNamjae Jeon atomic64_set(&vol->dirty_clusters, 0); 76911ccc910SNamjae Jeon 77011ccc910SNamjae Jeon out_restore: 7711e9ea7e0SNamjae Jeon up_write(&vol->lcnbmp_lock); 77211ccc910SNamjae Jeon memalloc_nofs_restore(memalloc_flags); 77311ccc910SNamjae Jeon 77411ccc910SNamjae Jeon return err < 0 ? ERR_PTR(err) : rl; 7751e9ea7e0SNamjae Jeon } 7761e9ea7e0SNamjae Jeon 77711ccc910SNamjae Jeon /* 7781e9ea7e0SNamjae Jeon * __ntfs_cluster_free - free clusters on an ntfs volume 7791e9ea7e0SNamjae Jeon * @ni: ntfs inode whose runlist describes the clusters to free 7801e9ea7e0SNamjae Jeon * @start_vcn: vcn in the runlist of @ni at which to start freeing clusters 7811e9ea7e0SNamjae Jeon * @count: number of clusters to free or -1 for all clusters 7821e9ea7e0SNamjae Jeon * @ctx: active attribute search context if present or NULL if not 7831e9ea7e0SNamjae Jeon * @is_rollback: true if this is a rollback operation 7841e9ea7e0SNamjae Jeon * 7851e9ea7e0SNamjae Jeon * Free @count clusters starting at the cluster @start_vcn in the runlist 7861e9ea7e0SNamjae Jeon * described by the vfs inode @ni. 7871e9ea7e0SNamjae Jeon * 7881e9ea7e0SNamjae Jeon * If @count is -1, all clusters from @start_vcn to the end of the runlist are 7891e9ea7e0SNamjae Jeon * deallocated. Thus, to completely free all clusters in a runlist, use 7901e9ea7e0SNamjae Jeon * @start_vcn = 0 and @count = -1. 7911e9ea7e0SNamjae Jeon * 7921e9ea7e0SNamjae Jeon * If @ctx is specified, it is an active search context of @ni and its base mft 7931e9ea7e0SNamjae Jeon * record. This is needed when __ntfs_cluster_free() encounters unmapped 7941e9ea7e0SNamjae Jeon * runlist fragments and allows their mapping. If you do not have the mft 7951e9ea7e0SNamjae Jeon * record mapped, you can specify @ctx as NULL and __ntfs_cluster_free() will 7961e9ea7e0SNamjae Jeon * perform the necessary mapping and unmapping. 7971e9ea7e0SNamjae Jeon * 7981e9ea7e0SNamjae Jeon * Note, __ntfs_cluster_free() saves the state of @ctx on entry and restores it 7991e9ea7e0SNamjae Jeon * before returning. Thus, @ctx will be left pointing to the same attribute on 8001e9ea7e0SNamjae Jeon * return as on entry. However, the actual pointers in @ctx may point to 8011e9ea7e0SNamjae Jeon * different memory locations on return, so you must remember to reset any 8021e9ea7e0SNamjae Jeon * cached pointers from the @ctx, i.e. after the call to __ntfs_cluster_free(), 8031e9ea7e0SNamjae Jeon * you will probably want to do: 8041e9ea7e0SNamjae Jeon * m = ctx->mrec; 8051e9ea7e0SNamjae Jeon * a = ctx->attr; 80611ccc910SNamjae Jeon * Assuming you cache ctx->attr in a variable @a of type attr_record * and that 80711ccc910SNamjae Jeon * you cache ctx->mrec in a variable @m of type struct mft_record *. 8081e9ea7e0SNamjae Jeon * 8091e9ea7e0SNamjae Jeon * @is_rollback should always be 'false', it is for internal use to rollback 8101e9ea7e0SNamjae Jeon * errors. You probably want to use ntfs_cluster_free() instead. 8111e9ea7e0SNamjae Jeon * 8121e9ea7e0SNamjae Jeon * Note, __ntfs_cluster_free() does not modify the runlist, so you have to 8131e9ea7e0SNamjae Jeon * remove from the runlist or mark sparse the freed runs later. 8141e9ea7e0SNamjae Jeon * 8151e9ea7e0SNamjae Jeon * Return the number of deallocated clusters (not counting sparse ones) on 8161e9ea7e0SNamjae Jeon * success and -errno on error. 8171e9ea7e0SNamjae Jeon * 8181e9ea7e0SNamjae Jeon * WARNING: If @ctx is supplied, regardless of whether success or failure is 8191e9ea7e0SNamjae Jeon * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx 8201e9ea7e0SNamjae Jeon * is no longer valid, i.e. you need to either call 8211e9ea7e0SNamjae Jeon * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. 8221e9ea7e0SNamjae Jeon * In that case PTR_ERR(@ctx->mrec) will give you the error code for 8231e9ea7e0SNamjae Jeon * why the mapping of the old inode failed. 8241e9ea7e0SNamjae Jeon * 8251e9ea7e0SNamjae Jeon * Locking: - The runlist described by @ni must be locked for writing on entry 8261e9ea7e0SNamjae Jeon * and is locked on return. Note the runlist may be modified when 8271e9ea7e0SNamjae Jeon * needed runlist fragments need to be mapped. 8281e9ea7e0SNamjae Jeon * - The volume lcn bitmap must be unlocked on entry and is unlocked 8291e9ea7e0SNamjae Jeon * on return. 8301e9ea7e0SNamjae Jeon * - This function takes the volume lcn bitmap lock for writing and 8311e9ea7e0SNamjae Jeon * modifies the bitmap contents. 8321e9ea7e0SNamjae Jeon * - If @ctx is NULL, the base mft record of @ni must not be mapped on 8331e9ea7e0SNamjae Jeon * entry and it will be left unmapped on return. 8341e9ea7e0SNamjae Jeon * - If @ctx is not NULL, the base mft record must be mapped on entry 8351e9ea7e0SNamjae Jeon * and it will be left mapped on return. 8361e9ea7e0SNamjae Jeon */ 83711ccc910SNamjae Jeon s64 __ntfs_cluster_free(struct ntfs_inode *ni, const s64 start_vcn, s64 count, 83811ccc910SNamjae Jeon struct ntfs_attr_search_ctx *ctx, const bool is_rollback) 8391e9ea7e0SNamjae Jeon { 8401e9ea7e0SNamjae Jeon s64 delta, to_free, total_freed, real_freed; 84111ccc910SNamjae Jeon struct ntfs_volume *vol; 8421e9ea7e0SNamjae Jeon struct inode *lcnbmp_vi; 84311ccc910SNamjae Jeon struct runlist_element *rl; 8441e9ea7e0SNamjae Jeon int err; 84511ccc910SNamjae Jeon unsigned int memalloc_flags; 8461e9ea7e0SNamjae Jeon 847d9038d99SNamjae Jeon ntfs_debug("Entering for i_ino 0x%llx, start_vcn 0x%llx, count 0x%llx.%s", 84811ccc910SNamjae Jeon ni->mft_no, start_vcn, count, 8491e9ea7e0SNamjae Jeon is_rollback ? " (rollback)" : ""); 8501e9ea7e0SNamjae Jeon vol = ni->vol; 8511e9ea7e0SNamjae Jeon lcnbmp_vi = vol->lcnbmp_ino; 85211ccc910SNamjae Jeon if (start_vcn < 0 || count < -1) 85311ccc910SNamjae Jeon return -EINVAL; 85411ccc910SNamjae Jeon 85511ccc910SNamjae Jeon if (!NVolFreeClusterKnown(vol)) 85611ccc910SNamjae Jeon wait_event(vol->free_waitq, NVolFreeClusterKnown(vol)); 85711ccc910SNamjae Jeon 8581e9ea7e0SNamjae Jeon /* 8591e9ea7e0SNamjae Jeon * Lock the lcn bitmap for writing but only if not rolling back. We 8601e9ea7e0SNamjae Jeon * must hold the lock all the way including through rollback otherwise 8611e9ea7e0SNamjae Jeon * rollback is not possible because once we have cleared a bit and 8621e9ea7e0SNamjae Jeon * dropped the lock, anyone could have set the bit again, thus 8631e9ea7e0SNamjae Jeon * allocating the cluster for another use. 8641e9ea7e0SNamjae Jeon */ 86511ccc910SNamjae Jeon if (likely(!is_rollback)) { 86611ccc910SNamjae Jeon memalloc_flags = memalloc_nofs_save(); 8671e9ea7e0SNamjae Jeon down_write(&vol->lcnbmp_lock); 86811ccc910SNamjae Jeon } 8691e9ea7e0SNamjae Jeon 8701e9ea7e0SNamjae Jeon total_freed = real_freed = 0; 8711e9ea7e0SNamjae Jeon 8721e9ea7e0SNamjae Jeon rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, ctx); 8731e9ea7e0SNamjae Jeon if (IS_ERR(rl)) { 8741e9ea7e0SNamjae Jeon err = PTR_ERR(rl); 87511ccc910SNamjae Jeon if (err == -ENOENT) { 87611ccc910SNamjae Jeon if (likely(!is_rollback)) { 87711ccc910SNamjae Jeon up_write(&vol->lcnbmp_lock); 87811ccc910SNamjae Jeon memalloc_nofs_restore(memalloc_flags); 87911ccc910SNamjae Jeon } 88011ccc910SNamjae Jeon return 0; 88111ccc910SNamjae Jeon } 88211ccc910SNamjae Jeon 88311ccc910SNamjae Jeon if (!is_rollback) 88411ccc910SNamjae Jeon ntfs_error(vol->sb, 88511ccc910SNamjae Jeon "Failed to find first runlist element (error %d), aborting.", 88611ccc910SNamjae Jeon err); 8871e9ea7e0SNamjae Jeon goto err_out; 8881e9ea7e0SNamjae Jeon } 8891e9ea7e0SNamjae Jeon if (unlikely(rl->lcn < LCN_HOLE)) { 8901e9ea7e0SNamjae Jeon if (!is_rollback) 89111ccc910SNamjae Jeon ntfs_error(vol->sb, "First runlist element has invalid lcn, aborting."); 8921e9ea7e0SNamjae Jeon err = -EIO; 8931e9ea7e0SNamjae Jeon goto err_out; 8941e9ea7e0SNamjae Jeon } 8951e9ea7e0SNamjae Jeon /* Find the starting cluster inside the run that needs freeing. */ 8961e9ea7e0SNamjae Jeon delta = start_vcn - rl->vcn; 8971e9ea7e0SNamjae Jeon 8981e9ea7e0SNamjae Jeon /* The number of clusters in this run that need freeing. */ 8991e9ea7e0SNamjae Jeon to_free = rl->length - delta; 9001e9ea7e0SNamjae Jeon if (count >= 0 && to_free > count) 9011e9ea7e0SNamjae Jeon to_free = count; 9021e9ea7e0SNamjae Jeon 9031e9ea7e0SNamjae Jeon if (likely(rl->lcn >= 0)) { 9041e9ea7e0SNamjae Jeon /* Do the actual freeing of the clusters in this run. */ 9051e9ea7e0SNamjae Jeon err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn + delta, 9061e9ea7e0SNamjae Jeon to_free, likely(!is_rollback) ? 0 : 1); 9071e9ea7e0SNamjae Jeon if (unlikely(err)) { 9081e9ea7e0SNamjae Jeon if (!is_rollback) 90911ccc910SNamjae Jeon ntfs_error(vol->sb, 91011ccc910SNamjae Jeon "Failed to clear first run (error %i), aborting.", 91111ccc910SNamjae Jeon err); 9121e9ea7e0SNamjae Jeon goto err_out; 9131e9ea7e0SNamjae Jeon } 9141e9ea7e0SNamjae Jeon /* We have freed @to_free real clusters. */ 9151e9ea7e0SNamjae Jeon real_freed = to_free; 91611ccc910SNamjae Jeon } 9171e9ea7e0SNamjae Jeon /* Go to the next run and adjust the number of clusters left to free. */ 9181e9ea7e0SNamjae Jeon ++rl; 9191e9ea7e0SNamjae Jeon if (count >= 0) 9201e9ea7e0SNamjae Jeon count -= to_free; 9211e9ea7e0SNamjae Jeon 9221e9ea7e0SNamjae Jeon /* Keep track of the total "freed" clusters, including sparse ones. */ 9231e9ea7e0SNamjae Jeon total_freed = to_free; 9241e9ea7e0SNamjae Jeon /* 9251e9ea7e0SNamjae Jeon * Loop over the remaining runs, using @count as a capping value, and 9261e9ea7e0SNamjae Jeon * free them. 9271e9ea7e0SNamjae Jeon */ 9281e9ea7e0SNamjae Jeon for (; rl->length && count != 0; ++rl) { 9291e9ea7e0SNamjae Jeon if (unlikely(rl->lcn < LCN_HOLE)) { 93011ccc910SNamjae Jeon s64 vcn; 9311e9ea7e0SNamjae Jeon 9321e9ea7e0SNamjae Jeon /* Attempt to map runlist. */ 9331e9ea7e0SNamjae Jeon vcn = rl->vcn; 9341e9ea7e0SNamjae Jeon rl = ntfs_attr_find_vcn_nolock(ni, vcn, ctx); 9351e9ea7e0SNamjae Jeon if (IS_ERR(rl)) { 9361e9ea7e0SNamjae Jeon err = PTR_ERR(rl); 9371e9ea7e0SNamjae Jeon if (!is_rollback) 93811ccc910SNamjae Jeon ntfs_error(vol->sb, 93911ccc910SNamjae Jeon "Failed to map runlist fragment or failed to find subsequent runlist element."); 9401e9ea7e0SNamjae Jeon goto err_out; 9411e9ea7e0SNamjae Jeon } 9421e9ea7e0SNamjae Jeon if (unlikely(rl->lcn < LCN_HOLE)) { 9431e9ea7e0SNamjae Jeon if (!is_rollback) 94411ccc910SNamjae Jeon ntfs_error(vol->sb, 94511ccc910SNamjae Jeon "Runlist element has invalid lcn (0x%llx).", 9461e9ea7e0SNamjae Jeon rl->lcn); 9471e9ea7e0SNamjae Jeon err = -EIO; 9481e9ea7e0SNamjae Jeon goto err_out; 9491e9ea7e0SNamjae Jeon } 9501e9ea7e0SNamjae Jeon } 9511e9ea7e0SNamjae Jeon /* The number of clusters in this run that need freeing. */ 9521e9ea7e0SNamjae Jeon to_free = rl->length; 9531e9ea7e0SNamjae Jeon if (count >= 0 && to_free > count) 9541e9ea7e0SNamjae Jeon to_free = count; 9551e9ea7e0SNamjae Jeon 9561e9ea7e0SNamjae Jeon if (likely(rl->lcn >= 0)) { 9571e9ea7e0SNamjae Jeon /* Do the actual freeing of the clusters in the run. */ 9581e9ea7e0SNamjae Jeon err = ntfs_bitmap_set_bits_in_run(lcnbmp_vi, rl->lcn, 9591e9ea7e0SNamjae Jeon to_free, likely(!is_rollback) ? 0 : 1); 9601e9ea7e0SNamjae Jeon if (unlikely(err)) { 9611e9ea7e0SNamjae Jeon if (!is_rollback) 96211ccc910SNamjae Jeon ntfs_error(vol->sb, "Failed to clear subsequent run."); 9631e9ea7e0SNamjae Jeon goto err_out; 9641e9ea7e0SNamjae Jeon } 9651e9ea7e0SNamjae Jeon /* We have freed @to_free real clusters. */ 9661e9ea7e0SNamjae Jeon real_freed += to_free; 9671e9ea7e0SNamjae Jeon } 9681e9ea7e0SNamjae Jeon /* Adjust the number of clusters left to free. */ 9691e9ea7e0SNamjae Jeon if (count >= 0) 9701e9ea7e0SNamjae Jeon count -= to_free; 9711e9ea7e0SNamjae Jeon 9721e9ea7e0SNamjae Jeon /* Update the total done clusters. */ 9731e9ea7e0SNamjae Jeon total_freed += to_free; 9741e9ea7e0SNamjae Jeon } 97511ccc910SNamjae Jeon ntfs_inc_free_clusters(vol, real_freed); 97611ccc910SNamjae Jeon if (likely(!is_rollback)) { 9771e9ea7e0SNamjae Jeon up_write(&vol->lcnbmp_lock); 97811ccc910SNamjae Jeon memalloc_nofs_restore(memalloc_flags); 97911ccc910SNamjae Jeon } 9801e9ea7e0SNamjae Jeon 98111ccc910SNamjae Jeon WARN_ON(count > 0); 98211ccc910SNamjae Jeon 98311ccc910SNamjae Jeon if (NVolDiscard(vol) && !is_rollback) { 98411ccc910SNamjae Jeon s64 total_discarded = 0, rl_off; 98511ccc910SNamjae Jeon u32 gran = bdev_discard_granularity(vol->sb->s_bdev); 98611ccc910SNamjae Jeon 98711ccc910SNamjae Jeon rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, ctx); 98811ccc910SNamjae Jeon if (IS_ERR(rl)) 98911ccc910SNamjae Jeon return real_freed; 99011ccc910SNamjae Jeon rl_off = start_vcn - rl->vcn; 99111ccc910SNamjae Jeon while (rl->length && total_discarded < total_freed) { 99211ccc910SNamjae Jeon s64 to_discard = rl->length - rl_off; 99311ccc910SNamjae Jeon 99411ccc910SNamjae Jeon if (to_discard + total_discarded > total_freed) 99511ccc910SNamjae Jeon to_discard = total_freed - total_discarded; 99611ccc910SNamjae Jeon if (rl->lcn >= 0) { 99711ccc910SNamjae Jeon sector_t start_sector, end_sector; 99811ccc910SNamjae Jeon int ret; 99911ccc910SNamjae Jeon 100011ccc910SNamjae Jeon start_sector = ALIGN(NTFS_CLU_TO_B(vol, rl->lcn + rl_off), 100111ccc910SNamjae Jeon gran) >> SECTOR_SHIFT; 100211ccc910SNamjae Jeon end_sector = ALIGN_DOWN(NTFS_CLU_TO_B(vol, 100311ccc910SNamjae Jeon rl->lcn + rl_off + to_discard), 100411ccc910SNamjae Jeon gran) >> SECTOR_SHIFT; 100511ccc910SNamjae Jeon if (start_sector < end_sector) { 100611ccc910SNamjae Jeon ret = blkdev_issue_discard(vol->sb->s_bdev, start_sector, 100711ccc910SNamjae Jeon end_sector - start_sector, 100811ccc910SNamjae Jeon GFP_NOFS); 100911ccc910SNamjae Jeon if (ret) 101011ccc910SNamjae Jeon break; 101111ccc910SNamjae Jeon } 101211ccc910SNamjae Jeon } 101311ccc910SNamjae Jeon 101411ccc910SNamjae Jeon total_discarded += to_discard; 101511ccc910SNamjae Jeon ++rl; 101611ccc910SNamjae Jeon rl_off = 0; 101711ccc910SNamjae Jeon } 101811ccc910SNamjae Jeon } 10191e9ea7e0SNamjae Jeon 10201e9ea7e0SNamjae Jeon /* We are done. Return the number of actually freed clusters. */ 10211e9ea7e0SNamjae Jeon ntfs_debug("Done."); 10221e9ea7e0SNamjae Jeon return real_freed; 10231e9ea7e0SNamjae Jeon err_out: 10241e9ea7e0SNamjae Jeon if (is_rollback) 10251e9ea7e0SNamjae Jeon return err; 10261e9ea7e0SNamjae Jeon /* If no real clusters were freed, no need to rollback. */ 10271e9ea7e0SNamjae Jeon if (!real_freed) { 10281e9ea7e0SNamjae Jeon up_write(&vol->lcnbmp_lock); 102911ccc910SNamjae Jeon memalloc_nofs_restore(memalloc_flags); 10301e9ea7e0SNamjae Jeon return err; 10311e9ea7e0SNamjae Jeon } 10321e9ea7e0SNamjae Jeon /* 10331e9ea7e0SNamjae Jeon * Attempt to rollback and if that succeeds just return the error code. 10341e9ea7e0SNamjae Jeon * If rollback fails, set the volume errors flag, emit an error 10351e9ea7e0SNamjae Jeon * message, and return the error code. 10361e9ea7e0SNamjae Jeon */ 10371e9ea7e0SNamjae Jeon delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, true); 10381e9ea7e0SNamjae Jeon if (delta < 0) { 103911ccc910SNamjae Jeon ntfs_error(vol->sb, 104011ccc910SNamjae Jeon "Failed to rollback (error %i). Leaving inconsistent metadata! Unmount and run chkdsk.", 104111ccc910SNamjae Jeon (int)delta); 10421e9ea7e0SNamjae Jeon NVolSetErrors(vol); 10431e9ea7e0SNamjae Jeon } 104411ccc910SNamjae Jeon ntfs_dec_free_clusters(vol, delta); 10451e9ea7e0SNamjae Jeon up_write(&vol->lcnbmp_lock); 104611ccc910SNamjae Jeon memalloc_nofs_restore(memalloc_flags); 10471e9ea7e0SNamjae Jeon ntfs_error(vol->sb, "Aborting (error %i).", err); 10481e9ea7e0SNamjae Jeon return err; 10491e9ea7e0SNamjae Jeon } 1050