summaryrefslogtreecommitdiffstats
path: root/fs/qnx4/bitmap.c
blob: e1cd061a25f748dec3d77bf7c2b3d0a428cbb385 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/*
 * QNX4 file system, Linux implementation.
 *
 * Version : 0.2.1
 *
 * Using parts of the xiafs filesystem.
 *
 * History :
 *
 * 28-05-1998 by Richard Frowijn : first release.
 * 20-06-1998 by Frank Denis : basic optimisations.
 * 25-06-1998 by Frank Denis : qnx4_is_free, qnx4_set_bitmap, qnx4_bmap .
 * 28-06-1998 by Frank Denis : qnx4_free_inode (to be fixed) .
 */

#include <linux/buffer_head.h>
#include <linux/bitops.h>
#include "qnx4.h"

#if 0
int qnx4_new_block(struct super_block *sb)
{
	return 0;
}
#endif  /*  0  */

static void count_bits(register const char *bmPart, register int size,
		       int *const tf)
{
	char b;
	int tot = *tf;

	if (size > QNX4_BLOCK_SIZE) {
		size = QNX4_BLOCK_SIZE;
	}
	do {
		b = *bmPart++;
		if ((b & 1) == 0)
			tot++;
		if ((b & 2) == 0)
			tot++;
		if ((b & 4) == 0)
			tot++;
		if ((b & 8) == 0)
			tot++;
		if ((b & 16) == 0)
			tot++;
		if ((b & 32) == 0)
			tot++;
		if ((b & 64) == 0)
			tot++;
		if ((b & 128) == 0)
			tot++;
		size--;
	} while (size != 0);
	*tf = tot;
}

unsigned long qnx4_count_free_blocks(struct super_block *sb)
{
	int start = le32_to_cpu(qnx4_sb(sb)->BitMap->di_first_xtnt.xtnt_blk) - 1;
	int total = 0;
	int total_free = 0;
	int offset = 0;
	int size = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size);
	struct buffer_head *bh;

	while (total < size) {
		if ((bh = sb_bread(sb, start + offset)) == NULL) {
			printk("qnx4: I/O error in counting free blocks\n");
			break;
		}
		count_bits(bh->b_data, size - total, &total_free);
		brelse(bh);
		total += QNX4_BLOCK_SIZE;
		offset++;
	}

	return total_free;
}

#ifdef CONFIG_QNX4FS_RW

int qnx4_is_free(struct super_block *sb, long block)
{
	int start = le32_to_cpu(qnx4_sb(sb)->BitMap->di_first_xtnt.xtnt_blk) - 1;
	int size = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size);
	struct buffer_head *bh;
	const char *g;
	int ret = -EIO;

	start += block / (QNX4_BLOCK_SIZE * 8);
	QNX4DEBUG(("qnx4: is_free requesting block [%lu], bitmap in block [%lu]\n",
		   (unsigned long) block, (unsigned long) start));
	(void) size;		/* CHECKME */
	bh = sb_bread(sb, start);
	if (bh == NULL) {
		return -EIO;
	}
	g = bh->b_data + (block % QNX4_BLOCK_SIZE);
	if (((*g) & (1 << (block % 8))) == 0) {
		QNX4DEBUG(("qnx4: is_free -> block is free\n"));
		ret = 1;
	} else {
		QNX4DEBUG(("qnx4: is_free -> block is busy\n"));
		ret = 0;
	}
	brelse(bh);

	return ret;
}

int qnx4_set_bitmap(struct super_block *sb, long block, int busy)
{
	int start = le32_to_cpu(qnx4_sb(sb)->BitMap->di_first_xtnt.xtnt_blk) - 1;
	int size = le32_to_cpu(qnx4_sb(sb)->BitMap->di_size);
	struct buffer_head *bh;
	char *g;

	start += block / (QNX4_BLOCK_SIZE * 8);
	QNX4DEBUG(("qnx4: set_bitmap requesting block [%lu], bitmap in block [%lu]\n",
		   (unsigned long) block, (unsigned long) start));
	(void) size;		/* CHECKME */
	bh = sb_bread(sb, start);
	if (bh == NULL) {
		return -EIO;
	}
	g = bh->b_data + (block % QNX4_BLOCK_SIZE);
	if (busy == 0) {
		(*g) &= ~(1 << (block % 8));
	} else {
		(*g) |= (1 << (block % 8));
	}
	mark_buffer_dirty(bh);
	brelse(bh);

	return 0;
}

static void qnx4_clear_inode(struct inode *inode)
{
	struct qnx4_inode_entry *qnx4_ino = qnx4_raw_inode(inode);
	/* What for? */
	memset(qnx4_ino->di_fname, 0, sizeof qnx4_ino->di_fname);
	qnx4_ino->di_size = 0;
	qnx4_ino->di_num_xtnts = 0;
	qnx4_ino->di_mode = 0;
	qnx4_ino->di_status = 0;
}

void qnx4_free_inode(struct inode *inode)
{
	if (inode->i_ino < 1) {
		printk("free_inode: inode 0 or nonexistent inode\n");
		return;
	}
	qnx4_clear_inode(inode);
	clear_inode(inode);
}

#endif