162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/affs/bitmap.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (c) 1996 Hans-Joachim Widmaier 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * bitmap.c contains the code that handles all bitmap related stuff - 862306a36Sopenharmony_ci * block allocation, deallocation, calculation of free space. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include "affs.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ciu32 1562306a36Sopenharmony_ciaffs_count_free_blocks(struct super_block *sb) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci struct affs_bm_info *bm; 1862306a36Sopenharmony_ci u32 free; 1962306a36Sopenharmony_ci int i; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci pr_debug("%s()\n", __func__); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci if (sb_rdonly(sb)) 2462306a36Sopenharmony_ci return 0; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci mutex_lock(&AFFS_SB(sb)->s_bmlock); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci bm = AFFS_SB(sb)->s_bitmap; 2962306a36Sopenharmony_ci free = 0; 3062306a36Sopenharmony_ci for (i = AFFS_SB(sb)->s_bmap_count; i > 0; bm++, i--) 3162306a36Sopenharmony_ci free += bm->bm_free; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci mutex_unlock(&AFFS_SB(sb)->s_bmlock); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return free; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_civoid 3962306a36Sopenharmony_ciaffs_free_block(struct super_block *sb, u32 block) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 4262306a36Sopenharmony_ci struct affs_bm_info *bm; 4362306a36Sopenharmony_ci struct buffer_head *bh; 4462306a36Sopenharmony_ci u32 blk, bmap, bit, mask, tmp; 4562306a36Sopenharmony_ci __be32 *data; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci pr_debug("%s(%u)\n", __func__, block); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if (block > sbi->s_partition_size) 5062306a36Sopenharmony_ci goto err_range; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci blk = block - sbi->s_reserved; 5362306a36Sopenharmony_ci bmap = blk / sbi->s_bmap_bits; 5462306a36Sopenharmony_ci bit = blk % sbi->s_bmap_bits; 5562306a36Sopenharmony_ci bm = &sbi->s_bitmap[bmap]; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci mutex_lock(&sbi->s_bmlock); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci bh = sbi->s_bmap_bh; 6062306a36Sopenharmony_ci if (sbi->s_last_bmap != bmap) { 6162306a36Sopenharmony_ci affs_brelse(bh); 6262306a36Sopenharmony_ci bh = affs_bread(sb, bm->bm_key); 6362306a36Sopenharmony_ci if (!bh) 6462306a36Sopenharmony_ci goto err_bh_read; 6562306a36Sopenharmony_ci sbi->s_bmap_bh = bh; 6662306a36Sopenharmony_ci sbi->s_last_bmap = bmap; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci mask = 1 << (bit & 31); 7062306a36Sopenharmony_ci data = (__be32 *)bh->b_data + bit / 32 + 1; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci /* mark block free */ 7362306a36Sopenharmony_ci tmp = be32_to_cpu(*data); 7462306a36Sopenharmony_ci if (tmp & mask) 7562306a36Sopenharmony_ci goto err_free; 7662306a36Sopenharmony_ci *data = cpu_to_be32(tmp | mask); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* fix checksum */ 7962306a36Sopenharmony_ci tmp = be32_to_cpu(*(__be32 *)bh->b_data); 8062306a36Sopenharmony_ci *(__be32 *)bh->b_data = cpu_to_be32(tmp - mask); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci mark_buffer_dirty(bh); 8362306a36Sopenharmony_ci affs_mark_sb_dirty(sb); 8462306a36Sopenharmony_ci bm->bm_free++; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci mutex_unlock(&sbi->s_bmlock); 8762306a36Sopenharmony_ci return; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cierr_free: 9062306a36Sopenharmony_ci affs_warning(sb,"affs_free_block","Trying to free block %u which is already free", block); 9162306a36Sopenharmony_ci mutex_unlock(&sbi->s_bmlock); 9262306a36Sopenharmony_ci return; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cierr_bh_read: 9562306a36Sopenharmony_ci affs_error(sb,"affs_free_block","Cannot read bitmap block %u", bm->bm_key); 9662306a36Sopenharmony_ci sbi->s_bmap_bh = NULL; 9762306a36Sopenharmony_ci sbi->s_last_bmap = ~0; 9862306a36Sopenharmony_ci mutex_unlock(&sbi->s_bmlock); 9962306a36Sopenharmony_ci return; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cierr_range: 10262306a36Sopenharmony_ci affs_error(sb, "affs_free_block","Block %u outside partition", block); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci/* 10662306a36Sopenharmony_ci * Allocate a block in the given allocation zone. 10762306a36Sopenharmony_ci * Since we have to byte-swap the bitmap on little-endian 10862306a36Sopenharmony_ci * machines, this is rather expensive. Therefore we will 10962306a36Sopenharmony_ci * preallocate up to 16 blocks from the same word, if 11062306a36Sopenharmony_ci * possible. We are not doing preallocations in the 11162306a36Sopenharmony_ci * header zone, though. 11262306a36Sopenharmony_ci */ 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciu32 11562306a36Sopenharmony_ciaffs_alloc_block(struct inode *inode, u32 goal) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci struct super_block *sb; 11862306a36Sopenharmony_ci struct affs_sb_info *sbi; 11962306a36Sopenharmony_ci struct affs_bm_info *bm; 12062306a36Sopenharmony_ci struct buffer_head *bh; 12162306a36Sopenharmony_ci __be32 *data, *enddata; 12262306a36Sopenharmony_ci u32 blk, bmap, bit, mask, mask2, tmp; 12362306a36Sopenharmony_ci int i; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci sb = inode->i_sb; 12662306a36Sopenharmony_ci sbi = AFFS_SB(sb); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci pr_debug("balloc(inode=%lu,goal=%u): ", inode->i_ino, goal); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (AFFS_I(inode)->i_pa_cnt) { 13162306a36Sopenharmony_ci pr_debug("%d\n", AFFS_I(inode)->i_lastalloc+1); 13262306a36Sopenharmony_ci AFFS_I(inode)->i_pa_cnt--; 13362306a36Sopenharmony_ci return ++AFFS_I(inode)->i_lastalloc; 13462306a36Sopenharmony_ci } 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci if (!goal || goal > sbi->s_partition_size) { 13762306a36Sopenharmony_ci if (goal) 13862306a36Sopenharmony_ci affs_warning(sb, "affs_balloc", "invalid goal %d", goal); 13962306a36Sopenharmony_ci //if (!AFFS_I(inode)->i_last_block) 14062306a36Sopenharmony_ci // affs_warning(sb, "affs_balloc", "no last alloc block"); 14162306a36Sopenharmony_ci goal = sbi->s_reserved; 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci blk = goal - sbi->s_reserved; 14562306a36Sopenharmony_ci bmap = blk / sbi->s_bmap_bits; 14662306a36Sopenharmony_ci bm = &sbi->s_bitmap[bmap]; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci mutex_lock(&sbi->s_bmlock); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (bm->bm_free) 15162306a36Sopenharmony_ci goto find_bmap_bit; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cifind_bmap: 15462306a36Sopenharmony_ci /* search for the next bmap buffer with free bits */ 15562306a36Sopenharmony_ci i = sbi->s_bmap_count; 15662306a36Sopenharmony_ci do { 15762306a36Sopenharmony_ci if (--i < 0) 15862306a36Sopenharmony_ci goto err_full; 15962306a36Sopenharmony_ci bmap++; 16062306a36Sopenharmony_ci bm++; 16162306a36Sopenharmony_ci if (bmap < sbi->s_bmap_count) 16262306a36Sopenharmony_ci continue; 16362306a36Sopenharmony_ci /* restart search at zero */ 16462306a36Sopenharmony_ci bmap = 0; 16562306a36Sopenharmony_ci bm = sbi->s_bitmap; 16662306a36Sopenharmony_ci } while (!bm->bm_free); 16762306a36Sopenharmony_ci blk = bmap * sbi->s_bmap_bits; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cifind_bmap_bit: 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci bh = sbi->s_bmap_bh; 17262306a36Sopenharmony_ci if (sbi->s_last_bmap != bmap) { 17362306a36Sopenharmony_ci affs_brelse(bh); 17462306a36Sopenharmony_ci bh = affs_bread(sb, bm->bm_key); 17562306a36Sopenharmony_ci if (!bh) 17662306a36Sopenharmony_ci goto err_bh_read; 17762306a36Sopenharmony_ci sbi->s_bmap_bh = bh; 17862306a36Sopenharmony_ci sbi->s_last_bmap = bmap; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* find an unused block in this bitmap block */ 18262306a36Sopenharmony_ci bit = blk % sbi->s_bmap_bits; 18362306a36Sopenharmony_ci data = (__be32 *)bh->b_data + bit / 32 + 1; 18462306a36Sopenharmony_ci enddata = (__be32 *)((u8 *)bh->b_data + sb->s_blocksize); 18562306a36Sopenharmony_ci mask = ~0UL << (bit & 31); 18662306a36Sopenharmony_ci blk &= ~31UL; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci tmp = be32_to_cpu(*data); 18962306a36Sopenharmony_ci if (tmp & mask) 19062306a36Sopenharmony_ci goto find_bit; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* scan the rest of the buffer */ 19362306a36Sopenharmony_ci do { 19462306a36Sopenharmony_ci blk += 32; 19562306a36Sopenharmony_ci if (++data >= enddata) 19662306a36Sopenharmony_ci /* didn't find something, can only happen 19762306a36Sopenharmony_ci * if scan didn't start at 0, try next bmap 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci goto find_bmap; 20062306a36Sopenharmony_ci } while (!*data); 20162306a36Sopenharmony_ci tmp = be32_to_cpu(*data); 20262306a36Sopenharmony_ci mask = ~0; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cifind_bit: 20562306a36Sopenharmony_ci /* finally look for a free bit in the word */ 20662306a36Sopenharmony_ci bit = ffs(tmp & mask) - 1; 20762306a36Sopenharmony_ci blk += bit + sbi->s_reserved; 20862306a36Sopenharmony_ci mask2 = mask = 1 << (bit & 31); 20962306a36Sopenharmony_ci AFFS_I(inode)->i_lastalloc = blk; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci /* prealloc as much as possible within this word */ 21262306a36Sopenharmony_ci while ((mask2 <<= 1)) { 21362306a36Sopenharmony_ci if (!(tmp & mask2)) 21462306a36Sopenharmony_ci break; 21562306a36Sopenharmony_ci AFFS_I(inode)->i_pa_cnt++; 21662306a36Sopenharmony_ci mask |= mask2; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci bm->bm_free -= AFFS_I(inode)->i_pa_cnt + 1; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci *data = cpu_to_be32(tmp & ~mask); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* fix checksum */ 22362306a36Sopenharmony_ci tmp = be32_to_cpu(*(__be32 *)bh->b_data); 22462306a36Sopenharmony_ci *(__be32 *)bh->b_data = cpu_to_be32(tmp + mask); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci mark_buffer_dirty(bh); 22762306a36Sopenharmony_ci affs_mark_sb_dirty(sb); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci mutex_unlock(&sbi->s_bmlock); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci pr_debug("%d\n", blk); 23262306a36Sopenharmony_ci return blk; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cierr_bh_read: 23562306a36Sopenharmony_ci affs_error(sb,"affs_read_block","Cannot read bitmap block %u", bm->bm_key); 23662306a36Sopenharmony_ci sbi->s_bmap_bh = NULL; 23762306a36Sopenharmony_ci sbi->s_last_bmap = ~0; 23862306a36Sopenharmony_cierr_full: 23962306a36Sopenharmony_ci mutex_unlock(&sbi->s_bmlock); 24062306a36Sopenharmony_ci pr_debug("failed\n"); 24162306a36Sopenharmony_ci return 0; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ciint affs_init_bitmap(struct super_block *sb, int *flags) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci struct affs_bm_info *bm; 24762306a36Sopenharmony_ci struct buffer_head *bmap_bh = NULL, *bh = NULL; 24862306a36Sopenharmony_ci __be32 *bmap_blk; 24962306a36Sopenharmony_ci u32 size, blk, end, offset, mask; 25062306a36Sopenharmony_ci int i, res = 0; 25162306a36Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (*flags & SB_RDONLY) 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (!AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->bm_flag) { 25762306a36Sopenharmony_ci pr_notice("Bitmap invalid - mounting %s read only\n", sb->s_id); 25862306a36Sopenharmony_ci *flags |= SB_RDONLY; 25962306a36Sopenharmony_ci return 0; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci sbi->s_last_bmap = ~0; 26362306a36Sopenharmony_ci sbi->s_bmap_bh = NULL; 26462306a36Sopenharmony_ci sbi->s_bmap_bits = sb->s_blocksize * 8 - 32; 26562306a36Sopenharmony_ci sbi->s_bmap_count = (sbi->s_partition_size - sbi->s_reserved + 26662306a36Sopenharmony_ci sbi->s_bmap_bits - 1) / sbi->s_bmap_bits; 26762306a36Sopenharmony_ci size = sbi->s_bmap_count * sizeof(*bm); 26862306a36Sopenharmony_ci bm = sbi->s_bitmap = kzalloc(size, GFP_KERNEL); 26962306a36Sopenharmony_ci if (!sbi->s_bitmap) { 27062306a36Sopenharmony_ci pr_err("Bitmap allocation failed\n"); 27162306a36Sopenharmony_ci return -ENOMEM; 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci bmap_blk = (__be32 *)sbi->s_root_bh->b_data; 27562306a36Sopenharmony_ci blk = sb->s_blocksize / 4 - 49; 27662306a36Sopenharmony_ci end = blk + 25; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci for (i = sbi->s_bmap_count; i > 0; bm++, i--) { 27962306a36Sopenharmony_ci affs_brelse(bh); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci bm->bm_key = be32_to_cpu(bmap_blk[blk]); 28262306a36Sopenharmony_ci bh = affs_bread(sb, bm->bm_key); 28362306a36Sopenharmony_ci if (!bh) { 28462306a36Sopenharmony_ci pr_err("Cannot read bitmap\n"); 28562306a36Sopenharmony_ci res = -EIO; 28662306a36Sopenharmony_ci goto out; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci if (affs_checksum_block(sb, bh)) { 28962306a36Sopenharmony_ci pr_warn("Bitmap %u invalid - mounting %s read only.\n", 29062306a36Sopenharmony_ci bm->bm_key, sb->s_id); 29162306a36Sopenharmony_ci *flags |= SB_RDONLY; 29262306a36Sopenharmony_ci goto out; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci pr_debug("read bitmap block %d: %d\n", blk, bm->bm_key); 29562306a36Sopenharmony_ci bm->bm_free = memweight(bh->b_data + 4, sb->s_blocksize - 4); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* Don't try read the extension if this is the last block, 29862306a36Sopenharmony_ci * but we also need the right bm pointer below 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci if (++blk < end || i == 1) 30162306a36Sopenharmony_ci continue; 30262306a36Sopenharmony_ci if (bmap_bh) 30362306a36Sopenharmony_ci affs_brelse(bmap_bh); 30462306a36Sopenharmony_ci bmap_bh = affs_bread(sb, be32_to_cpu(bmap_blk[blk])); 30562306a36Sopenharmony_ci if (!bmap_bh) { 30662306a36Sopenharmony_ci pr_err("Cannot read bitmap extension\n"); 30762306a36Sopenharmony_ci res = -EIO; 30862306a36Sopenharmony_ci goto out; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci bmap_blk = (__be32 *)bmap_bh->b_data; 31162306a36Sopenharmony_ci blk = 0; 31262306a36Sopenharmony_ci end = sb->s_blocksize / 4 - 1; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci offset = (sbi->s_partition_size - sbi->s_reserved) % sbi->s_bmap_bits; 31662306a36Sopenharmony_ci mask = ~(0xFFFFFFFFU << (offset & 31)); 31762306a36Sopenharmony_ci pr_debug("last word: %d %d %d\n", offset, offset / 32 + 1, mask); 31862306a36Sopenharmony_ci offset = offset / 32 + 1; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (mask) { 32162306a36Sopenharmony_ci u32 old, new; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Mark unused bits in the last word as allocated */ 32462306a36Sopenharmony_ci old = be32_to_cpu(((__be32 *)bh->b_data)[offset]); 32562306a36Sopenharmony_ci new = old & mask; 32662306a36Sopenharmony_ci //if (old != new) { 32762306a36Sopenharmony_ci ((__be32 *)bh->b_data)[offset] = cpu_to_be32(new); 32862306a36Sopenharmony_ci /* fix checksum */ 32962306a36Sopenharmony_ci //new -= old; 33062306a36Sopenharmony_ci //old = be32_to_cpu(*(__be32 *)bh->b_data); 33162306a36Sopenharmony_ci //*(__be32 *)bh->b_data = cpu_to_be32(old - new); 33262306a36Sopenharmony_ci //mark_buffer_dirty(bh); 33362306a36Sopenharmony_ci //} 33462306a36Sopenharmony_ci /* correct offset for the bitmap count below */ 33562306a36Sopenharmony_ci //offset++; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci while (++offset < sb->s_blocksize / 4) 33862306a36Sopenharmony_ci ((__be32 *)bh->b_data)[offset] = 0; 33962306a36Sopenharmony_ci ((__be32 *)bh->b_data)[0] = 0; 34062306a36Sopenharmony_ci ((__be32 *)bh->b_data)[0] = cpu_to_be32(-affs_checksum_block(sb, bh)); 34162306a36Sopenharmony_ci mark_buffer_dirty(bh); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* recalculate bitmap count for last block */ 34462306a36Sopenharmony_ci bm--; 34562306a36Sopenharmony_ci bm->bm_free = memweight(bh->b_data + 4, sb->s_blocksize - 4); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ciout: 34862306a36Sopenharmony_ci affs_brelse(bh); 34962306a36Sopenharmony_ci affs_brelse(bmap_bh); 35062306a36Sopenharmony_ci return res; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_civoid affs_free_bitmap(struct super_block *sb) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci struct affs_sb_info *sbi = AFFS_SB(sb); 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (!sbi->s_bitmap) 35862306a36Sopenharmony_ci return; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci affs_brelse(sbi->s_bmap_bh); 36162306a36Sopenharmony_ci sbi->s_bmap_bh = NULL; 36262306a36Sopenharmony_ci sbi->s_last_bmap = ~0; 36362306a36Sopenharmony_ci kfree(sbi->s_bitmap); 36462306a36Sopenharmony_ci sbi->s_bitmap = NULL; 36562306a36Sopenharmony_ci} 366