Blame view

fs/minix/bitmap.c 6.83 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   *  linux/fs/minix/bitmap.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
  
  /*
   * Modified for 680x0 by Hamish Macdonald
   * Fixed for 680x0 by Andreas Schwab
   */
  
  /* bitmap.c contains the code that handles the inode and block bitmaps */
  
  #include "minix.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  #include <linux/buffer_head.h>
  #include <linux/bitops.h>
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
17
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18

febfcf911   Philippe De Muyter   fs: mark nibblema...
19
  static const int nibblemap[] = { 4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0 };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20

cc46759a8   Al Viro   get rid of BKL in...
21
  static DEFINE_SPINLOCK(bitmap_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
  static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, __u32 numbits)
  {
  	unsigned i, j, sum = 0;
  	struct buffer_head *bh;
    
  	for (i=0; i<numblocks-1; i++) {
  		if (!(bh=map[i])) 
  			return(0);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
30
  		for (j=0; j<bh->b_size; j++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
34
35
36
  			sum += nibblemap[bh->b_data[j] & 0xf]
  				+ nibblemap[(bh->b_data[j]>>4) & 0xf];
  	}
  
  	if (numblocks==0 || !(bh=map[numblocks-1]))
  		return(0);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
37
  	i = ((numbits - (numblocks-1) * bh->b_size * 8) / 16) * 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
43
44
45
46
47
48
49
50
  	for (j=0; j<i; j++) {
  		sum += nibblemap[bh->b_data[j] & 0xf]
  			+ nibblemap[(bh->b_data[j]>>4) & 0xf];
  	}
  
  	i = numbits%16;
  	if (i!=0) {
  		i = *(__u16 *)(&bh->b_data[j]) | ~((1<<i) - 1);
  		sum += nibblemap[i & 0xf] + nibblemap[(i>>4) & 0xf];
  		sum += nibblemap[(i>>8) & 0xf] + nibblemap[(i>>12) & 0xf];
  	}
  	return(sum);
  }
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
51
  void minix_free_block(struct inode *inode, unsigned long block)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  {
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
53
54
55
56
57
  	struct super_block *sb = inode->i_sb;
  	struct minix_sb_info *sbi = minix_sb(sb);
  	struct buffer_head *bh;
  	int k = sb->s_blocksize_bits + 3;
  	unsigned long bit, zone;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
  
  	if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) {
11b844875   Denis Vlasenko   [PATCH] fix messa...
60
61
  		printk("Trying to free block not in datazone
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
  		return;
  	}
  	zone = block - sbi->s_firstdatazone + 1;
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
65
66
  	bit = zone & ((1<<k) - 1);
  	zone >>= k;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
  	if (zone >= sbi->s_zmap_blocks) {
  		printk("minix_free_block: nonexistent bitmap buffer
  ");
  		return;
  	}
  	bh = sbi->s_zmap[zone];
cc46759a8   Al Viro   get rid of BKL in...
73
  	spin_lock(&bitmap_lock);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
74
75
76
  	if (!minix_test_and_clear_bit(bit, bh->b_data))
  		printk("minix_free_block (%s:%lu): bit already cleared
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  		       sb->s_id, block);
cc46759a8   Al Viro   get rid of BKL in...
78
  	spin_unlock(&bitmap_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
85
  	mark_buffer_dirty(bh);
  	return;
  }
  
  int minix_new_block(struct inode * inode)
  {
  	struct minix_sb_info *sbi = minix_sb(inode->i_sb);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
86
  	int bits_per_zone = 8 * inode->i_sb->s_blocksize;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
87
88
89
90
91
  	int i;
  
  	for (i = 0; i < sbi->s_zmap_blocks; i++) {
  		struct buffer_head *bh = sbi->s_zmap[i];
  		int j;
cc46759a8   Al Viro   get rid of BKL in...
92
  		spin_lock(&bitmap_lock);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
93
94
95
  		j = minix_find_first_zero_bit(bh->b_data, bits_per_zone);
  		if (j < bits_per_zone) {
  			minix_set_bit(j, bh->b_data);
cc46759a8   Al Viro   get rid of BKL in...
96
  			spin_unlock(&bitmap_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  			mark_buffer_dirty(bh);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
98
  			j += i * bits_per_zone + sbi->s_firstdatazone-1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
  			if (j < sbi->s_firstdatazone || j >= sbi->s_nzones)
  				break;
  			return j;
  		}
cc46759a8   Al Viro   get rid of BKL in...
103
  		spin_unlock(&bitmap_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  	}
  	return 0;
  }
  
  unsigned long minix_count_free_blocks(struct minix_sb_info *sbi)
  {
  	return (count_free(sbi->s_zmap, sbi->s_zmap_blocks,
  		sbi->s_nzones - sbi->s_firstdatazone + 1)
  		<< sbi->s_log_zone_size);
  }
  
  struct minix_inode *
  minix_V1_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
  {
  	int block;
  	struct minix_sb_info *sbi = minix_sb(sb);
  	struct minix_inode *p;
  
  	if (!ino || ino > sbi->s_ninodes) {
  		printk("Bad inode number on dev %s: %ld is out of range
  ",
  		       sb->s_id, (long)ino);
  		return NULL;
  	}
  	ino--;
  	block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
  		 ino / MINIX_INODES_PER_BLOCK;
  	*bh = sb_bread(sb, block);
  	if (!*bh) {
11b844875   Denis Vlasenko   [PATCH] fix messa...
133
134
  		printk("Unable to read inode block
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
138
139
140
141
142
143
144
145
146
  		return NULL;
  	}
  	p = (void *)(*bh)->b_data;
  	return p + ino % MINIX_INODES_PER_BLOCK;
  }
  
  struct minix2_inode *
  minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh)
  {
  	int block;
  	struct minix_sb_info *sbi = minix_sb(sb);
  	struct minix2_inode *p;
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
147
  	int minix2_inodes_per_block = sb->s_blocksize / sizeof(struct minix2_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
152
153
154
155
156
157
  
  	*bh = NULL;
  	if (!ino || ino > sbi->s_ninodes) {
  		printk("Bad inode number on dev %s: %ld is out of range
  ",
  		       sb->s_id, (long)ino);
  		return NULL;
  	}
  	ino--;
  	block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks +
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
158
  		 ino / minix2_inodes_per_block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
  	*bh = sb_bread(sb, block);
  	if (!*bh) {
11b844875   Denis Vlasenko   [PATCH] fix messa...
161
162
  		printk("Unable to read inode block
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
  		return NULL;
  	}
  	p = (void *)(*bh)->b_data;
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
166
  	return p + ino % minix2_inodes_per_block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  }
  
  /* Clear the link count and mode of a deleted inode on disk. */
  
  static void minix_clear_inode(struct inode *inode)
  {
  	struct buffer_head *bh = NULL;
  
  	if (INODE_VERSION(inode) == MINIX_V1) {
  		struct minix_inode *raw_inode;
  		raw_inode = minix_V1_raw_inode(inode->i_sb, inode->i_ino, &bh);
  		if (raw_inode) {
  			raw_inode->i_nlinks = 0;
  			raw_inode->i_mode = 0;
  		}
  	} else {
  		struct minix2_inode *raw_inode;
  		raw_inode = minix_V2_raw_inode(inode->i_sb, inode->i_ino, &bh);
  		if (raw_inode) {
  			raw_inode->i_nlinks = 0;
  			raw_inode->i_mode = 0;
  		}
  	}
  	if (bh) {
  		mark_buffer_dirty(bh);
  		brelse (bh);
  	}
  }
  
  void minix_free_inode(struct inode * inode)
  {
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
198
  	struct super_block *sb = inode->i_sb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
  	struct minix_sb_info *sbi = minix_sb(inode->i_sb);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
200
201
202
  	struct buffer_head *bh;
  	int k = sb->s_blocksize_bits + 3;
  	unsigned long ino, bit;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
205
206
207
  
  	ino = inode->i_ino;
  	if (ino < 1 || ino > sbi->s_ninodes) {
  		printk("minix_free_inode: inode 0 or nonexistent inode
  ");
5ccb4a78d   Al Viro   switch minix to -...
208
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
  	}
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
210
211
212
  	bit = ino & ((1<<k) - 1);
  	ino >>= k;
  	if (ino >= sbi->s_imap_blocks) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
  		printk("minix_free_inode: nonexistent imap in superblock
  ");
5ccb4a78d   Al Viro   switch minix to -...
215
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
  	}
  
  	minix_clear_inode(inode);	/* clear on-disk copy */
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
219
  	bh = sbi->s_imap[ino];
cc46759a8   Al Viro   get rid of BKL in...
220
  	spin_lock(&bitmap_lock);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
221
222
223
  	if (!minix_test_and_clear_bit(bit, bh->b_data))
  		printk("minix_free_inode: bit %lu already cleared
  ", bit);
cc46759a8   Al Viro   get rid of BKL in...
224
  	spin_unlock(&bitmap_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  	mark_buffer_dirty(bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
  }
9eed1fb72   Dmitry Monakhov   minix: replace in...
227
  struct inode *minix_new_inode(const struct inode *dir, int mode, int *error)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
231
232
  {
  	struct super_block *sb = dir->i_sb;
  	struct minix_sb_info *sbi = minix_sb(sb);
  	struct inode *inode = new_inode(sb);
  	struct buffer_head * bh;
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
233
234
235
  	int bits_per_zone = 8 * sb->s_blocksize;
  	unsigned long j;
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
239
240
  
  	if (!inode) {
  		*error = -ENOMEM;
  		return NULL;
  	}
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
241
  	j = bits_per_zone;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
  	bh = NULL;
  	*error = -ENOSPC;
cc46759a8   Al Viro   get rid of BKL in...
244
  	spin_lock(&bitmap_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
245
246
  	for (i = 0; i < sbi->s_imap_blocks; i++) {
  		bh = sbi->s_imap[i];
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
247
248
  		j = minix_find_first_zero_bit(bh->b_data, bits_per_zone);
  		if (j < bits_per_zone)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
  			break;
  	}
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
251
  	if (!bh || j >= bits_per_zone) {
cc46759a8   Al Viro   get rid of BKL in...
252
  		spin_unlock(&bitmap_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
  		iput(inode);
  		return NULL;
  	}
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
256
  	if (minix_test_and_set_bit(j, bh->b_data)) {	/* shouldn't happen */
cc46759a8   Al Viro   get rid of BKL in...
257
  		spin_unlock(&bitmap_lock);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
258
259
  		printk("minix_new_inode: bit already set
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
  		iput(inode);
  		return NULL;
  	}
cc46759a8   Al Viro   get rid of BKL in...
263
  	spin_unlock(&bitmap_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  	mark_buffer_dirty(bh);
939b00df0   Andries Brouwer   [PATCH] Minix V3 ...
265
  	j += i * bits_per_zone;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
267
268
269
  	if (!j || j > sbi->s_ninodes) {
  		iput(inode);
  		return NULL;
  	}
9eed1fb72   Dmitry Monakhov   minix: replace in...
270
  	inode_init_owner(inode, dir, mode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
  	inode->i_ino = j;
  	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
ba52de123   Theodore Ts'o   [PATCH] inode-die...
273
  	inode->i_blocks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
278
279
280
281
282
283
284
285
  	memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
  	insert_inode_hash(inode);
  	mark_inode_dirty(inode);
  
  	*error = 0;
  	return inode;
  }
  
  unsigned long minix_count_free_inodes(struct minix_sb_info *sbi)
  {
  	return count_free(sbi->s_imap, sbi->s_imap_blocks, sbi->s_ninodes + 1);
  }