xref: /kernel/linux/linux-5.10/fs/exfat/balloc.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/blkdev.h>
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci#include <linux/buffer_head.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "exfat_raw.h"
118c2ecf20Sopenharmony_ci#include "exfat_fs.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic const unsigned char free_bit[] = {
148c2ecf20Sopenharmony_ci	0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*  0 ~  19*/
158c2ecf20Sopenharmony_ci	0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3,/* 20 ~  39*/
168c2ecf20Sopenharmony_ci	0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/* 40 ~  59*/
178c2ecf20Sopenharmony_ci	0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/* 60 ~  79*/
188c2ecf20Sopenharmony_ci	0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2,/* 80 ~  99*/
198c2ecf20Sopenharmony_ci	0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3,/*100 ~ 119*/
208c2ecf20Sopenharmony_ci	0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*120 ~ 139*/
218c2ecf20Sopenharmony_ci	0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5,/*140 ~ 159*/
228c2ecf20Sopenharmony_ci	0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2,/*160 ~ 179*/
238c2ecf20Sopenharmony_ci	0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3,/*180 ~ 199*/
248c2ecf20Sopenharmony_ci	0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2,/*200 ~ 219*/
258c2ecf20Sopenharmony_ci	0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4,/*220 ~ 239*/
268c2ecf20Sopenharmony_ci	0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0                /*240 ~ 254*/
278c2ecf20Sopenharmony_ci};
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic const unsigned char used_bit[] = {
308c2ecf20Sopenharmony_ci	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3,/*  0 ~  19*/
318c2ecf20Sopenharmony_ci	2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4,/* 20 ~  39*/
328c2ecf20Sopenharmony_ci	2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5,/* 40 ~  59*/
338c2ecf20Sopenharmony_ci	4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,/* 60 ~  79*/
348c2ecf20Sopenharmony_ci	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4,/* 80 ~  99*/
358c2ecf20Sopenharmony_ci	3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6,/*100 ~ 119*/
368c2ecf20Sopenharmony_ci	4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4,/*120 ~ 139*/
378c2ecf20Sopenharmony_ci	3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,/*140 ~ 159*/
388c2ecf20Sopenharmony_ci	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5,/*160 ~ 179*/
398c2ecf20Sopenharmony_ci	4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5,/*180 ~ 199*/
408c2ecf20Sopenharmony_ci	3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6,/*200 ~ 219*/
418c2ecf20Sopenharmony_ci	5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,/*220 ~ 239*/
428c2ecf20Sopenharmony_ci	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8             /*240 ~ 255*/
438c2ecf20Sopenharmony_ci};
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci/*
468c2ecf20Sopenharmony_ci *  Allocation Bitmap Management Functions
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_cistatic int exfat_allocate_bitmap(struct super_block *sb,
498c2ecf20Sopenharmony_ci		struct exfat_dentry *ep)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
528c2ecf20Sopenharmony_ci	long long map_size;
538c2ecf20Sopenharmony_ci	unsigned int i, need_map_size;
548c2ecf20Sopenharmony_ci	sector_t sector;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	sbi->map_clu = le32_to_cpu(ep->dentry.bitmap.start_clu);
578c2ecf20Sopenharmony_ci	map_size = le64_to_cpu(ep->dentry.bitmap.size);
588c2ecf20Sopenharmony_ci	need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE)
598c2ecf20Sopenharmony_ci		+ 1;
608c2ecf20Sopenharmony_ci	if (need_map_size != map_size) {
618c2ecf20Sopenharmony_ci		exfat_err(sb, "bogus allocation bitmap size(need : %u, cur : %lld)",
628c2ecf20Sopenharmony_ci			  need_map_size, map_size);
638c2ecf20Sopenharmony_ci		/*
648c2ecf20Sopenharmony_ci		 * Only allowed when bogus allocation
658c2ecf20Sopenharmony_ci		 * bitmap size is large
668c2ecf20Sopenharmony_ci		 */
678c2ecf20Sopenharmony_ci		if (need_map_size > map_size)
688c2ecf20Sopenharmony_ci			return -EIO;
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci	sbi->map_sectors = ((need_map_size - 1) >>
718c2ecf20Sopenharmony_ci			(sb->s_blocksize_bits)) + 1;
728c2ecf20Sopenharmony_ci	sbi->vol_amap = kvmalloc_array(sbi->map_sectors,
738c2ecf20Sopenharmony_ci				sizeof(struct buffer_head *), GFP_KERNEL);
748c2ecf20Sopenharmony_ci	if (!sbi->vol_amap)
758c2ecf20Sopenharmony_ci		return -ENOMEM;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	sector = exfat_cluster_to_sector(sbi, sbi->map_clu);
788c2ecf20Sopenharmony_ci	for (i = 0; i < sbi->map_sectors; i++) {
798c2ecf20Sopenharmony_ci		sbi->vol_amap[i] = sb_bread(sb, sector + i);
808c2ecf20Sopenharmony_ci		if (!sbi->vol_amap[i]) {
818c2ecf20Sopenharmony_ci			/* release all buffers and free vol_amap */
828c2ecf20Sopenharmony_ci			int j = 0;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci			while (j < i)
858c2ecf20Sopenharmony_ci				brelse(sbi->vol_amap[j++]);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci			kvfree(sbi->vol_amap);
888c2ecf20Sopenharmony_ci			sbi->vol_amap = NULL;
898c2ecf20Sopenharmony_ci			return -EIO;
908c2ecf20Sopenharmony_ci		}
918c2ecf20Sopenharmony_ci	}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	return 0;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ciint exfat_load_bitmap(struct super_block *sb)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	unsigned int i, type;
998c2ecf20Sopenharmony_ci	struct exfat_chain clu;
1008c2ecf20Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	exfat_chain_set(&clu, sbi->root_dir, 0, ALLOC_FAT_CHAIN);
1038c2ecf20Sopenharmony_ci	while (clu.dir != EXFAT_EOF_CLUSTER) {
1048c2ecf20Sopenharmony_ci		for (i = 0; i < sbi->dentries_per_clu; i++) {
1058c2ecf20Sopenharmony_ci			struct exfat_dentry *ep;
1068c2ecf20Sopenharmony_ci			struct buffer_head *bh;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci			ep = exfat_get_dentry(sb, &clu, i, &bh, NULL);
1098c2ecf20Sopenharmony_ci			if (!ep)
1108c2ecf20Sopenharmony_ci				return -EIO;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci			type = exfat_get_entry_type(ep);
1138c2ecf20Sopenharmony_ci			if (type == TYPE_UNUSED)
1148c2ecf20Sopenharmony_ci				break;
1158c2ecf20Sopenharmony_ci			if (type != TYPE_BITMAP)
1168c2ecf20Sopenharmony_ci				continue;
1178c2ecf20Sopenharmony_ci			if (ep->dentry.bitmap.flags == 0x0) {
1188c2ecf20Sopenharmony_ci				int err;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci				err = exfat_allocate_bitmap(sb, ep);
1218c2ecf20Sopenharmony_ci				brelse(bh);
1228c2ecf20Sopenharmony_ci				return err;
1238c2ecf20Sopenharmony_ci			}
1248c2ecf20Sopenharmony_ci			brelse(bh);
1258c2ecf20Sopenharmony_ci		}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		if (exfat_get_next_cluster(sb, &clu.dir))
1288c2ecf20Sopenharmony_ci			return -EIO;
1298c2ecf20Sopenharmony_ci	}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return -EINVAL;
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_civoid exfat_free_bitmap(struct exfat_sb_info *sbi)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	int i;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	for (i = 0; i < sbi->map_sectors; i++)
1398c2ecf20Sopenharmony_ci		__brelse(sbi->vol_amap[i]);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	kvfree(sbi->vol_amap);
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ciint exfat_set_bitmap(struct inode *inode, unsigned int clu)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	int i, b;
1478c2ecf20Sopenharmony_ci	unsigned int ent_idx;
1488c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
1498c2ecf20Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (!is_valid_cluster(sbi, clu))
1528c2ecf20Sopenharmony_ci		return -EINVAL;
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
1558c2ecf20Sopenharmony_ci	i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
1568c2ecf20Sopenharmony_ci	b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	set_bit_le(b, sbi->vol_amap[i]->b_data);
1598c2ecf20Sopenharmony_ci	exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode));
1608c2ecf20Sopenharmony_ci	return 0;
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_civoid exfat_clear_bitmap(struct inode *inode, unsigned int clu)
1648c2ecf20Sopenharmony_ci{
1658c2ecf20Sopenharmony_ci	int i, b;
1668c2ecf20Sopenharmony_ci	unsigned int ent_idx;
1678c2ecf20Sopenharmony_ci	struct super_block *sb = inode->i_sb;
1688c2ecf20Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
1698c2ecf20Sopenharmony_ci	struct exfat_mount_options *opts = &sbi->options;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (!is_valid_cluster(sbi, clu))
1728c2ecf20Sopenharmony_ci		return;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
1758c2ecf20Sopenharmony_ci	i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
1768c2ecf20Sopenharmony_ci	b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	clear_bit_le(b, sbi->vol_amap[i]->b_data);
1798c2ecf20Sopenharmony_ci	exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode));
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (opts->discard) {
1828c2ecf20Sopenharmony_ci		int ret_discard;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci		ret_discard = sb_issue_discard(sb,
1858c2ecf20Sopenharmony_ci			exfat_cluster_to_sector(sbi, clu),
1868c2ecf20Sopenharmony_ci			(1 << sbi->sect_per_clus_bits), GFP_NOFS, 0);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci		if (ret_discard == -EOPNOTSUPP) {
1898c2ecf20Sopenharmony_ci			exfat_err(sb, "discard not supported by device, disabling");
1908c2ecf20Sopenharmony_ci			opts->discard = 0;
1918c2ecf20Sopenharmony_ci		}
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci/*
1968c2ecf20Sopenharmony_ci * If the value of "clu" is 0, it means cluster 2 which is the first cluster of
1978c2ecf20Sopenharmony_ci * the cluster heap.
1988c2ecf20Sopenharmony_ci */
1998c2ecf20Sopenharmony_ciunsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	unsigned int i, map_i, map_b, ent_idx;
2028c2ecf20Sopenharmony_ci	unsigned int clu_base, clu_free;
2038c2ecf20Sopenharmony_ci	unsigned char k, clu_mask;
2048c2ecf20Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	WARN_ON(clu < EXFAT_FIRST_CLUSTER);
2078c2ecf20Sopenharmony_ci	ent_idx = CLUSTER_TO_BITMAP_ENT(clu);
2088c2ecf20Sopenharmony_ci	clu_base = BITMAP_ENT_TO_CLUSTER(ent_idx & ~(BITS_PER_BYTE_MASK));
2098c2ecf20Sopenharmony_ci	clu_mask = IGNORED_BITS_REMAINED(clu, clu_base);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	map_i = BITMAP_OFFSET_SECTOR_INDEX(sb, ent_idx);
2128c2ecf20Sopenharmony_ci	map_b = BITMAP_OFFSET_BYTE_IN_SECTOR(sb, ent_idx);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters;
2158c2ecf20Sopenharmony_ci	     i += BITS_PER_BYTE) {
2168c2ecf20Sopenharmony_ci		k = *(sbi->vol_amap[map_i]->b_data + map_b);
2178c2ecf20Sopenharmony_ci		if (clu_mask > 0) {
2188c2ecf20Sopenharmony_ci			k |= clu_mask;
2198c2ecf20Sopenharmony_ci			clu_mask = 0;
2208c2ecf20Sopenharmony_ci		}
2218c2ecf20Sopenharmony_ci		if (k < 0xFF) {
2228c2ecf20Sopenharmony_ci			clu_free = clu_base + free_bit[k];
2238c2ecf20Sopenharmony_ci			if (clu_free < sbi->num_clusters)
2248c2ecf20Sopenharmony_ci				return clu_free;
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci		clu_base += BITS_PER_BYTE;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		if (++map_b >= sb->s_blocksize ||
2298c2ecf20Sopenharmony_ci		    clu_base >= sbi->num_clusters) {
2308c2ecf20Sopenharmony_ci			if (++map_i >= sbi->map_sectors) {
2318c2ecf20Sopenharmony_ci				clu_base = EXFAT_FIRST_CLUSTER;
2328c2ecf20Sopenharmony_ci				map_i = 0;
2338c2ecf20Sopenharmony_ci			}
2348c2ecf20Sopenharmony_ci			map_b = 0;
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci	}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	return EXFAT_EOF_CLUSTER;
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ciint exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count)
2428c2ecf20Sopenharmony_ci{
2438c2ecf20Sopenharmony_ci	struct exfat_sb_info *sbi = EXFAT_SB(sb);
2448c2ecf20Sopenharmony_ci	unsigned int count = 0;
2458c2ecf20Sopenharmony_ci	unsigned int i, map_i = 0, map_b = 0;
2468c2ecf20Sopenharmony_ci	unsigned int total_clus = EXFAT_DATA_CLUSTER_COUNT(sbi);
2478c2ecf20Sopenharmony_ci	unsigned int last_mask = total_clus & BITS_PER_BYTE_MASK;
2488c2ecf20Sopenharmony_ci	unsigned char clu_bits;
2498c2ecf20Sopenharmony_ci	const unsigned char last_bit_mask[] = {0, 0b00000001, 0b00000011,
2508c2ecf20Sopenharmony_ci		0b00000111, 0b00001111, 0b00011111, 0b00111111, 0b01111111};
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	total_clus &= ~last_mask;
2538c2ecf20Sopenharmony_ci	for (i = 0; i < total_clus; i += BITS_PER_BYTE) {
2548c2ecf20Sopenharmony_ci		clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
2558c2ecf20Sopenharmony_ci		count += used_bit[clu_bits];
2568c2ecf20Sopenharmony_ci		if (++map_b >= (unsigned int)sb->s_blocksize) {
2578c2ecf20Sopenharmony_ci			map_i++;
2588c2ecf20Sopenharmony_ci			map_b = 0;
2598c2ecf20Sopenharmony_ci		}
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (last_mask) {
2638c2ecf20Sopenharmony_ci		clu_bits = *(sbi->vol_amap[map_i]->b_data + map_b);
2648c2ecf20Sopenharmony_ci		clu_bits &= last_bit_mask[last_mask];
2658c2ecf20Sopenharmony_ci		count += used_bit[clu_bits];
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	*ret_count = count;
2698c2ecf20Sopenharmony_ci	return 0;
2708c2ecf20Sopenharmony_ci}
271