18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/fs/minix/bitmap.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * Modified for 680x0 by Hamish Macdonald 108c2ecf20Sopenharmony_ci * Fixed for 680x0 by Andreas Schwab 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* bitmap.c contains the code that handles the inode and block bitmaps */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "minix.h" 168c2ecf20Sopenharmony_ci#include <linux/buffer_head.h> 178c2ecf20Sopenharmony_ci#include <linux/bitops.h> 188c2ecf20Sopenharmony_ci#include <linux/sched.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(bitmap_lock); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * bitmap consists of blocks filled with 16bit words 248c2ecf20Sopenharmony_ci * bit set == busy, bit clear == free 258c2ecf20Sopenharmony_ci * endianness is a mess, but for counting zero bits it really doesn't matter... 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_cistatic __u32 count_free(struct buffer_head *map[], unsigned blocksize, __u32 numbits) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci __u32 sum = 0; 308c2ecf20Sopenharmony_ci unsigned blocks = DIV_ROUND_UP(numbits, blocksize * 8); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci while (blocks--) { 338c2ecf20Sopenharmony_ci unsigned words = blocksize / 2; 348c2ecf20Sopenharmony_ci __u16 *p = (__u16 *)(*map++)->b_data; 358c2ecf20Sopenharmony_ci while (words--) 368c2ecf20Sopenharmony_ci sum += 16 - hweight16(*p++); 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci return sum; 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_civoid minix_free_block(struct inode *inode, unsigned long block) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 458c2ecf20Sopenharmony_ci struct minix_sb_info *sbi = minix_sb(sb); 468c2ecf20Sopenharmony_ci struct buffer_head *bh; 478c2ecf20Sopenharmony_ci int k = sb->s_blocksize_bits + 3; 488c2ecf20Sopenharmony_ci unsigned long bit, zone; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) { 518c2ecf20Sopenharmony_ci printk("Trying to free block not in datazone\n"); 528c2ecf20Sopenharmony_ci return; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci zone = block - sbi->s_firstdatazone + 1; 558c2ecf20Sopenharmony_ci bit = zone & ((1<<k) - 1); 568c2ecf20Sopenharmony_ci zone >>= k; 578c2ecf20Sopenharmony_ci if (zone >= sbi->s_zmap_blocks) { 588c2ecf20Sopenharmony_ci printk("minix_free_block: nonexistent bitmap buffer\n"); 598c2ecf20Sopenharmony_ci return; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci bh = sbi->s_zmap[zone]; 628c2ecf20Sopenharmony_ci spin_lock(&bitmap_lock); 638c2ecf20Sopenharmony_ci if (!minix_test_and_clear_bit(bit, bh->b_data)) 648c2ecf20Sopenharmony_ci printk("minix_free_block (%s:%lu): bit already cleared\n", 658c2ecf20Sopenharmony_ci sb->s_id, block); 668c2ecf20Sopenharmony_ci spin_unlock(&bitmap_lock); 678c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 688c2ecf20Sopenharmony_ci return; 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ciint minix_new_block(struct inode * inode) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci struct minix_sb_info *sbi = minix_sb(inode->i_sb); 748c2ecf20Sopenharmony_ci int bits_per_zone = 8 * inode->i_sb->s_blocksize; 758c2ecf20Sopenharmony_ci int i; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_zmap_blocks; i++) { 788c2ecf20Sopenharmony_ci struct buffer_head *bh = sbi->s_zmap[i]; 798c2ecf20Sopenharmony_ci int j; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci spin_lock(&bitmap_lock); 828c2ecf20Sopenharmony_ci j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); 838c2ecf20Sopenharmony_ci if (j < bits_per_zone) { 848c2ecf20Sopenharmony_ci minix_set_bit(j, bh->b_data); 858c2ecf20Sopenharmony_ci spin_unlock(&bitmap_lock); 868c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 878c2ecf20Sopenharmony_ci j += i * bits_per_zone + sbi->s_firstdatazone-1; 888c2ecf20Sopenharmony_ci if (j < sbi->s_firstdatazone || j >= sbi->s_nzones) 898c2ecf20Sopenharmony_ci break; 908c2ecf20Sopenharmony_ci return j; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci spin_unlock(&bitmap_lock); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci return 0; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ciunsigned long minix_count_free_blocks(struct super_block *sb) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci struct minix_sb_info *sbi = minix_sb(sb); 1008c2ecf20Sopenharmony_ci u32 bits = sbi->s_nzones - sbi->s_firstdatazone + 1; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return (count_free(sbi->s_zmap, sb->s_blocksize, bits) 1038c2ecf20Sopenharmony_ci << sbi->s_log_zone_size); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cistruct minix_inode * 1078c2ecf20Sopenharmony_ciminix_V1_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci int block; 1108c2ecf20Sopenharmony_ci struct minix_sb_info *sbi = minix_sb(sb); 1118c2ecf20Sopenharmony_ci struct minix_inode *p; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (!ino || ino > sbi->s_ninodes) { 1148c2ecf20Sopenharmony_ci printk("Bad inode number on dev %s: %ld is out of range\n", 1158c2ecf20Sopenharmony_ci sb->s_id, (long)ino); 1168c2ecf20Sopenharmony_ci return NULL; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci ino--; 1198c2ecf20Sopenharmony_ci block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks + 1208c2ecf20Sopenharmony_ci ino / MINIX_INODES_PER_BLOCK; 1218c2ecf20Sopenharmony_ci *bh = sb_bread(sb, block); 1228c2ecf20Sopenharmony_ci if (!*bh) { 1238c2ecf20Sopenharmony_ci printk("Unable to read inode block\n"); 1248c2ecf20Sopenharmony_ci return NULL; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci p = (void *)(*bh)->b_data; 1278c2ecf20Sopenharmony_ci return p + ino % MINIX_INODES_PER_BLOCK; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistruct minix2_inode * 1318c2ecf20Sopenharmony_ciminix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci int block; 1348c2ecf20Sopenharmony_ci struct minix_sb_info *sbi = minix_sb(sb); 1358c2ecf20Sopenharmony_ci struct minix2_inode *p; 1368c2ecf20Sopenharmony_ci int minix2_inodes_per_block = sb->s_blocksize / sizeof(struct minix2_inode); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci *bh = NULL; 1398c2ecf20Sopenharmony_ci if (!ino || ino > sbi->s_ninodes) { 1408c2ecf20Sopenharmony_ci printk("Bad inode number on dev %s: %ld is out of range\n", 1418c2ecf20Sopenharmony_ci sb->s_id, (long)ino); 1428c2ecf20Sopenharmony_ci return NULL; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci ino--; 1458c2ecf20Sopenharmony_ci block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks + 1468c2ecf20Sopenharmony_ci ino / minix2_inodes_per_block; 1478c2ecf20Sopenharmony_ci *bh = sb_bread(sb, block); 1488c2ecf20Sopenharmony_ci if (!*bh) { 1498c2ecf20Sopenharmony_ci printk("Unable to read inode block\n"); 1508c2ecf20Sopenharmony_ci return NULL; 1518c2ecf20Sopenharmony_ci } 1528c2ecf20Sopenharmony_ci p = (void *)(*bh)->b_data; 1538c2ecf20Sopenharmony_ci return p + ino % minix2_inodes_per_block; 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* Clear the link count and mode of a deleted inode on disk. */ 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void minix_clear_inode(struct inode *inode) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci struct buffer_head *bh = NULL; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (INODE_VERSION(inode) == MINIX_V1) { 1638c2ecf20Sopenharmony_ci struct minix_inode *raw_inode; 1648c2ecf20Sopenharmony_ci raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh); 1658c2ecf20Sopenharmony_ci if (raw_inode) { 1668c2ecf20Sopenharmony_ci raw_inode->i_nlinks = 0; 1678c2ecf20Sopenharmony_ci raw_inode->i_mode = 0; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci } else { 1708c2ecf20Sopenharmony_ci struct minix2_inode *raw_inode; 1718c2ecf20Sopenharmony_ci raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh); 1728c2ecf20Sopenharmony_ci if (raw_inode) { 1738c2ecf20Sopenharmony_ci raw_inode->i_nlinks = 0; 1748c2ecf20Sopenharmony_ci raw_inode->i_mode = 0; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci if (bh) { 1788c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 1798c2ecf20Sopenharmony_ci brelse (bh); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_civoid minix_free_inode(struct inode * inode) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 1868c2ecf20Sopenharmony_ci struct minix_sb_info *sbi = minix_sb(inode->i_sb); 1878c2ecf20Sopenharmony_ci struct buffer_head *bh; 1888c2ecf20Sopenharmony_ci int k = sb->s_blocksize_bits + 3; 1898c2ecf20Sopenharmony_ci unsigned long ino, bit; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci ino = inode->i_ino; 1928c2ecf20Sopenharmony_ci if (ino < 1 || ino > sbi->s_ninodes) { 1938c2ecf20Sopenharmony_ci printk("minix_free_inode: inode 0 or nonexistent inode\n"); 1948c2ecf20Sopenharmony_ci return; 1958c2ecf20Sopenharmony_ci } 1968c2ecf20Sopenharmony_ci bit = ino & ((1<<k) - 1); 1978c2ecf20Sopenharmony_ci ino >>= k; 1988c2ecf20Sopenharmony_ci if (ino >= sbi->s_imap_blocks) { 1998c2ecf20Sopenharmony_ci printk("minix_free_inode: nonexistent imap in superblock\n"); 2008c2ecf20Sopenharmony_ci return; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci minix_clear_inode(inode); /* clear on-disk copy */ 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci bh = sbi->s_imap[ino]; 2068c2ecf20Sopenharmony_ci spin_lock(&bitmap_lock); 2078c2ecf20Sopenharmony_ci if (!minix_test_and_clear_bit(bit, bh->b_data)) 2088c2ecf20Sopenharmony_ci printk("minix_free_inode: bit %lu already cleared\n", bit); 2098c2ecf20Sopenharmony_ci spin_unlock(&bitmap_lock); 2108c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_cistruct inode *minix_new_inode(const struct inode *dir, umode_t mode, int *error) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 2168c2ecf20Sopenharmony_ci struct minix_sb_info *sbi = minix_sb(sb); 2178c2ecf20Sopenharmony_ci struct inode *inode = new_inode(sb); 2188c2ecf20Sopenharmony_ci struct buffer_head * bh; 2198c2ecf20Sopenharmony_ci int bits_per_zone = 8 * sb->s_blocksize; 2208c2ecf20Sopenharmony_ci unsigned long j; 2218c2ecf20Sopenharmony_ci int i; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (!inode) { 2248c2ecf20Sopenharmony_ci *error = -ENOMEM; 2258c2ecf20Sopenharmony_ci return NULL; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci j = bits_per_zone; 2288c2ecf20Sopenharmony_ci bh = NULL; 2298c2ecf20Sopenharmony_ci *error = -ENOSPC; 2308c2ecf20Sopenharmony_ci spin_lock(&bitmap_lock); 2318c2ecf20Sopenharmony_ci for (i = 0; i < sbi->s_imap_blocks; i++) { 2328c2ecf20Sopenharmony_ci bh = sbi->s_imap[i]; 2338c2ecf20Sopenharmony_ci j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); 2348c2ecf20Sopenharmony_ci if (j < bits_per_zone) 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci if (!bh || j >= bits_per_zone) { 2388c2ecf20Sopenharmony_ci spin_unlock(&bitmap_lock); 2398c2ecf20Sopenharmony_ci iput(inode); 2408c2ecf20Sopenharmony_ci return NULL; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci if (minix_test_and_set_bit(j, bh->b_data)) { /* shouldn't happen */ 2438c2ecf20Sopenharmony_ci spin_unlock(&bitmap_lock); 2448c2ecf20Sopenharmony_ci printk("minix_new_inode: bit already set\n"); 2458c2ecf20Sopenharmony_ci iput(inode); 2468c2ecf20Sopenharmony_ci return NULL; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci spin_unlock(&bitmap_lock); 2498c2ecf20Sopenharmony_ci mark_buffer_dirty(bh); 2508c2ecf20Sopenharmony_ci j += i * bits_per_zone; 2518c2ecf20Sopenharmony_ci if (!j || j > sbi->s_ninodes) { 2528c2ecf20Sopenharmony_ci iput(inode); 2538c2ecf20Sopenharmony_ci return NULL; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci inode_init_owner(inode, dir, mode); 2568c2ecf20Sopenharmony_ci inode->i_ino = j; 2578c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 2588c2ecf20Sopenharmony_ci inode->i_blocks = 0; 2598c2ecf20Sopenharmony_ci memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u)); 2608c2ecf20Sopenharmony_ci insert_inode_hash(inode); 2618c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci *error = 0; 2648c2ecf20Sopenharmony_ci return inode; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ciunsigned long minix_count_free_inodes(struct super_block *sb) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct minix_sb_info *sbi = minix_sb(sb); 2708c2ecf20Sopenharmony_ci u32 bits = sbi->s_ninodes + 1; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci return count_free(sbi->s_imap, sb->s_blocksize, bits); 2738c2ecf20Sopenharmony_ci} 274