xref: /openbmc/linux/fs/exfat/balloc.c (revision 8ebc80a25f9d9bf7a8e368b266d5b740c485c362)
11e49a94cSNamjae Jeon // SPDX-License-Identifier: GPL-2.0-or-later
21e49a94cSNamjae Jeon /*
31e49a94cSNamjae Jeon  *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
41e49a94cSNamjae Jeon  */
51e49a94cSNamjae Jeon 
61e49a94cSNamjae Jeon #include <linux/blkdev.h>
71e49a94cSNamjae Jeon #include <linux/slab.h>
81e49a94cSNamjae Jeon #include <linux/buffer_head.h>
91e49a94cSNamjae Jeon 
101e49a94cSNamjae Jeon #include "exfat_raw.h"
111e49a94cSNamjae Jeon #include "exfat_fs.h"
121e49a94cSNamjae Jeon 
131e49a94cSNamjae Jeon static const unsigned char free_bit[] = {
141e49a94cSNamjae Jeon 	0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*  0 ~  19*/
151e49a94cSNamjae Jeon 	0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~  39*/
161e49a94cSNamjae Jeon 	0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~  59*/
171e49a94cSNamjae Jeon 	0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~  79*/
181e49a94cSNamjae Jeon 	0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~  99*/
191e49a94cSNamjae Jeon 	0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/
201e49a94cSNamjae Jeon 	0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/
211e49a94cSNamjae Jeon 	0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/
221e49a94cSNamjae Jeon 	0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/
231e49a94cSNamjae Jeon 	0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/
241e49a94cSNamjae Jeon 	0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/
251e49a94cSNamjae Jeon 	0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/
261e49a94cSNamjae Jeon 	0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0                /*240 ~ 254*/
271e49a94cSNamjae Jeon };
281e49a94cSNamjae Jeon 
291e49a94cSNamjae Jeon static const unsigned char used_bit[] = {
301e49a94cSNamjae Jeon 	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/*  0 ~  19*/
311e49a94cSNamjae Jeon 	2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~  39*/
321e49a94cSNamjae Jeon 	2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~  59*/
331e49a94cSNamjae Jeon 	4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~  79*/
341e49a94cSNamjae Jeon 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~  99*/
351e49a94cSNamjae Jeon 	3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/
361e49a94cSNamjae Jeon 	4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/
371e49a94cSNamjae Jeon 	3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/
381e49a94cSNamjae Jeon 	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/
391e49a94cSNamjae Jeon 	4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/
401e49a94cSNamjae Jeon 	3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/
411e49a94cSNamjae Jeon 	5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/
421e49a94cSNamjae Jeon 	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8             /*240 ~ 255*/
431e49a94cSNamjae Jeon };
441e49a94cSNamjae Jeon 
451e49a94cSNamjae Jeon /*
461e49a94cSNamjae Jeon  *  Allocation Bitmap Management Functions
471e49a94cSNamjae Jeon  */
exfat_allocate_bitmap(struct super_block * sb,struct exfat_dentry * ep)481e49a94cSNamjae Jeon static int exfat_allocate_bitmap(struct super_block *sb,
491e49a94cSNamjae Jeon 		struct exfat_dentry *ep)
501e49a94cSNamjae Jeon {
511e49a94cSNamjae Jeon 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
521e49a94cSNamjae Jeon 	long long map_size;
531e49a94cSNamjae Jeon 	unsigned int i, need_map_size;
541e49a94cSNamjae Jeon 	sector_t sector;
551e49a94cSNamjae Jeon 
561e49a94cSNamjae Jeon 	sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu);
571e49a94cSNamjae Jeon 	map_size = le64_to_cpu(ep->dentry.bitmap.size);
581e49a94cSNamjae Jeon 	need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE)
591e49a94cSNamjae Jeon 		+ 1;
601e49a94cSNamjae Jeon 	if (need_map_size != map_size) {
61d1727d55SJoe Perches 		exfat_err(sb, "bogus allocation bitmap size(need : %u, cur : %lld)",
621e49a94cSNamjae Jeon 			  need_map_size, map_size);
631e49a94cSNamjae Jeon 		/*
641e49a94cSNamjae Jeon 		 * Only allowed when bogus allocation
651e49a94cSNamjae Jeon 		 * bitmap size is large
661e49a94cSNamjae Jeon 		 */
671e49a94cSNamjae Jeon 		if (need_map_size > map_size)
681e49a94cSNamjae Jeon 			return -EIO;
691e49a94cSNamjae Jeon 	}
701e49a94cSNamjae Jeon 	sbi->map_sectors = ((need_map_size - 1) >>
711e49a94cSNamjae Jeon 			(sb->s_blocksize_bits)) + 1;
72daf60d6cSgaoming 	sbi->vol_amap = kvmalloc_array(sbi->map_sectors,
731e49a94cSNamjae Jeon 				sizeof(struct buffer_head *), GFP_KERNEL);
741e49a94cSNamjae Jeon 	if (!sbi->vol_amap)
751e49a94cSNamjae Jeon 		return -ENOMEM;
761e49a94cSNamjae Jeon 
771e49a94cSNamjae Jeon 	sector = exfat_cluster_to_sector(sbi, sbi->map_clu);
781e49a94cSNamjae Jeon 	for (i = 0; i < sbi->map_sectors; i++) {
791e49a94cSNamjae Jeon 		sbi->vol_amap[i] = sb_bread(sb, sector + i);
801e49a94cSNamjae Jeon 		if (!sbi->vol_amap[i]) {
811e49a94cSNamjae Jeon 			/* release all buffers and free vol_amap */
821e49a94cSNamjae Jeon 			int j = 0;
831e49a94cSNamjae Jeon 
841e49a94cSNamjae Jeon 			while (j < i)
851e49a94cSNamjae Jeon 				brelse(sbi->vol_amap[j++]);
861e49a94cSNamjae Jeon 
87daf60d6cSgaoming 			kvfree(sbi->vol_amap);
881e49a94cSNamjae Jeon 			sbi->vol_amap = NULL;
891e49a94cSNamjae Jeon 			return -EIO;
901e49a94cSNamjae Jeon 		}
911e49a94cSNamjae Jeon 	}
921e49a94cSNamjae Jeon 
931e49a94cSNamjae Jeon 	return 0;
941e49a94cSNamjae Jeon }
951e49a94cSNamjae Jeon 
exfat_load_bitmap(struct super_block * sb)961e49a94cSNamjae Jeon int exfat_load_bitmap(struct super_block *sb)
971e49a94cSNamjae Jeon {
981e49a94cSNamjae Jeon 	unsigned int i, type;
991e49a94cSNamjae Jeon 	struct exfat_chain clu;
1001e49a94cSNamjae Jeon 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
1011e49a94cSNamjae Jeon 
1021e49a94cSNamjae Jeon 	exfat_chain_set(&clu, sbi->root_dir, 0, ALLOC_FAT_CHAIN);
1031e49a94cSNamjae Jeon 	while (clu.dir != EXFAT_EOF_CLUSTER) {
1041e49a94cSNamjae Jeon 		for (i = 0; i < sbi->dentries_per_clu; i++) {
1051e49a94cSNamjae Jeon 			struct exfat_dentry *ep;
1061e49a94cSNamjae Jeon 			struct buffer_head *bh;
1071e49a94cSNamjae Jeon 
108c71510b3SYuezhang.Mo 			ep = exfat_get_dentry(sb, &clu, i, &bh);
1091e49a94cSNamjae Jeon 			if (!ep)
1101e49a94cSNamjae Jeon 				return -EIO;
1111e49a94cSNamjae Jeon 
1121e49a94cSNamjae Jeon 			type = exfat_get_entry_type(ep);
113bf0b3b35SYuezhang Mo 			if (type == TYPE_BITMAP &&
114bf0b3b35SYuezhang Mo 			    ep->dentry.bitmap.flags == 0x0) {
1151e49a94cSNamjae Jeon 				int err;
1161e49a94cSNamjae Jeon 
1171e49a94cSNamjae Jeon 				err = exfat_allocate_bitmap(sb, ep);
1181e49a94cSNamjae Jeon 				brelse(bh);
1191e49a94cSNamjae Jeon 				return err;
1201e49a94cSNamjae Jeon 			}
1211e49a94cSNamjae Jeon 			brelse(bh);
122bf0b3b35SYuezhang Mo 
123bf0b3b35SYuezhang Mo 			if (type == TYPE_UNUSED)
124bf0b3b35SYuezhang Mo 				return -EINVAL;
1251e49a94cSNamjae Jeon 		}
1261e49a94cSNamjae Jeon 
1271e49a94cSNamjae Jeon 		if (exfat_get_next_cluster(sb, &clu.dir))
1281e49a94cSNamjae Jeon 			return -EIO;
1291e49a94cSNamjae Jeon 	}
1301e49a94cSNamjae Jeon 
1311e49a94cSNamjae Jeon 	return -EINVAL;
1321e49a94cSNamjae Jeon }
1331e49a94cSNamjae Jeon 
exfat_free_bitmap(struct exfat_sb_info * sbi)1341e49a94cSNamjae Jeon void exfat_free_bitmap(struct exfat_sb_info *sbi)
1351e49a94cSNamjae Jeon {
1361e49a94cSNamjae Jeon 	int i;
1371e49a94cSNamjae Jeon 
1381e49a94cSNamjae Jeon 	for (i = 0; i < sbi->map_sectors; i++)
1391e49a94cSNamjae Jeon 		__brelse(sbi->vol_amap[i]);
1401e49a94cSNamjae Jeon 
141daf60d6cSgaoming 	kvfree(sbi->vol_amap);
1421e49a94cSNamjae Jeon }
1431e49a94cSNamjae Jeon 
exfat_set_bitmap(struct inode * inode,unsigned int clu,bool sync)14423befe49SHyeongseok Kim int exfat_set_bitmap(struct inode *inode, unsigned int clu, bool sync)
1451e49a94cSNamjae Jeon {
1461e49a94cSNamjae Jeon 	int i, b;
1471e49a94cSNamjae Jeon 	unsigned int ent_idx;
1481e49a94cSNamjae Jeon 	struct super_block *sb = inode->i_sb;
1491e49a94cSNamjae Jeon 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
1501e49a94cSNamjae Jeon 
15164ba4b15STadeusz Struk 	if (!is_valid_cluster(sbi, clu))
15264ba4b15STadeusz Struk 		return -EINVAL;
15364ba4b15STadeusz Struk 
1541e49a94cSNamjae Jeon 	ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
1551e49a94cSNamjae Jeon 	i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
1561e49a94cSNamjae Jeon 	b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
1571e49a94cSNamjae Jeon 
1581e49a94cSNamjae Jeon 	set_bit_le(b, sbi->vol_amap[i]->b_data);
15923befe49SHyeongseok Kim 	exfat_update_bh(sbi->vol_amap[i], sync);
1601e49a94cSNamjae Jeon 	return 0;
1611e49a94cSNamjae Jeon }
1621e49a94cSNamjae Jeon 
exfat_clear_bitmap(struct inode * inode,unsigned int clu,bool sync)163*747de766SNamjae Jeon int exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync)
1641e49a94cSNamjae Jeon {
1651e49a94cSNamjae Jeon 	int i, b;
1661e49a94cSNamjae Jeon 	unsigned int ent_idx;
1671e49a94cSNamjae Jeon 	struct super_block *sb = inode->i_sb;
1681e49a94cSNamjae Jeon 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
1691e49a94cSNamjae Jeon 	struct exfat_mount_options *opts = &sbi->options;
1701e49a94cSNamjae Jeon 
17164ba4b15STadeusz Struk 	if (!is_valid_cluster(sbi, clu))
172*747de766SNamjae Jeon 		return -EIO;
17364ba4b15STadeusz Struk 
1741e49a94cSNamjae Jeon 	ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
1751e49a94cSNamjae Jeon 	i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
1761e49a94cSNamjae Jeon 	b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
1771e49a94cSNamjae Jeon 
178*747de766SNamjae Jeon 	if (!test_bit_le(b, sbi->vol_amap[i]->b_data))
179*747de766SNamjae Jeon 		return -EIO;
180*747de766SNamjae Jeon 
1811e49a94cSNamjae Jeon 	clear_bit_le(b, sbi->vol_amap[i]->b_data);
182*747de766SNamjae Jeon 
183f728760aSHyeongseok Kim 	exfat_update_bh(sbi->vol_amap[i], sync);
1841e49a94cSNamjae Jeon 
1851e49a94cSNamjae Jeon 	if (opts->discard) {
1861e49a94cSNamjae Jeon 		int ret_discard;
1871e49a94cSNamjae Jeon 
1881e49a94cSNamjae Jeon 		ret_discard = sb_issue_discard(sb,
18977edfc6eSHyeongseok Kim 			exfat_cluster_to_sector(sbi, clu),
1901e49a94cSNamjae Jeon 			(1 << sbi->sect_per_clus_bits), GFP_NOFS, 0);
1911e49a94cSNamjae Jeon 
1921e49a94cSNamjae Jeon 		if (ret_discard == -EOPNOTSUPP) {
193d1727d55SJoe Perches 			exfat_err(sb, "discard not supported by device, disabling");
1941e49a94cSNamjae Jeon 			opts->discard = 0;
1951e49a94cSNamjae Jeon 		}
1961e49a94cSNamjae Jeon 	}
197*747de766SNamjae Jeon 
198*747de766SNamjae Jeon 	return 0;
1991e49a94cSNamjae Jeon }
2001e49a94cSNamjae Jeon 
2011e49a94cSNamjae Jeon /*
2021e49a94cSNamjae Jeon  * If the value of "clu" is 0, it means cluster 2 which is the first cluster of
2031e49a94cSNamjae Jeon  * the cluster heap.
2041e49a94cSNamjae Jeon  */
exfat_find_free_bitmap(struct super_block * sb,unsigned int clu)2051e49a94cSNamjae Jeon unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu)
2061e49a94cSNamjae Jeon {
2071e49a94cSNamjae Jeon 	unsigned int i, map_i, map_b, ent_idx;
2081e49a94cSNamjae Jeon 	unsigned int clu_base, clu_free;
2091e49a94cSNamjae Jeon 	unsigned char k, clu_mask;
2101e49a94cSNamjae Jeon 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
2111e49a94cSNamjae Jeon 
2121e49a94cSNamjae Jeon 	WARN_ON(clu < EXFAT_FIRST_CLUSTER);
2131e49a94cSNamjae Jeon 	ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
2141e49a94cSNamjae Jeon 	clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx & ~(BITS_PER_BYTE_MASK));
2151e49a94cSNamjae Jeon 	clu_mask = IGNORED_BITS_REMAINED(clu, clu_base);
2161e49a94cSNamjae Jeon 
2171e49a94cSNamjae Jeon 	map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
2181e49a94cSNamjae Jeon 	map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx);
2191e49a94cSNamjae Jeon 
2201e49a94cSNamjae Jeon 	for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters;
2211e49a94cSNamjae Jeon 	     i += BITS_PER_BYTE) {
2221e49a94cSNamjae Jeon 		k = *(sbi->vol_amap[map_i]->b_data + map_b);
2231e49a94cSNamjae Jeon 		if (clu_mask > 0) {
2241e49a94cSNamjae Jeon 			k |= clu_mask;
2251e49a94cSNamjae Jeon 			clu_mask = 0;
2261e49a94cSNamjae Jeon 		}
2271e49a94cSNamjae Jeon 		if (k < 0xFF) {
2281e49a94cSNamjae Jeon 			clu_free = clu_base + free_bit[k];
2291e49a94cSNamjae Jeon 			if (clu_free < sbi->num_clusters)
2301e49a94cSNamjae Jeon 				return clu_free;
2311e49a94cSNamjae Jeon 		}
2321e49a94cSNamjae Jeon 		clu_base += BITS_PER_BYTE;
2331e49a94cSNamjae Jeon 
2341e49a94cSNamjae Jeon 		if (++map_b >= sb->s_blocksize ||
2351e49a94cSNamjae Jeon 		    clu_base >= sbi->num_clusters) {
2361e49a94cSNamjae Jeon 			if (++map_i >= sbi->map_sectors) {
2371e49a94cSNamjae Jeon 				clu_base = EXFAT_FIRST_CLUSTER;
2381e49a94cSNamjae Jeon 				map_i = 0;
2391e49a94cSNamjae Jeon 			}
2401e49a94cSNamjae Jeon 			map_b = 0;
2411e49a94cSNamjae Jeon 		}
2421e49a94cSNamjae Jeon 	}
2431e49a94cSNamjae Jeon 
2441e49a94cSNamjae Jeon 	return EXFAT_EOF_CLUSTER;
2451e49a94cSNamjae Jeon }
2461e49a94cSNamjae Jeon 
exfat_count_used_clusters(struct super_block * sb,unsigned int * ret_count)2471e49a94cSNamjae Jeon int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count)
2481e49a94cSNamjae Jeon {
2491e49a94cSNamjae Jeon 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
2501e49a94cSNamjae Jeon 	unsigned int count = 0;
2511e49a94cSNamjae Jeon 	unsigned int i, map_i = 0, map_b = 0;
2521e49a94cSNamjae Jeon 	unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi);
2531e49a94cSNamjae Jeon 	unsigned int last_mask = total_clus & BITS_PER_BYTE_MASK;
2541e49a94cSNamjae Jeon 	unsigned char clu_bits;
2551e49a94cSNamjae Jeon 	const unsigned char last_bit_mask[] = {0, 0b00000001, 0b00000011,
2561e49a94cSNamjae Jeon 		0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111};
2571e49a94cSNamjae Jeon 
2581e49a94cSNamjae Jeon 	total_clus &= ~last_mask;
2591e49a94cSNamjae Jeon 	for (i = 0; i < total_clus; i += BITS_PER_BYTE) {
2601e49a94cSNamjae Jeon 		clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
2611e49a94cSNamjae Jeon 		count += used_bit[clu_bits];
2621e49a94cSNamjae Jeon 		if (++map_b >= (unsigned int)sb->s_blocksize) {
2631e49a94cSNamjae Jeon 			map_i++;
2641e49a94cSNamjae Jeon 			map_b = 0;
2651e49a94cSNamjae Jeon 		}
2661e49a94cSNamjae Jeon 	}
2671e49a94cSNamjae Jeon 
2681e49a94cSNamjae Jeon 	if (last_mask) {
2691e49a94cSNamjae Jeon 		clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
2701e49a94cSNamjae Jeon 		clu_bits &= last_bit_mask[last_mask];
2711e49a94cSNamjae Jeon 		count += used_bit[clu_bits];
2721e49a94cSNamjae Jeon 	}
2731e49a94cSNamjae Jeon 
2741e49a94cSNamjae Jeon 	*ret_count = count;
2751e49a94cSNamjae Jeon 	return 0;
2761e49a94cSNamjae Jeon }
277654762dfSHyeongseok Kim 
exfat_trim_fs(struct inode * inode,struct fstrim_range * range)278654762dfSHyeongseok Kim int exfat_trim_fs(struct inode *inode, struct fstrim_range *range)
279654762dfSHyeongseok Kim {
280654762dfSHyeongseok Kim 	unsigned int trim_begin, trim_end, count, next_free_clu;
281654762dfSHyeongseok Kim 	u64 clu_start, clu_end, trim_minlen, trimmed_total = 0;
282654762dfSHyeongseok Kim 	struct super_block *sb = inode->i_sb;
283654762dfSHyeongseok Kim 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
284654762dfSHyeongseok Kim 	int err = 0;
285654762dfSHyeongseok Kim 
286654762dfSHyeongseok Kim 	clu_start = max_t(u64, range->start >> sbi->cluster_size_bits,
287654762dfSHyeongseok Kim 				EXFAT_FIRST_CLUSTER);
288654762dfSHyeongseok Kim 	clu_end = clu_start + (range->len >> sbi->cluster_size_bits) - 1;
289654762dfSHyeongseok Kim 	trim_minlen = range->minlen >> sbi->cluster_size_bits;
290654762dfSHyeongseok Kim 
291654762dfSHyeongseok Kim 	if (clu_start >= sbi->num_clusters || range->len < sbi->cluster_size)
292654762dfSHyeongseok Kim 		return -EINVAL;
293654762dfSHyeongseok Kim 
294654762dfSHyeongseok Kim 	if (clu_end >= sbi->num_clusters)
295654762dfSHyeongseok Kim 		clu_end = sbi->num_clusters - 1;
296654762dfSHyeongseok Kim 
297654762dfSHyeongseok Kim 	mutex_lock(&sbi->bitmap_lock);
298654762dfSHyeongseok Kim 
299654762dfSHyeongseok Kim 	trim_begin = trim_end = exfat_find_free_bitmap(sb, clu_start);
300654762dfSHyeongseok Kim 	if (trim_begin == EXFAT_EOF_CLUSTER)
301654762dfSHyeongseok Kim 		goto unlock;
302654762dfSHyeongseok Kim 
303654762dfSHyeongseok Kim 	next_free_clu = exfat_find_free_bitmap(sb, trim_end + 1);
304654762dfSHyeongseok Kim 	if (next_free_clu == EXFAT_EOF_CLUSTER)
305654762dfSHyeongseok Kim 		goto unlock;
306654762dfSHyeongseok Kim 
307654762dfSHyeongseok Kim 	do {
308654762dfSHyeongseok Kim 		if (next_free_clu == trim_end + 1) {
309654762dfSHyeongseok Kim 			/* extend trim range for continuous free cluster */
310654762dfSHyeongseok Kim 			trim_end++;
311654762dfSHyeongseok Kim 		} else {
312654762dfSHyeongseok Kim 			/* trim current range if it's larger than trim_minlen */
313654762dfSHyeongseok Kim 			count = trim_end - trim_begin + 1;
314654762dfSHyeongseok Kim 			if (count >= trim_minlen) {
315654762dfSHyeongseok Kim 				err = sb_issue_discard(sb,
316654762dfSHyeongseok Kim 					exfat_cluster_to_sector(sbi, trim_begin),
317654762dfSHyeongseok Kim 					count * sbi->sect_per_clus, GFP_NOFS, 0);
318654762dfSHyeongseok Kim 				if (err)
319654762dfSHyeongseok Kim 					goto unlock;
320654762dfSHyeongseok Kim 
321654762dfSHyeongseok Kim 				trimmed_total += count;
322654762dfSHyeongseok Kim 			}
323654762dfSHyeongseok Kim 
324654762dfSHyeongseok Kim 			/* set next start point of the free hole */
325654762dfSHyeongseok Kim 			trim_begin = trim_end = next_free_clu;
326654762dfSHyeongseok Kim 		}
327654762dfSHyeongseok Kim 
328654762dfSHyeongseok Kim 		if (next_free_clu >= clu_end)
329654762dfSHyeongseok Kim 			break;
330654762dfSHyeongseok Kim 
331654762dfSHyeongseok Kim 		if (fatal_signal_pending(current)) {
332654762dfSHyeongseok Kim 			err = -ERESTARTSYS;
333654762dfSHyeongseok Kim 			goto unlock;
334654762dfSHyeongseok Kim 		}
335654762dfSHyeongseok Kim 
336654762dfSHyeongseok Kim 		next_free_clu = exfat_find_free_bitmap(sb, next_free_clu + 1);
337654762dfSHyeongseok Kim 	} while (next_free_clu != EXFAT_EOF_CLUSTER &&
338654762dfSHyeongseok Kim 			next_free_clu > trim_end);
339654762dfSHyeongseok Kim 
340654762dfSHyeongseok Kim 	/* try to trim remainder */
341654762dfSHyeongseok Kim 	count = trim_end - trim_begin + 1;
342654762dfSHyeongseok Kim 	if (count >= trim_minlen) {
343654762dfSHyeongseok Kim 		err = sb_issue_discard(sb, exfat_cluster_to_sector(sbi, trim_begin),
344654762dfSHyeongseok Kim 			count * sbi->sect_per_clus, GFP_NOFS, 0);
345654762dfSHyeongseok Kim 		if (err)
346654762dfSHyeongseok Kim 			goto unlock;
347654762dfSHyeongseok Kim 
348654762dfSHyeongseok Kim 		trimmed_total += count;
349654762dfSHyeongseok Kim 	}
350654762dfSHyeongseok Kim 
351654762dfSHyeongseok Kim unlock:
352654762dfSHyeongseok Kim 	mutex_unlock(&sbi->bitmap_lock);
353654762dfSHyeongseok Kim 	range->len = trimmed_total << sbi->cluster_size_bits;
354654762dfSHyeongseok Kim 
355654762dfSHyeongseok Kim 	return err;
356654762dfSHyeongseok Kim }
357