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/slab.h> 78c2ecf20Sopenharmony_ci#include <asm/unaligned.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 int exfat_mirror_bh(struct super_block *sb, sector_t sec, 148c2ecf20Sopenharmony_ci struct buffer_head *bh) 158c2ecf20Sopenharmony_ci{ 168c2ecf20Sopenharmony_ci struct buffer_head *c_bh; 178c2ecf20Sopenharmony_ci struct exfat_sb_info *sbi = EXFAT_SB(sb); 188c2ecf20Sopenharmony_ci sector_t sec2; 198c2ecf20Sopenharmony_ci int err = 0; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci if (sbi->FAT2_start_sector != sbi->FAT1_start_sector) { 228c2ecf20Sopenharmony_ci sec2 = sec - sbi->FAT1_start_sector + sbi->FAT2_start_sector; 238c2ecf20Sopenharmony_ci c_bh = sb_getblk(sb, sec2); 248c2ecf20Sopenharmony_ci if (!c_bh) 258c2ecf20Sopenharmony_ci return -ENOMEM; 268c2ecf20Sopenharmony_ci memcpy(c_bh->b_data, bh->b_data, sb->s_blocksize); 278c2ecf20Sopenharmony_ci set_buffer_uptodate(c_bh); 288c2ecf20Sopenharmony_ci mark_buffer_dirty(c_bh); 298c2ecf20Sopenharmony_ci if (sb->s_flags & SB_SYNCHRONOUS) 308c2ecf20Sopenharmony_ci err = sync_dirty_buffer(c_bh); 318c2ecf20Sopenharmony_ci brelse(c_bh); 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci return err; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int __exfat_ent_get(struct super_block *sb, unsigned int loc, 388c2ecf20Sopenharmony_ci unsigned int *content) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci unsigned int off; 418c2ecf20Sopenharmony_ci sector_t sec; 428c2ecf20Sopenharmony_ci struct buffer_head *bh; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci sec = FAT_ENT_OFFSET_SECTOR(sb, loc); 458c2ecf20Sopenharmony_ci off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci bh = sb_bread(sb, sec); 488c2ecf20Sopenharmony_ci if (!bh) 498c2ecf20Sopenharmony_ci return -EIO; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci *content = le32_to_cpu(*(__le32 *)(&bh->b_data[off])); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* remap reserved clusters to simplify code */ 548c2ecf20Sopenharmony_ci if (*content > EXFAT_BAD_CLUSTER) 558c2ecf20Sopenharmony_ci *content = EXFAT_EOF_CLUSTER; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci brelse(bh); 588c2ecf20Sopenharmony_ci return 0; 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ciint exfat_ent_set(struct super_block *sb, unsigned int loc, 628c2ecf20Sopenharmony_ci unsigned int content) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci unsigned int off; 658c2ecf20Sopenharmony_ci sector_t sec; 668c2ecf20Sopenharmony_ci __le32 *fat_entry; 678c2ecf20Sopenharmony_ci struct buffer_head *bh; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci sec = FAT_ENT_OFFSET_SECTOR(sb, loc); 708c2ecf20Sopenharmony_ci off = FAT_ENT_OFFSET_BYTE_IN_SECTOR(sb, loc); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci bh = sb_bread(sb, sec); 738c2ecf20Sopenharmony_ci if (!bh) 748c2ecf20Sopenharmony_ci return -EIO; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci fat_entry = (__le32 *)&(bh->b_data[off]); 778c2ecf20Sopenharmony_ci *fat_entry = cpu_to_le32(content); 788c2ecf20Sopenharmony_ci exfat_update_bh(bh, sb->s_flags & SB_SYNCHRONOUS); 798c2ecf20Sopenharmony_ci exfat_mirror_bh(sb, sec, bh); 808c2ecf20Sopenharmony_ci brelse(bh); 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ciint exfat_ent_get(struct super_block *sb, unsigned int loc, 858c2ecf20Sopenharmony_ci unsigned int *content) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct exfat_sb_info *sbi = EXFAT_SB(sb); 888c2ecf20Sopenharmony_ci int err; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (!is_valid_cluster(sbi, loc)) { 918c2ecf20Sopenharmony_ci exfat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", 928c2ecf20Sopenharmony_ci loc); 938c2ecf20Sopenharmony_ci return -EIO; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci err = __exfat_ent_get(sb, loc, content); 978c2ecf20Sopenharmony_ci if (err) { 988c2ecf20Sopenharmony_ci exfat_fs_error(sb, 998c2ecf20Sopenharmony_ci "failed to access to FAT (entry 0x%08x, err:%d)", 1008c2ecf20Sopenharmony_ci loc, err); 1018c2ecf20Sopenharmony_ci return err; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (*content == EXFAT_FREE_CLUSTER) { 1058c2ecf20Sopenharmony_ci exfat_fs_error(sb, 1068c2ecf20Sopenharmony_ci "invalid access to FAT free cluster (entry 0x%08x)", 1078c2ecf20Sopenharmony_ci loc); 1088c2ecf20Sopenharmony_ci return -EIO; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (*content == EXFAT_BAD_CLUSTER) { 1128c2ecf20Sopenharmony_ci exfat_fs_error(sb, 1138c2ecf20Sopenharmony_ci "invalid access to FAT bad cluster (entry 0x%08x)", 1148c2ecf20Sopenharmony_ci loc); 1158c2ecf20Sopenharmony_ci return -EIO; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (*content != EXFAT_EOF_CLUSTER && !is_valid_cluster(sbi, *content)) { 1198c2ecf20Sopenharmony_ci exfat_fs_error(sb, 1208c2ecf20Sopenharmony_ci "invalid access to FAT (entry 0x%08x) bogus content (0x%08x)", 1218c2ecf20Sopenharmony_ci loc, *content); 1228c2ecf20Sopenharmony_ci return -EIO; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ciint exfat_chain_cont_cluster(struct super_block *sb, unsigned int chain, 1298c2ecf20Sopenharmony_ci unsigned int len) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci if (!len) 1328c2ecf20Sopenharmony_ci return 0; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci while (len > 1) { 1358c2ecf20Sopenharmony_ci if (exfat_ent_set(sb, chain, chain + 1)) 1368c2ecf20Sopenharmony_ci return -EIO; 1378c2ecf20Sopenharmony_ci chain++; 1388c2ecf20Sopenharmony_ci len--; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci if (exfat_ent_set(sb, chain, EXFAT_EOF_CLUSTER)) 1428c2ecf20Sopenharmony_ci return -EIO; 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciint exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci unsigned int num_clusters = 0; 1498c2ecf20Sopenharmony_ci unsigned int clu; 1508c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 1518c2ecf20Sopenharmony_ci struct exfat_sb_info *sbi = EXFAT_SB(sb); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* invalid cluster number */ 1548c2ecf20Sopenharmony_ci if (p_chain->dir == EXFAT_FREE_CLUSTER || 1558c2ecf20Sopenharmony_ci p_chain->dir == EXFAT_EOF_CLUSTER || 1568c2ecf20Sopenharmony_ci p_chain->dir < EXFAT_FIRST_CLUSTER) 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci /* no cluster to truncate */ 1608c2ecf20Sopenharmony_ci if (p_chain->size == 0) 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci /* check cluster validation */ 1648c2ecf20Sopenharmony_ci if (!is_valid_cluster(sbi, p_chain->dir)) { 1658c2ecf20Sopenharmony_ci exfat_err(sb, "invalid start cluster (%u)", p_chain->dir); 1668c2ecf20Sopenharmony_ci return -EIO; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci clu = p_chain->dir; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { 1728c2ecf20Sopenharmony_ci do { 1738c2ecf20Sopenharmony_ci exfat_clear_bitmap(inode, clu); 1748c2ecf20Sopenharmony_ci clu++; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci num_clusters++; 1778c2ecf20Sopenharmony_ci } while (num_clusters < p_chain->size); 1788c2ecf20Sopenharmony_ci } else { 1798c2ecf20Sopenharmony_ci do { 1808c2ecf20Sopenharmony_ci exfat_clear_bitmap(inode, clu); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci if (exfat_get_next_cluster(sb, &clu)) 1838c2ecf20Sopenharmony_ci goto dec_used_clus; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci num_clusters++; 1868c2ecf20Sopenharmony_ci } while (clu != EXFAT_EOF_CLUSTER); 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cidec_used_clus: 1908c2ecf20Sopenharmony_ci sbi->used_clusters -= num_clusters; 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ciint exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, 1958c2ecf20Sopenharmony_ci unsigned int *ret_clu) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci unsigned int clu, next; 1988c2ecf20Sopenharmony_ci unsigned int count = 0; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci next = p_chain->dir; 2018c2ecf20Sopenharmony_ci if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { 2028c2ecf20Sopenharmony_ci *ret_clu = next + p_chain->size - 1; 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci do { 2078c2ecf20Sopenharmony_ci count++; 2088c2ecf20Sopenharmony_ci clu = next; 2098c2ecf20Sopenharmony_ci if (exfat_ent_get(sb, clu, &next)) 2108c2ecf20Sopenharmony_ci return -EIO; 2118c2ecf20Sopenharmony_ci } while (next != EXFAT_EOF_CLUSTER); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (p_chain->size != count) { 2148c2ecf20Sopenharmony_ci exfat_fs_error(sb, 2158c2ecf20Sopenharmony_ci "bogus directory size (clus : ondisk(%d) != counted(%d))", 2168c2ecf20Sopenharmony_ci p_chain->size, count); 2178c2ecf20Sopenharmony_ci return -EIO; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci *ret_clu = clu; 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ciint exfat_zeroed_cluster(struct inode *dir, unsigned int clu) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 2278c2ecf20Sopenharmony_ci struct exfat_sb_info *sbi = EXFAT_SB(sb); 2288c2ecf20Sopenharmony_ci struct buffer_head *bhs[MAX_BUF_PER_PAGE]; 2298c2ecf20Sopenharmony_ci int nr_bhs = MAX_BUF_PER_PAGE; 2308c2ecf20Sopenharmony_ci sector_t blknr, last_blknr; 2318c2ecf20Sopenharmony_ci int err, i, n; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci blknr = exfat_cluster_to_sector(sbi, clu); 2348c2ecf20Sopenharmony_ci last_blknr = blknr + sbi->sect_per_clus; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci if (last_blknr > sbi->num_sectors && sbi->num_sectors > 0) { 2378c2ecf20Sopenharmony_ci exfat_fs_error_ratelimit(sb, 2388c2ecf20Sopenharmony_ci "%s: out of range(sect:%llu len:%u)", 2398c2ecf20Sopenharmony_ci __func__, (unsigned long long)blknr, 2408c2ecf20Sopenharmony_ci sbi->sect_per_clus); 2418c2ecf20Sopenharmony_ci return -EIO; 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* Zeroing the unused blocks on this cluster */ 2458c2ecf20Sopenharmony_ci while (blknr < last_blknr) { 2468c2ecf20Sopenharmony_ci for (n = 0; n < nr_bhs && blknr < last_blknr; n++, blknr++) { 2478c2ecf20Sopenharmony_ci bhs[n] = sb_getblk(sb, blknr); 2488c2ecf20Sopenharmony_ci if (!bhs[n]) { 2498c2ecf20Sopenharmony_ci err = -ENOMEM; 2508c2ecf20Sopenharmony_ci goto release_bhs; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci memset(bhs[n]->b_data, 0, sb->s_blocksize); 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci err = exfat_update_bhs(bhs, n, IS_DIRSYNC(dir)); 2568c2ecf20Sopenharmony_ci if (err) 2578c2ecf20Sopenharmony_ci goto release_bhs; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) 2608c2ecf20Sopenharmony_ci brelse(bhs[i]); 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cirelease_bhs: 2658c2ecf20Sopenharmony_ci exfat_err(sb, "failed zeroed sect %llu\n", (unsigned long long)blknr); 2668c2ecf20Sopenharmony_ci for (i = 0; i < n; i++) 2678c2ecf20Sopenharmony_ci bforget(bhs[i]); 2688c2ecf20Sopenharmony_ci return err; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ciint exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, 2728c2ecf20Sopenharmony_ci struct exfat_chain *p_chain) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci int ret = -ENOSPC; 2758c2ecf20Sopenharmony_ci unsigned int num_clusters = 0, total_cnt; 2768c2ecf20Sopenharmony_ci unsigned int hint_clu, new_clu, last_clu = EXFAT_EOF_CLUSTER; 2778c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 2788c2ecf20Sopenharmony_ci struct exfat_sb_info *sbi = EXFAT_SB(sb); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci total_cnt = EXFAT_DATA_CLUSTER_COUNT(sbi); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci if (unlikely(total_cnt < sbi->used_clusters)) { 2838c2ecf20Sopenharmony_ci exfat_fs_error_ratelimit(sb, 2848c2ecf20Sopenharmony_ci "%s: invalid used clusters(t:%u,u:%u)\n", 2858c2ecf20Sopenharmony_ci __func__, total_cnt, sbi->used_clusters); 2868c2ecf20Sopenharmony_ci return -EIO; 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (num_alloc > total_cnt - sbi->used_clusters) 2908c2ecf20Sopenharmony_ci return -ENOSPC; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci hint_clu = p_chain->dir; 2938c2ecf20Sopenharmony_ci /* find new cluster */ 2948c2ecf20Sopenharmony_ci if (hint_clu == EXFAT_EOF_CLUSTER) { 2958c2ecf20Sopenharmony_ci if (sbi->clu_srch_ptr < EXFAT_FIRST_CLUSTER) { 2968c2ecf20Sopenharmony_ci exfat_err(sb, "sbi->clu_srch_ptr is invalid (%u)\n", 2978c2ecf20Sopenharmony_ci sbi->clu_srch_ptr); 2988c2ecf20Sopenharmony_ci sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci hint_clu = exfat_find_free_bitmap(sb, sbi->clu_srch_ptr); 3028c2ecf20Sopenharmony_ci if (hint_clu == EXFAT_EOF_CLUSTER) 3038c2ecf20Sopenharmony_ci return -ENOSPC; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci /* check cluster validation */ 3078c2ecf20Sopenharmony_ci if (!is_valid_cluster(sbi, hint_clu)) { 3088c2ecf20Sopenharmony_ci exfat_err(sb, "hint_cluster is invalid (%u)", 3098c2ecf20Sopenharmony_ci hint_clu); 3108c2ecf20Sopenharmony_ci hint_clu = EXFAT_FIRST_CLUSTER; 3118c2ecf20Sopenharmony_ci if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { 3128c2ecf20Sopenharmony_ci if (exfat_chain_cont_cluster(sb, p_chain->dir, 3138c2ecf20Sopenharmony_ci num_clusters)) 3148c2ecf20Sopenharmony_ci return -EIO; 3158c2ecf20Sopenharmony_ci p_chain->flags = ALLOC_FAT_CHAIN; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci p_chain->dir = EXFAT_EOF_CLUSTER; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci while ((new_clu = exfat_find_free_bitmap(sb, hint_clu)) != 3228c2ecf20Sopenharmony_ci EXFAT_EOF_CLUSTER) { 3238c2ecf20Sopenharmony_ci if (new_clu != hint_clu && 3248c2ecf20Sopenharmony_ci p_chain->flags == ALLOC_NO_FAT_CHAIN) { 3258c2ecf20Sopenharmony_ci if (exfat_chain_cont_cluster(sb, p_chain->dir, 3268c2ecf20Sopenharmony_ci num_clusters)) { 3278c2ecf20Sopenharmony_ci ret = -EIO; 3288c2ecf20Sopenharmony_ci goto free_cluster; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci p_chain->flags = ALLOC_FAT_CHAIN; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* update allocation bitmap */ 3348c2ecf20Sopenharmony_ci if (exfat_set_bitmap(inode, new_clu)) { 3358c2ecf20Sopenharmony_ci ret = -EIO; 3368c2ecf20Sopenharmony_ci goto free_cluster; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci num_clusters++; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* update FAT table */ 3428c2ecf20Sopenharmony_ci if (p_chain->flags == ALLOC_FAT_CHAIN) { 3438c2ecf20Sopenharmony_ci if (exfat_ent_set(sb, new_clu, EXFAT_EOF_CLUSTER)) { 3448c2ecf20Sopenharmony_ci ret = -EIO; 3458c2ecf20Sopenharmony_ci goto free_cluster; 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (p_chain->dir == EXFAT_EOF_CLUSTER) { 3508c2ecf20Sopenharmony_ci p_chain->dir = new_clu; 3518c2ecf20Sopenharmony_ci } else if (p_chain->flags == ALLOC_FAT_CHAIN) { 3528c2ecf20Sopenharmony_ci if (exfat_ent_set(sb, last_clu, new_clu)) { 3538c2ecf20Sopenharmony_ci ret = -EIO; 3548c2ecf20Sopenharmony_ci goto free_cluster; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci last_clu = new_clu; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (--num_alloc == 0) { 3608c2ecf20Sopenharmony_ci sbi->clu_srch_ptr = hint_clu; 3618c2ecf20Sopenharmony_ci sbi->used_clusters += num_clusters; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci p_chain->size += num_clusters; 3648c2ecf20Sopenharmony_ci return 0; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci hint_clu = new_clu + 1; 3688c2ecf20Sopenharmony_ci if (hint_clu >= sbi->num_clusters) { 3698c2ecf20Sopenharmony_ci hint_clu = EXFAT_FIRST_CLUSTER; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { 3728c2ecf20Sopenharmony_ci if (exfat_chain_cont_cluster(sb, p_chain->dir, 3738c2ecf20Sopenharmony_ci num_clusters)) { 3748c2ecf20Sopenharmony_ci ret = -EIO; 3758c2ecf20Sopenharmony_ci goto free_cluster; 3768c2ecf20Sopenharmony_ci } 3778c2ecf20Sopenharmony_ci p_chain->flags = ALLOC_FAT_CHAIN; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci } 3818c2ecf20Sopenharmony_cifree_cluster: 3828c2ecf20Sopenharmony_ci if (num_clusters) 3838c2ecf20Sopenharmony_ci exfat_free_cluster(inode, p_chain); 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ciint exfat_count_num_clusters(struct super_block *sb, 3888c2ecf20Sopenharmony_ci struct exfat_chain *p_chain, unsigned int *ret_count) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci unsigned int i, count; 3918c2ecf20Sopenharmony_ci unsigned int clu; 3928c2ecf20Sopenharmony_ci struct exfat_sb_info *sbi = EXFAT_SB(sb); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!p_chain->dir || p_chain->dir == EXFAT_EOF_CLUSTER) { 3958c2ecf20Sopenharmony_ci *ret_count = 0; 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci if (p_chain->flags == ALLOC_NO_FAT_CHAIN) { 4008c2ecf20Sopenharmony_ci *ret_count = p_chain->size; 4018c2ecf20Sopenharmony_ci return 0; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci clu = p_chain->dir; 4058c2ecf20Sopenharmony_ci count = 0; 4068c2ecf20Sopenharmony_ci for (i = EXFAT_FIRST_CLUSTER; i < sbi->num_clusters; i++) { 4078c2ecf20Sopenharmony_ci count++; 4088c2ecf20Sopenharmony_ci if (exfat_ent_get(sb, clu, &clu)) 4098c2ecf20Sopenharmony_ci return -EIO; 4108c2ecf20Sopenharmony_ci if (clu == EXFAT_EOF_CLUSTER) 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci *ret_count = count; 4158c2ecf20Sopenharmony_ci return 0; 4168c2ecf20Sopenharmony_ci} 417