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