xref: /openbmc/linux/fs/minix/bitmap.c (revision f7f43858)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  linux/fs/minix/bitmap.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 1991, 1992  Linus Torvalds
61da177e4SLinus Torvalds  */
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds /*
91da177e4SLinus Torvalds  * Modified for 680x0 by Hamish Macdonald
101da177e4SLinus Torvalds  * Fixed for 680x0 by Andreas Schwab
111da177e4SLinus Torvalds  */
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds /* bitmap.c contains the code that handles the inode and block bitmaps */
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include "minix.h"
161da177e4SLinus Torvalds #include <linux/buffer_head.h>
171da177e4SLinus Torvalds #include <linux/bitops.h>
18e8edc6e0SAlexey Dobriyan #include <linux/sched.h>
191da177e4SLinus Torvalds 
20cc46759aSAl Viro static DEFINE_SPINLOCK(bitmap_lock);
21cc46759aSAl Viro 
22f1fd306aSAl Viro /*
23f1fd306aSAl Viro  * bitmap consists of blocks filled with 16bit words
24f1fd306aSAl Viro  * bit set == busy, bit clear == free
25f1fd306aSAl Viro  * endianness is a mess, but for counting zero bits it really doesn't matter...
26f1fd306aSAl Viro  */
count_free(struct buffer_head * map[],unsigned blocksize,__u32 numbits)27f1fd306aSAl Viro static __u32 count_free(struct buffer_head *map[], unsigned blocksize, __u32 numbits)
281da177e4SLinus Torvalds {
29f1fd306aSAl Viro 	__u32 sum = 0;
30f1fd306aSAl Viro 	unsigned blocks = DIV_ROUND_UP(numbits, blocksize * 8);
311da177e4SLinus Torvalds 
32f1fd306aSAl Viro 	while (blocks--) {
33f1fd306aSAl Viro 		unsigned words = blocksize / 2;
34f1fd306aSAl Viro 		__u16 *p = (__u16 *)(*map++)->b_data;
35f1fd306aSAl Viro 		while (words--)
36f1fd306aSAl Viro 			sum += 16 - hweight16(*p++);
371da177e4SLinus Torvalds 	}
381da177e4SLinus Torvalds 
39f1fd306aSAl Viro 	return sum;
401da177e4SLinus Torvalds }
411da177e4SLinus Torvalds 
minix_free_block(struct inode * inode,unsigned long block)42939b00dfSAndries Brouwer void minix_free_block(struct inode *inode, unsigned long block)
431da177e4SLinus Torvalds {
441da177e4SLinus Torvalds 	struct super_block *sb = inode->i_sb;
451da177e4SLinus Torvalds 	struct minix_sb_info *sbi = minix_sb(sb);
461da177e4SLinus Torvalds 	struct buffer_head *bh;
47939b00dfSAndries Brouwer 	int k = sb->s_blocksize_bits + 3;
48939b00dfSAndries Brouwer 	unsigned long bit, zone;
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
5111b84487SDenis Vlasenko 		printk("Trying to free block not in datazone\n");
521da177e4SLinus Torvalds 		return;
531da177e4SLinus Torvalds 	}
541da177e4SLinus Torvalds 	zone = block - sbi->s_firstdatazone + 1;
55939b00dfSAndries Brouwer 	bit = zone & ((1<<k) - 1);
56939b00dfSAndries Brouwer 	zone >>= k;
571da177e4SLinus Torvalds 	if (zone >= sbi->s_zmap_blocks) {
581da177e4SLinus Torvalds 		printk("minix_free_block: nonexistent bitmap buffer\n");
591da177e4SLinus Torvalds 		return;
601da177e4SLinus Torvalds 	}
611da177e4SLinus Torvalds 	bh = sbi->s_zmap[zone];
62cc46759aSAl Viro 	spin_lock(&bitmap_lock);
631da177e4SLinus Torvalds 	if (!minix_test_and_clear_bit(bit, bh->b_data))
64939b00dfSAndries Brouwer 		printk("minix_free_block (%s:%lu): bit already cleared\n",
651da177e4SLinus Torvalds 		       sb->s_id, block);
66cc46759aSAl Viro 	spin_unlock(&bitmap_lock);
671da177e4SLinus Torvalds 	mark_buffer_dirty(bh);
681da177e4SLinus Torvalds 	return;
691da177e4SLinus Torvalds }
701da177e4SLinus Torvalds 
minix_new_block(struct inode * inode)711da177e4SLinus Torvalds int minix_new_block(struct inode * inode)
721da177e4SLinus Torvalds {
731da177e4SLinus Torvalds 	struct minix_sb_info *sbi = minix_sb(inode->i_sb);
74939b00dfSAndries Brouwer 	int bits_per_zone = 8 * inode->i_sb->s_blocksize;
751da177e4SLinus Torvalds 	int i;
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds 	for (i = 0; i < sbi->s_zmap_blocks; i++) {
781da177e4SLinus Torvalds 		struct buffer_head *bh = sbi->s_zmap[i];
791da177e4SLinus Torvalds 		int j;
801da177e4SLinus Torvalds 
81cc46759aSAl Viro 		spin_lock(&bitmap_lock);
82939b00dfSAndries Brouwer 		j = minix_find_first_zero_bit(bh->b_data, bits_per_zone);
83939b00dfSAndries Brouwer 		if (j < bits_per_zone) {
841da177e4SLinus Torvalds 			minix_set_bit(j, bh->b_data);
85cc46759aSAl Viro 			spin_unlock(&bitmap_lock);
861da177e4SLinus Torvalds 			mark_buffer_dirty(bh);
87939b00dfSAndries Brouwer 			j += i * bits_per_zone + sbi->s_firstdatazone-1;
881da177e4SLinus Torvalds 			if (j < sbi->s_firstdatazone || j >= sbi->s_nzones)
891da177e4SLinus Torvalds 				break;
901da177e4SLinus Torvalds 			return j;
911da177e4SLinus Torvalds 		}
92cc46759aSAl Viro 		spin_unlock(&bitmap_lock);
931da177e4SLinus Torvalds 	}
941da177e4SLinus Torvalds 	return 0;
951da177e4SLinus Torvalds }
961da177e4SLinus Torvalds 
minix_count_free_blocks(struct super_block * sb)97016e8d44SJosh Boyer unsigned long minix_count_free_blocks(struct super_block *sb)
981da177e4SLinus Torvalds {
99016e8d44SJosh Boyer 	struct minix_sb_info *sbi = minix_sb(sb);
1006d6747f8SQi Yong 	u32 bits = sbi->s_nzones - sbi->s_firstdatazone + 1;
101016e8d44SJosh Boyer 
102016e8d44SJosh Boyer 	return (count_free(sbi->s_zmap, sb->s_blocksize, bits)
1031da177e4SLinus Torvalds 		<< sbi->s_log_zone_size);
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds struct minix_inode *
minix_V1_raw_inode(struct super_block * sb,ino_t ino,struct buffer_head ** bh)1071da177e4SLinus Torvalds minix_V1_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
1081da177e4SLinus Torvalds {
1091da177e4SLinus Torvalds 	int block;
1101da177e4SLinus Torvalds 	struct minix_sb_info *sbi = minix_sb(sb);
1111da177e4SLinus Torvalds 	struct minix_inode *p;
1121da177e4SLinus Torvalds 
1131da177e4SLinus Torvalds 	if (!ino || ino > sbi->s_ninodes) {
1141da177e4SLinus Torvalds 		printk("Bad inode number on dev %s: %ld is out of range\n",
1151da177e4SLinus Torvalds 		       sb->s_id, (long)ino);
1161da177e4SLinus Torvalds 		return NULL;
1171da177e4SLinus Torvalds 	}
1181da177e4SLinus Torvalds 	ino--;
1191da177e4SLinus Torvalds 	block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
1201da177e4SLinus Torvalds 		 ino / MINIX_INODES_PER_BLOCK;
1211da177e4SLinus Torvalds 	*bh = sb_bread(sb, block);
1221da177e4SLinus Torvalds 	if (!*bh) {
12311b84487SDenis Vlasenko 		printk("Unable to read inode block\n");
1241da177e4SLinus Torvalds 		return NULL;
1251da177e4SLinus Torvalds 	}
1261da177e4SLinus Torvalds 	p = (void *)(*bh)->b_data;
1271da177e4SLinus Torvalds 	return p + ino % MINIX_INODES_PER_BLOCK;
1281da177e4SLinus Torvalds }
1291da177e4SLinus Torvalds 
1301da177e4SLinus Torvalds struct minix2_inode *
minix_V2_raw_inode(struct super_block * sb,ino_t ino,struct buffer_head ** bh)1311da177e4SLinus Torvalds minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
1321da177e4SLinus Torvalds {
1331da177e4SLinus Torvalds 	int block;
1341da177e4SLinus Torvalds 	struct minix_sb_info *sbi = minix_sb(sb);
1351da177e4SLinus Torvalds 	struct minix2_inode *p;
136939b00dfSAndries Brouwer 	int minix2_inodes_per_block = sb->s_blocksize / sizeof(struct minix2_inode);
1371da177e4SLinus Torvalds 
1381da177e4SLinus Torvalds 	*bh = NULL;
1391da177e4SLinus Torvalds 	if (!ino || ino > sbi->s_ninodes) {
1401da177e4SLinus Torvalds 		printk("Bad inode number on dev %s: %ld is out of range\n",
1411da177e4SLinus Torvalds 		       sb->s_id, (long)ino);
1421da177e4SLinus Torvalds 		return NULL;
1431da177e4SLinus Torvalds 	}
1441da177e4SLinus Torvalds 	ino--;
1451da177e4SLinus Torvalds 	block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
146939b00dfSAndries Brouwer 		 ino / minix2_inodes_per_block;
1471da177e4SLinus Torvalds 	*bh = sb_bread(sb, block);
1481da177e4SLinus Torvalds 	if (!*bh) {
14911b84487SDenis Vlasenko 		printk("Unable to read inode block\n");
1501da177e4SLinus Torvalds 		return NULL;
1511da177e4SLinus Torvalds 	}
1521da177e4SLinus Torvalds 	p = (void *)(*bh)->b_data;
153939b00dfSAndries Brouwer 	return p + ino % minix2_inodes_per_block;
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds /* Clear the link count and mode of a deleted inode on disk. */
1571da177e4SLinus Torvalds 
minix_clear_inode(struct inode * inode)1581da177e4SLinus Torvalds static void minix_clear_inode(struct inode *inode)
1591da177e4SLinus Torvalds {
1601da177e4SLinus Torvalds 	struct buffer_head *bh = NULL;
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	if (INODE_VERSION(inode) == MINIX_V1) {
1631da177e4SLinus Torvalds 		struct minix_inode *raw_inode;
1641da177e4SLinus Torvalds 		raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
1651da177e4SLinus Torvalds 		if (raw_inode) {
1661da177e4SLinus Torvalds 			raw_inode->i_nlinks = 0;
1671da177e4SLinus Torvalds 			raw_inode->i_mode = 0;
1681da177e4SLinus Torvalds 		}
1691da177e4SLinus Torvalds 	} else {
1701da177e4SLinus Torvalds 		struct minix2_inode *raw_inode;
1711da177e4SLinus Torvalds 		raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
1721da177e4SLinus Torvalds 		if (raw_inode) {
1731da177e4SLinus Torvalds 			raw_inode->i_nlinks = 0;
1741da177e4SLinus Torvalds 			raw_inode->i_mode = 0;
1751da177e4SLinus Torvalds 		}
1761da177e4SLinus Torvalds 	}
1771da177e4SLinus Torvalds 	if (bh) {
1781da177e4SLinus Torvalds 		mark_buffer_dirty(bh);
1791da177e4SLinus Torvalds 		brelse (bh);
1801da177e4SLinus Torvalds 	}
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds 
minix_free_inode(struct inode * inode)1831da177e4SLinus Torvalds void minix_free_inode(struct inode * inode)
1841da177e4SLinus Torvalds {
185939b00dfSAndries Brouwer 	struct super_block *sb = inode->i_sb;
1861da177e4SLinus Torvalds 	struct minix_sb_info *sbi = minix_sb(inode->i_sb);
1871da177e4SLinus Torvalds 	struct buffer_head *bh;
188939b00dfSAndries Brouwer 	int k = sb->s_blocksize_bits + 3;
189939b00dfSAndries Brouwer 	unsigned long ino, bit;
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds 	ino = inode->i_ino;
1921da177e4SLinus Torvalds 	if (ino < 1 || ino > sbi->s_ninodes) {
1931da177e4SLinus Torvalds 		printk("minix_free_inode: inode 0 or nonexistent inode\n");
1945ccb4a78SAl Viro 		return;
1951da177e4SLinus Torvalds 	}
196939b00dfSAndries Brouwer 	bit = ino & ((1<<k) - 1);
197939b00dfSAndries Brouwer 	ino >>= k;
198939b00dfSAndries Brouwer 	if (ino >= sbi->s_imap_blocks) {
1991da177e4SLinus Torvalds 		printk("minix_free_inode: nonexistent imap in superblock\n");
2005ccb4a78SAl Viro 		return;
2011da177e4SLinus Torvalds 	}
2021da177e4SLinus Torvalds 
2031da177e4SLinus Torvalds 	minix_clear_inode(inode);	/* clear on-disk copy */
2041da177e4SLinus Torvalds 
205939b00dfSAndries Brouwer 	bh = sbi->s_imap[ino];
206cc46759aSAl Viro 	spin_lock(&bitmap_lock);
207939b00dfSAndries Brouwer 	if (!minix_test_and_clear_bit(bit, bh->b_data))
208939b00dfSAndries Brouwer 		printk("minix_free_inode: bit %lu already cleared\n", bit);
209cc46759aSAl Viro 	spin_unlock(&bitmap_lock);
2101da177e4SLinus Torvalds 	mark_buffer_dirty(bh);
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds 
minix_new_inode(const struct inode * dir,umode_t mode)2134a29a126SAl Viro struct inode *minix_new_inode(const struct inode *dir, umode_t mode)
2141da177e4SLinus Torvalds {
2151da177e4SLinus Torvalds 	struct super_block *sb = dir->i_sb;
2161da177e4SLinus Torvalds 	struct minix_sb_info *sbi = minix_sb(sb);
2171da177e4SLinus Torvalds 	struct inode *inode = new_inode(sb);
2181da177e4SLinus Torvalds 	struct buffer_head * bh;
219939b00dfSAndries Brouwer 	int bits_per_zone = 8 * sb->s_blocksize;
220939b00dfSAndries Brouwer 	unsigned long j;
221939b00dfSAndries Brouwer 	int i;
2221da177e4SLinus Torvalds 
2234a29a126SAl Viro 	if (!inode)
2244a29a126SAl Viro 		return ERR_PTR(-ENOMEM);
225939b00dfSAndries Brouwer 	j = bits_per_zone;
2261da177e4SLinus Torvalds 	bh = NULL;
227cc46759aSAl Viro 	spin_lock(&bitmap_lock);
2281da177e4SLinus Torvalds 	for (i = 0; i < sbi->s_imap_blocks; i++) {
2291da177e4SLinus Torvalds 		bh = sbi->s_imap[i];
230939b00dfSAndries Brouwer 		j = minix_find_first_zero_bit(bh->b_data, bits_per_zone);
231939b00dfSAndries Brouwer 		if (j < bits_per_zone)
2321da177e4SLinus Torvalds 			break;
2331da177e4SLinus Torvalds 	}
234939b00dfSAndries Brouwer 	if (!bh || j >= bits_per_zone) {
235cc46759aSAl Viro 		spin_unlock(&bitmap_lock);
2361da177e4SLinus Torvalds 		iput(inode);
2374a29a126SAl Viro 		return ERR_PTR(-ENOSPC);
2381da177e4SLinus Torvalds 	}
2391da177e4SLinus Torvalds 	if (minix_test_and_set_bit(j, bh->b_data)) {	/* shouldn't happen */
240cc46759aSAl Viro 		spin_unlock(&bitmap_lock);
241939b00dfSAndries Brouwer 		printk("minix_new_inode: bit already set\n");
2421da177e4SLinus Torvalds 		iput(inode);
2434a29a126SAl Viro 		return ERR_PTR(-ENOSPC);
2441da177e4SLinus Torvalds 	}
245cc46759aSAl Viro 	spin_unlock(&bitmap_lock);
2461da177e4SLinus Torvalds 	mark_buffer_dirty(bh);
247939b00dfSAndries Brouwer 	j += i * bits_per_zone;
2481da177e4SLinus Torvalds 	if (!j || j > sbi->s_ninodes) {
2491da177e4SLinus Torvalds 		iput(inode);
2504a29a126SAl Viro 		return ERR_PTR(-ENOSPC);
2511da177e4SLinus Torvalds 	}
252f2d40141SChristian Brauner 	inode_init_owner(&nop_mnt_idmap, inode, dir, mode);
2531da177e4SLinus Torvalds 	inode->i_ino = j;
254*f7f43858SJeff Layton 	inode->i_mtime = inode->i_atime = inode_set_ctime_current(inode);
255ba52de12STheodore Ts'o 	inode->i_blocks = 0;
2561da177e4SLinus Torvalds 	memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
2571da177e4SLinus Torvalds 	insert_inode_hash(inode);
2581da177e4SLinus Torvalds 	mark_inode_dirty(inode);
2591da177e4SLinus Torvalds 
2601da177e4SLinus Torvalds 	return inode;
2611da177e4SLinus Torvalds }
2621da177e4SLinus Torvalds 
minix_count_free_inodes(struct super_block * sb)263016e8d44SJosh Boyer unsigned long minix_count_free_inodes(struct super_block *sb)
2641da177e4SLinus Torvalds {
265016e8d44SJosh Boyer 	struct minix_sb_info *sbi = minix_sb(sb);
266016e8d44SJosh Boyer 	u32 bits = sbi->s_ninodes + 1;
267016e8d44SJosh Boyer 
268016e8d44SJosh Boyer 	return count_free(sbi->s_imap, sb->s_blocksize, bits);
2691da177e4SLinus Torvalds }
270