11e9ea7e0SNamjae Jeon // SPDX-License-Identifier: GPL-2.0-or-later 21e9ea7e0SNamjae Jeon /* 311ccc910SNamjae Jeon * NTFS kernel bitmap handling. 41e9ea7e0SNamjae Jeon * 51e9ea7e0SNamjae Jeon * Copyright (c) 2004-2005 Anton Altaparmakov 611ccc910SNamjae Jeon * Copyright (c) 2025 LG Electronics Co., Ltd. 71e9ea7e0SNamjae Jeon */ 81e9ea7e0SNamjae Jeon 911ccc910SNamjae Jeon #include <linux/bitops.h> 1011ccc910SNamjae Jeon #include <linux/blkdev.h> 111e9ea7e0SNamjae Jeon 121e9ea7e0SNamjae Jeon #include "bitmap.h" 131e9ea7e0SNamjae Jeon #include "ntfs.h" 141e9ea7e0SNamjae Jeon 1511ccc910SNamjae Jeon int ntfs_trim_fs(struct ntfs_volume *vol, struct fstrim_range *range) 1611ccc910SNamjae Jeon { 1711ccc910SNamjae Jeon size_t buf_clusters; 1811ccc910SNamjae Jeon pgoff_t index, start_index, end_index; 1911ccc910SNamjae Jeon struct file_ra_state *ra; 2011ccc910SNamjae Jeon struct folio *folio; 2111ccc910SNamjae Jeon unsigned long *bitmap; 2211ccc910SNamjae Jeon char *kaddr; 2311ccc910SNamjae Jeon u64 end, trimmed = 0, start_buf, end_buf, end_cluster; 2411ccc910SNamjae Jeon u64 start_cluster = ntfs_bytes_to_cluster(vol, range->start); 2511ccc910SNamjae Jeon u32 dq = bdev_discard_granularity(vol->sb->s_bdev); 2611ccc910SNamjae Jeon int ret = 0; 2711ccc910SNamjae Jeon 2811ccc910SNamjae Jeon if (!dq) 2911ccc910SNamjae Jeon dq = vol->cluster_size; 3011ccc910SNamjae Jeon 3111ccc910SNamjae Jeon if (start_cluster >= vol->nr_clusters) 3211ccc910SNamjae Jeon return -EINVAL; 3311ccc910SNamjae Jeon 3411ccc910SNamjae Jeon if (range->len == (u64)-1) 3511ccc910SNamjae Jeon end_cluster = vol->nr_clusters; 3611ccc910SNamjae Jeon else { 3711ccc910SNamjae Jeon end_cluster = ntfs_bytes_to_cluster(vol, 3811ccc910SNamjae Jeon (range->start + range->len + vol->cluster_size - 1)); 3911ccc910SNamjae Jeon if (end_cluster > vol->nr_clusters) 4011ccc910SNamjae Jeon end_cluster = vol->nr_clusters; 4111ccc910SNamjae Jeon } 4211ccc910SNamjae Jeon 4311ccc910SNamjae Jeon ra = kzalloc(sizeof(*ra), GFP_NOFS); 4411ccc910SNamjae Jeon if (!ra) 4511ccc910SNamjae Jeon return -ENOMEM; 4611ccc910SNamjae Jeon 4711ccc910SNamjae Jeon buf_clusters = PAGE_SIZE * 8; 4811ccc910SNamjae Jeon start_index = start_cluster >> 15; 4911ccc910SNamjae Jeon end_index = (end_cluster + buf_clusters - 1) >> 15; 5011ccc910SNamjae Jeon 5111ccc910SNamjae Jeon for (index = start_index; index < end_index; index++) { 5211ccc910SNamjae Jeon folio = ntfs_get_locked_folio(vol->lcnbmp_ino->i_mapping, 5311ccc910SNamjae Jeon index, end_index, ra); 5411ccc910SNamjae Jeon if (IS_ERR(folio)) { 5511ccc910SNamjae Jeon ret = PTR_ERR(folio); 5611ccc910SNamjae Jeon goto out_free; 5711ccc910SNamjae Jeon } 5811ccc910SNamjae Jeon 5911ccc910SNamjae Jeon kaddr = kmap_local_folio(folio, 0); 6011ccc910SNamjae Jeon bitmap = (unsigned long *)kaddr; 6111ccc910SNamjae Jeon 6211ccc910SNamjae Jeon start_buf = max_t(u64, index * buf_clusters, start_cluster); 6311ccc910SNamjae Jeon end_buf = min_t(u64, (index + 1) * buf_clusters, end_cluster); 6411ccc910SNamjae Jeon 6511ccc910SNamjae Jeon end = start_buf; 6611ccc910SNamjae Jeon while (end < end_buf) { 6711ccc910SNamjae Jeon u64 aligned_start, aligned_count; 6811ccc910SNamjae Jeon u64 start = find_next_zero_bit(bitmap, end_buf - start_buf, 6911ccc910SNamjae Jeon end - start_buf) + start_buf; 7011ccc910SNamjae Jeon if (start >= end_buf) 7111ccc910SNamjae Jeon break; 7211ccc910SNamjae Jeon 7311ccc910SNamjae Jeon end = find_next_bit(bitmap, end_buf - start_buf, 7411ccc910SNamjae Jeon start - start_buf) + start_buf; 7511ccc910SNamjae Jeon 7611ccc910SNamjae Jeon aligned_start = ALIGN(ntfs_cluster_to_bytes(vol, start), dq); 7711ccc910SNamjae Jeon aligned_count = 7811ccc910SNamjae Jeon ALIGN_DOWN(ntfs_cluster_to_bytes(vol, end - start), dq); 7911ccc910SNamjae Jeon if (aligned_count >= range->minlen) { 8011ccc910SNamjae Jeon ret = blkdev_issue_discard(vol->sb->s_bdev, aligned_start >> 9, 8111ccc910SNamjae Jeon aligned_count >> 9, GFP_NOFS); 8211ccc910SNamjae Jeon if (ret) 8311ccc910SNamjae Jeon goto out_unmap; 8411ccc910SNamjae Jeon trimmed += aligned_count; 8511ccc910SNamjae Jeon } 8611ccc910SNamjae Jeon } 8711ccc910SNamjae Jeon 8811ccc910SNamjae Jeon out_unmap: 8911ccc910SNamjae Jeon kunmap_local(kaddr); 9011ccc910SNamjae Jeon folio_unlock(folio); 9111ccc910SNamjae Jeon folio_put(folio); 9211ccc910SNamjae Jeon 9311ccc910SNamjae Jeon if (ret) 9411ccc910SNamjae Jeon goto out_free; 9511ccc910SNamjae Jeon } 9611ccc910SNamjae Jeon 9711ccc910SNamjae Jeon range->len = trimmed; 9811ccc910SNamjae Jeon 9911ccc910SNamjae Jeon out_free: 10011ccc910SNamjae Jeon kfree(ra); 10111ccc910SNamjae Jeon return ret; 10211ccc910SNamjae Jeon } 10311ccc910SNamjae Jeon 10411ccc910SNamjae Jeon /* 1051e9ea7e0SNamjae Jeon * __ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value 1061e9ea7e0SNamjae Jeon * @vi: vfs inode describing the bitmap 1071e9ea7e0SNamjae Jeon * @start_bit: first bit to set 1081e9ea7e0SNamjae Jeon * @count: number of bits to set 1091e9ea7e0SNamjae Jeon * @value: value to set the bits to (i.e. 0 or 1) 1101e9ea7e0SNamjae Jeon * @is_rollback: if 'true' this is a rollback operation 1111e9ea7e0SNamjae Jeon * 1121e9ea7e0SNamjae Jeon * Set @count bits starting at bit @start_bit in the bitmap described by the 1131e9ea7e0SNamjae Jeon * vfs inode @vi to @value, where @value is either 0 or 1. 1141e9ea7e0SNamjae Jeon * 1151e9ea7e0SNamjae Jeon * @is_rollback should always be 'false', it is for internal use to rollback 1161e9ea7e0SNamjae Jeon * errors. You probably want to use ntfs_bitmap_set_bits_in_run() instead. 1171e9ea7e0SNamjae Jeon * 1181e9ea7e0SNamjae Jeon * Return 0 on success and -errno on error. 1191e9ea7e0SNamjae Jeon */ 1201e9ea7e0SNamjae Jeon int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit, 1211e9ea7e0SNamjae Jeon const s64 count, const u8 value, const bool is_rollback) 1221e9ea7e0SNamjae Jeon { 1231e9ea7e0SNamjae Jeon s64 cnt = count; 1241e9ea7e0SNamjae Jeon pgoff_t index, end_index; 1251e9ea7e0SNamjae Jeon struct address_space *mapping; 12611ccc910SNamjae Jeon struct folio *folio; 1271e9ea7e0SNamjae Jeon u8 *kaddr; 1281e9ea7e0SNamjae Jeon int pos, len; 1291e9ea7e0SNamjae Jeon u8 bit; 13011ccc910SNamjae Jeon struct ntfs_inode *ni = NTFS_I(vi); 13111ccc910SNamjae Jeon struct ntfs_volume *vol = ni->vol; 1321e9ea7e0SNamjae Jeon 133*e7d82353SNamjae Jeon ntfs_debug("Entering for i_ino 0x%llx, start_bit 0x%llx, count 0x%llx, value %u.%s", 134*e7d82353SNamjae Jeon ni->mft_no, (unsigned long long)start_bit, 1351e9ea7e0SNamjae Jeon (unsigned long long)cnt, (unsigned int)value, 1361e9ea7e0SNamjae Jeon is_rollback ? " (rollback)" : ""); 13711ccc910SNamjae Jeon 13811ccc910SNamjae Jeon if (start_bit < 0 || cnt < 0 || value > 1) 13911ccc910SNamjae Jeon return -EINVAL; 14011ccc910SNamjae Jeon 1411e9ea7e0SNamjae Jeon /* 1421e9ea7e0SNamjae Jeon * Calculate the indices for the pages containing the first and last 1431e9ea7e0SNamjae Jeon * bits, i.e. @start_bit and @start_bit + @cnt - 1, respectively. 1441e9ea7e0SNamjae Jeon */ 1451e9ea7e0SNamjae Jeon index = start_bit >> (3 + PAGE_SHIFT); 1461e9ea7e0SNamjae Jeon end_index = (start_bit + cnt - 1) >> (3 + PAGE_SHIFT); 1471e9ea7e0SNamjae Jeon 1481e9ea7e0SNamjae Jeon /* Get the page containing the first bit (@start_bit). */ 1491e9ea7e0SNamjae Jeon mapping = vi->i_mapping; 15011ccc910SNamjae Jeon folio = read_mapping_folio(mapping, index, NULL); 15111ccc910SNamjae Jeon if (IS_ERR(folio)) { 1521e9ea7e0SNamjae Jeon if (!is_rollback) 15311ccc910SNamjae Jeon ntfs_error(vi->i_sb, 15411ccc910SNamjae Jeon "Failed to map first page (error %li), aborting.", 15511ccc910SNamjae Jeon PTR_ERR(folio)); 15611ccc910SNamjae Jeon return PTR_ERR(folio); 1571e9ea7e0SNamjae Jeon } 15811ccc910SNamjae Jeon 15911ccc910SNamjae Jeon folio_lock(folio); 16011ccc910SNamjae Jeon kaddr = kmap_local_folio(folio, 0); 1611e9ea7e0SNamjae Jeon 1621e9ea7e0SNamjae Jeon /* Set @pos to the position of the byte containing @start_bit. */ 1631e9ea7e0SNamjae Jeon pos = (start_bit >> 3) & ~PAGE_MASK; 1641e9ea7e0SNamjae Jeon 1651e9ea7e0SNamjae Jeon /* Calculate the position of @start_bit in the first byte. */ 1661e9ea7e0SNamjae Jeon bit = start_bit & 7; 1671e9ea7e0SNamjae Jeon 1681e9ea7e0SNamjae Jeon /* If the first byte is partial, modify the appropriate bits in it. */ 1691e9ea7e0SNamjae Jeon if (bit) { 1701e9ea7e0SNamjae Jeon u8 *byte = kaddr + pos; 17111ccc910SNamjae Jeon 17211ccc910SNamjae Jeon if (ni->mft_no == FILE_Bitmap) 17311ccc910SNamjae Jeon ntfs_set_lcn_empty_bits(vol, index, value, min_t(s64, 8 - bit, cnt)); 1741e9ea7e0SNamjae Jeon while ((bit & 7) && cnt) { 1751e9ea7e0SNamjae Jeon cnt--; 1761e9ea7e0SNamjae Jeon if (value) 1771e9ea7e0SNamjae Jeon *byte |= 1 << bit++; 1781e9ea7e0SNamjae Jeon else 1791e9ea7e0SNamjae Jeon *byte &= ~(1 << bit++); 1801e9ea7e0SNamjae Jeon } 1811e9ea7e0SNamjae Jeon /* If we are done, unmap the page and return success. */ 1821e9ea7e0SNamjae Jeon if (!cnt) 1831e9ea7e0SNamjae Jeon goto done; 1841e9ea7e0SNamjae Jeon 1851e9ea7e0SNamjae Jeon /* Update @pos to the new position. */ 1861e9ea7e0SNamjae Jeon pos++; 1871e9ea7e0SNamjae Jeon } 1881e9ea7e0SNamjae Jeon /* 1891e9ea7e0SNamjae Jeon * Depending on @value, modify all remaining whole bytes in the page up 1901e9ea7e0SNamjae Jeon * to @cnt. 1911e9ea7e0SNamjae Jeon */ 1921e9ea7e0SNamjae Jeon len = min_t(s64, cnt >> 3, PAGE_SIZE - pos); 1931e9ea7e0SNamjae Jeon memset(kaddr + pos, value ? 0xff : 0, len); 1941e9ea7e0SNamjae Jeon cnt -= len << 3; 19511ccc910SNamjae Jeon if (ni->mft_no == FILE_Bitmap) 19611ccc910SNamjae Jeon ntfs_set_lcn_empty_bits(vol, index, value, len << 3); 1971e9ea7e0SNamjae Jeon 1981e9ea7e0SNamjae Jeon /* Update @len to point to the first not-done byte in the page. */ 1991e9ea7e0SNamjae Jeon if (cnt < 8) 2001e9ea7e0SNamjae Jeon len += pos; 2011e9ea7e0SNamjae Jeon 2021e9ea7e0SNamjae Jeon /* If we are not in the last page, deal with all subsequent pages. */ 2031e9ea7e0SNamjae Jeon while (index < end_index) { 20411ccc910SNamjae Jeon if (cnt <= 0) 2051e9ea7e0SNamjae Jeon goto rollback; 20611ccc910SNamjae Jeon 20711ccc910SNamjae Jeon /* Update @index and get the next folio. */ 20811ccc910SNamjae Jeon folio_mark_dirty(folio); 20911ccc910SNamjae Jeon folio_unlock(folio); 21011ccc910SNamjae Jeon kunmap_local(kaddr); 21111ccc910SNamjae Jeon folio_put(folio); 21211ccc910SNamjae Jeon folio = read_mapping_folio(mapping, ++index, NULL); 21311ccc910SNamjae Jeon if (IS_ERR(folio)) { 21411ccc910SNamjae Jeon ntfs_error(vi->i_sb, 21511ccc910SNamjae Jeon "Failed to map subsequent page (error %li), aborting.", 21611ccc910SNamjae Jeon PTR_ERR(folio)); 21711ccc910SNamjae Jeon goto rollback; 21811ccc910SNamjae Jeon } 21911ccc910SNamjae Jeon 22011ccc910SNamjae Jeon folio_lock(folio); 22111ccc910SNamjae Jeon kaddr = kmap_local_folio(folio, 0); 2221e9ea7e0SNamjae Jeon /* 2231e9ea7e0SNamjae Jeon * Depending on @value, modify all remaining whole bytes in the 2241e9ea7e0SNamjae Jeon * page up to @cnt. 2251e9ea7e0SNamjae Jeon */ 2261e9ea7e0SNamjae Jeon len = min_t(s64, cnt >> 3, PAGE_SIZE); 2271e9ea7e0SNamjae Jeon memset(kaddr, value ? 0xff : 0, len); 2281e9ea7e0SNamjae Jeon cnt -= len << 3; 22911ccc910SNamjae Jeon if (ni->mft_no == FILE_Bitmap) 23011ccc910SNamjae Jeon ntfs_set_lcn_empty_bits(vol, index, value, len << 3); 2311e9ea7e0SNamjae Jeon } 2321e9ea7e0SNamjae Jeon /* 2331e9ea7e0SNamjae Jeon * The currently mapped page is the last one. If the last byte is 2341e9ea7e0SNamjae Jeon * partial, modify the appropriate bits in it. Note, @len is the 2351e9ea7e0SNamjae Jeon * position of the last byte inside the page. 2361e9ea7e0SNamjae Jeon */ 2371e9ea7e0SNamjae Jeon if (cnt) { 2381e9ea7e0SNamjae Jeon u8 *byte; 2391e9ea7e0SNamjae Jeon 24011ccc910SNamjae Jeon WARN_ON(cnt > 7); 2411e9ea7e0SNamjae Jeon 2421e9ea7e0SNamjae Jeon bit = cnt; 2431e9ea7e0SNamjae Jeon byte = kaddr + len; 24411ccc910SNamjae Jeon if (ni->mft_no == FILE_Bitmap) 24511ccc910SNamjae Jeon ntfs_set_lcn_empty_bits(vol, index, value, bit); 2461e9ea7e0SNamjae Jeon while (bit--) { 2471e9ea7e0SNamjae Jeon if (value) 2481e9ea7e0SNamjae Jeon *byte |= 1 << bit; 2491e9ea7e0SNamjae Jeon else 2501e9ea7e0SNamjae Jeon *byte &= ~(1 << bit); 2511e9ea7e0SNamjae Jeon } 2521e9ea7e0SNamjae Jeon } 2531e9ea7e0SNamjae Jeon done: 25411ccc910SNamjae Jeon /* We are done. Unmap the folio and return success. */ 25511ccc910SNamjae Jeon folio_mark_dirty(folio); 25611ccc910SNamjae Jeon folio_unlock(folio); 25711ccc910SNamjae Jeon kunmap_local(kaddr); 25811ccc910SNamjae Jeon folio_put(folio); 2591e9ea7e0SNamjae Jeon ntfs_debug("Done."); 2601e9ea7e0SNamjae Jeon return 0; 2611e9ea7e0SNamjae Jeon rollback: 2621e9ea7e0SNamjae Jeon /* 2631e9ea7e0SNamjae Jeon * Current state: 2641e9ea7e0SNamjae Jeon * - no pages are mapped 2651e9ea7e0SNamjae Jeon * - @count - @cnt is the number of bits that have been modified 2661e9ea7e0SNamjae Jeon */ 2671e9ea7e0SNamjae Jeon if (is_rollback) 26811ccc910SNamjae Jeon return PTR_ERR(folio); 2691e9ea7e0SNamjae Jeon if (count != cnt) 2701e9ea7e0SNamjae Jeon pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt, 2711e9ea7e0SNamjae Jeon value ? 0 : 1, true); 2721e9ea7e0SNamjae Jeon else 2731e9ea7e0SNamjae Jeon pos = 0; 2741e9ea7e0SNamjae Jeon if (!pos) { 2751e9ea7e0SNamjae Jeon /* Rollback was successful. */ 27611ccc910SNamjae Jeon ntfs_error(vi->i_sb, 27711ccc910SNamjae Jeon "Failed to map subsequent page (error %li), aborting.", 27811ccc910SNamjae Jeon PTR_ERR(folio)); 2791e9ea7e0SNamjae Jeon } else { 2801e9ea7e0SNamjae Jeon /* Rollback failed. */ 28111ccc910SNamjae Jeon ntfs_error(vi->i_sb, 28211ccc910SNamjae Jeon "Failed to map subsequent page (error %li) and rollback failed (error %i). Aborting and leaving inconsistent metadata. Unmount and run chkdsk.", 28311ccc910SNamjae Jeon PTR_ERR(folio), pos); 2841e9ea7e0SNamjae Jeon NVolSetErrors(NTFS_SB(vi->i_sb)); 2851e9ea7e0SNamjae Jeon } 28611ccc910SNamjae Jeon return PTR_ERR(folio); 2871e9ea7e0SNamjae Jeon } 288