18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/kernel.h> 38c2ecf20Sopenharmony_ci#include <linux/fs.h> 48c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 58c2ecf20Sopenharmony_ci#include <asm/div64.h> 68c2ecf20Sopenharmony_ci#include "omfs.h" 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ciunsigned long omfs_count_free(struct super_block *sb) 98c2ecf20Sopenharmony_ci{ 108c2ecf20Sopenharmony_ci unsigned int i; 118c2ecf20Sopenharmony_ci unsigned long sum = 0; 128c2ecf20Sopenharmony_ci struct omfs_sb_info *sbi = OMFS_SB(sb); 138c2ecf20Sopenharmony_ci int nbits = sb->s_blocksize * 8; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_imap_size; i++) 168c2ecf20Sopenharmony_ci sum += nbits - bitmap_weight(sbi->s_imap[i], nbits); 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci return sum; 198c2ecf20Sopenharmony_ci} 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * Counts the run of zero bits starting at bit up to max. 238c2ecf20Sopenharmony_ci * It handles the case where a run might spill over a buffer. 248c2ecf20Sopenharmony_ci * Called with bitmap lock. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_cistatic int count_run(unsigned long **addr, int nbits, 278c2ecf20Sopenharmony_ci int addrlen, int bit, int max) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci int count = 0; 308c2ecf20Sopenharmony_ci int x; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci for (; addrlen > 0; addrlen--, addr++) { 338c2ecf20Sopenharmony_ci x = find_next_bit(*addr, nbits, bit); 348c2ecf20Sopenharmony_ci count += x - bit; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (x < nbits || count > max) 378c2ecf20Sopenharmony_ci return min(count, max); 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci bit = 0; 408c2ecf20Sopenharmony_ci } 418c2ecf20Sopenharmony_ci return min(count, max); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* 458c2ecf20Sopenharmony_ci * Sets or clears the run of count bits starting with bit. 468c2ecf20Sopenharmony_ci * Called with bitmap lock. 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_cistatic int set_run(struct super_block *sb, int map, 498c2ecf20Sopenharmony_ci int nbits, int bit, int count, int set) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci int i; 528c2ecf20Sopenharmony_ci int err; 538c2ecf20Sopenharmony_ci struct buffer_head *bh; 548c2ecf20Sopenharmony_ci struct omfs_sb_info *sbi = OMFS_SB(sb); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci err = -ENOMEM; 578c2ecf20Sopenharmony_ci bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map); 588c2ecf20Sopenharmony_ci if (!bh) 598c2ecf20Sopenharmony_ci goto out; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci for (i = 0; i < count; i++, bit++) { 628c2ecf20Sopenharmony_ci if (bit >= nbits) { 638c2ecf20Sopenharmony_ci bit = 0; 648c2ecf20Sopenharmony_ci map++; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 678c2ecf20Sopenharmony_ci brelse(bh); 688c2ecf20Sopenharmony_ci bh = sb_bread(sb, 698c2ecf20Sopenharmony_ci clus_to_blk(sbi, sbi->s_bitmap_ino) + map); 708c2ecf20Sopenharmony_ci if (!bh) 718c2ecf20Sopenharmony_ci goto out; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci if (set) { 748c2ecf20Sopenharmony_ci set_bit(bit, sbi->s_imap[map]); 758c2ecf20Sopenharmony_ci set_bit(bit, (unsigned long *)bh->b_data); 768c2ecf20Sopenharmony_ci } else { 778c2ecf20Sopenharmony_ci clear_bit(bit, sbi->s_imap[map]); 788c2ecf20Sopenharmony_ci clear_bit(bit, (unsigned long *)bh->b_data); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 828c2ecf20Sopenharmony_ci brelse(bh); 838c2ecf20Sopenharmony_ci err = 0; 848c2ecf20Sopenharmony_ciout: 858c2ecf20Sopenharmony_ci return err; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* 898c2ecf20Sopenharmony_ci * Tries to allocate exactly one block. Returns true if successful. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ciint omfs_allocate_block(struct super_block *sb, u64 block) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct buffer_head *bh; 948c2ecf20Sopenharmony_ci struct omfs_sb_info *sbi = OMFS_SB(sb); 958c2ecf20Sopenharmony_ci int bits_per_entry = 8 * sb->s_blocksize; 968c2ecf20Sopenharmony_ci unsigned int map, bit; 978c2ecf20Sopenharmony_ci int ret = 0; 988c2ecf20Sopenharmony_ci u64 tmp; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci tmp = block; 1018c2ecf20Sopenharmony_ci bit = do_div(tmp, bits_per_entry); 1028c2ecf20Sopenharmony_ci map = tmp; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_bitmap_lock); 1058c2ecf20Sopenharmony_ci if (map >= sbi->s_imap_size || test_and_set_bit(bit, sbi->s_imap[map])) 1068c2ecf20Sopenharmony_ci goto out; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (sbi->s_bitmap_ino > 0) { 1098c2ecf20Sopenharmony_ci bh = sb_bread(sb, clus_to_blk(sbi, sbi->s_bitmap_ino) + map); 1108c2ecf20Sopenharmony_ci if (!bh) 1118c2ecf20Sopenharmony_ci goto out; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci set_bit(bit, (unsigned long *)bh->b_data); 1148c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 1158c2ecf20Sopenharmony_ci brelse(bh); 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci ret = 1; 1188c2ecf20Sopenharmony_ciout: 1198c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_bitmap_lock); 1208c2ecf20Sopenharmony_ci return ret; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci/* 1258c2ecf20Sopenharmony_ci * Tries to allocate a set of blocks. The request size depends on the 1268c2ecf20Sopenharmony_ci * type: for inodes, we must allocate sbi->s_mirrors blocks, and for file 1278c2ecf20Sopenharmony_ci * blocks, we try to allocate sbi->s_clustersize, but can always get away 1288c2ecf20Sopenharmony_ci * with just one block. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ciint omfs_allocate_range(struct super_block *sb, 1318c2ecf20Sopenharmony_ci int min_request, 1328c2ecf20Sopenharmony_ci int max_request, 1338c2ecf20Sopenharmony_ci u64 *return_block, 1348c2ecf20Sopenharmony_ci int *return_size) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct omfs_sb_info *sbi = OMFS_SB(sb); 1378c2ecf20Sopenharmony_ci int bits_per_entry = 8 * sb->s_blocksize; 1388c2ecf20Sopenharmony_ci int ret = 0; 1398c2ecf20Sopenharmony_ci int i, run, bit; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_bitmap_lock); 1428c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_imap_size; i++) { 1438c2ecf20Sopenharmony_ci bit = 0; 1448c2ecf20Sopenharmony_ci while (bit < bits_per_entry) { 1458c2ecf20Sopenharmony_ci bit = find_next_zero_bit(sbi->s_imap[i], bits_per_entry, 1468c2ecf20Sopenharmony_ci bit); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (bit == bits_per_entry) 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci run = count_run(&sbi->s_imap[i], bits_per_entry, 1528c2ecf20Sopenharmony_ci sbi->s_imap_size-i, bit, max_request); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (run >= min_request) 1558c2ecf20Sopenharmony_ci goto found; 1568c2ecf20Sopenharmony_ci bit += run; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci ret = -ENOSPC; 1608c2ecf20Sopenharmony_ci goto out; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cifound: 1638c2ecf20Sopenharmony_ci *return_block = (u64) i * bits_per_entry + bit; 1648c2ecf20Sopenharmony_ci *return_size = run; 1658c2ecf20Sopenharmony_ci ret = set_run(sb, i, bits_per_entry, bit, run, 1); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciout: 1688c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_bitmap_lock); 1698c2ecf20Sopenharmony_ci return ret; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* 1738c2ecf20Sopenharmony_ci * Clears count bits starting at a given block. 1748c2ecf20Sopenharmony_ci */ 1758c2ecf20Sopenharmony_ciint omfs_clear_range(struct super_block *sb, u64 block, int count) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct omfs_sb_info *sbi = OMFS_SB(sb); 1788c2ecf20Sopenharmony_ci int bits_per_entry = 8 * sb->s_blocksize; 1798c2ecf20Sopenharmony_ci u64 tmp; 1808c2ecf20Sopenharmony_ci unsigned int map, bit; 1818c2ecf20Sopenharmony_ci int ret; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci tmp = block; 1848c2ecf20Sopenharmony_ci bit = do_div(tmp, bits_per_entry); 1858c2ecf20Sopenharmony_ci map = tmp; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (map >= sbi->s_imap_size) 1888c2ecf20Sopenharmony_ci return 0; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci mutex_lock(&sbi->s_bitmap_lock); 1918c2ecf20Sopenharmony_ci ret = set_run(sb, map, bits_per_entry, bit, count, 0); 1928c2ecf20Sopenharmony_ci mutex_unlock(&sbi->s_bitmap_lock); 1938c2ecf20Sopenharmony_ci return ret; 1948c2ecf20Sopenharmony_ci} 195